How to Force FastCGI Cache to Ignore PHP’s Cache-Control Headers and Prevent “MISS” Status


2 views
// 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:

  1. Ignore specific caching-related headers from backend
  2. 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:

  1. Clear your existing cache: rm -rf /var/cache/nginx/*
  2. Make test requests while monitoring headers:
    curl -I https://yoursite.com/forum/
    
  3. 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