// Typical headers sent by vBulletin/PHP that sabotage caching
HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Pragma: no-cache
Nginx's FastCGI cache checks both your configuration AND upstream headers. Even if your fastcgi_cache_valid
says "cache this", PHP's Cache-Control: private
overrides it.
Add this inside your PHP location block:
fastcgi_ignore_headers Cache-Control Expires Pragma;
fastcgi_hide_header Cache-Control;
fastcgi_hide_header Pragma;
For more granular control over specific URIs:
map $request_uri $skip_cache {
default 0;
~*/admincp/ 1;
~*/modcp/ 1;
~*/login\.php 1;
}
location ~ \.php(/.*)?$ {
fastcgi_cache RWI;
fastcgi_cache_valid 200 60m;
fastcgi_ignore_headers Cache-Control Expires Pragma;
fastcgi_no_cache $skip_cache;
fastcgi_cache_bypass $skip_cache;
# ... rest of your config
}
Check with curl:
curl -I https://yoursite.com/forum/ | grep -iE 'X-Cache|Cache-Control'
Expected output after fixes:
X-Cache: HIT
Cache-Control: (should be missing or overwritten)
For logged-in users handling:
map $http_cookie $cache_condition {
default "public";
~*rwi_userid|rwi_password "private";
}
server {
location ~ \.php$ {
fastcgi_cache_key "$scheme$request_method$host$request_uri$cache_condition";
# ...
}
}
After implementing these changes, monitor:
- Cache hit ratio (80%+ is good)
- Backend PHP process CPU usage
- Memory usage of FastCGI cache zone
When implementing FastCGI caching with Nginx for PHP applications like vBulletin, you might encounter persistent "MISS" statuses due to conflicting headers. The core issue arises when PHP scripts send:
Cache-Control: private
Pragma: no-cache
These headers automatically bypass FastCGI cache regardless of your Nginx configuration.
Nginx respects these HTTP headers by default. Even with proper fastcgi_cache
setup:
location ~ \.php(/.*)?$ {
fastcgi_cache RWI;
fastcgi_cache_valid 200 60m;
# ... other configs ...
}
The cache will still honor PHP's private
directive unless explicitly overridden.
Add this to your PHP location block:
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
fastcgi_hide_header Cache-Control;
fastcgi_hide_header Pragma;
This tells Nginx to:
- Ignore specific caching-related headers from backend
- Remove them from the final response
Here's the full optimized configuration:
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=RWI:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
server {
# ... other server configs ...
location ~ \.php(/.*)?$ {
fastcgi_cache RWI;
fastcgi_cache_valid 200 60m;
# Header control
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
fastcgi_hide_header Cache-Control;
fastcgi_hide_header Pragma;
# Cache bypass conditions
set $nocache 0;
if ($request_method = POST) {
set $nocache 1;
}
if ($http_cookie ~ (rwi_userid|rwi_password)) {
set $nocache 1;
}
if ($request_uri ~* "/vb/admincp/") {
set $nocache 1;
}
fastcgi_no_cache $nocache;
fastcgi_cache_bypass $nocache;
# Standard PHP handling
fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_pass "unix:/var/www/vhosts/system/example.com/php-fpm.sock";
include /etc/nginx/fastcgi.conf;
}
add_header X-Cache $upstream_cache_status;
}
After implementing these changes:
- Clear your existing cache:
rm -rf /var/cache/nginx/*
- Make test requests while monitoring headers:
curl -I https://yoursite.com/forum/
- Check for
X-Cache: HIT
in responses
When overriding cache headers:
- Ensure sensitive areas (admin, login) are properly excluded
- Monitor cache hit ratio with tools like GoAccess
- Adjust
inactive
time based on your traffic patterns
If caching still doesn't work:
# Check Nginx error logs
tail -f /var/log/nginx/error.log
# Verify cache directory permissions
ls -ld /var/cache/nginx
# Test FastCGI cache key
echo -n "httpsGETexample.com/forum/" | md5sum