How to Configure Nginx FastCGI Cache to Achieve Sub-100ms WordPress Response Times

A technical server-side caching guide to configuring Nginx FastCGI cache (proxy_cache) for WordPress to dramatically reduce TTFB and handle traffic spikes without hitting PHP-FPM.

How to Configure Nginx FastCGI Cache to Achieve Sub-100ms WordPress Response Times

WordPress performance plugins like WP Rocket and W3 Total Cache do an excellent job of page-level caching. However, they all operate at the PHP layer — meaning PHP still boots up, WordPress still loads, and a cache lookup still happens before the cached HTML is served.

True server-side performance means serving cached responses before PHP ever executes. This is what Nginx FastCGI Cache achieves, and it can reduce your WordPress Time to First Byte (TTFB) from 400-800ms down to under 20ms.

If you are running WordPress on a Dedicated Linux VPS with Nginx and PHP-FPM, this is the single most impactful performance optimization you can implement.

How FastCGI Cache Works

When a visitor requests a page:

  1. Without cache: Nginx → PHP-FPM → WordPress → MySQL → HTML generated → sent to user (~400ms)
  2. With FastCGI Cache (cache MISS): Nginx → PHP-FPM → WordPress → MySQL → HTML generated → stored in Nginx cache → sent to user (~400ms, but cached for next request)
  3. With FastCGI Cache (cache HIT): Nginx reads static HTML from disk cache → sent directly to user (~5-20ms). PHP-FPM and MySQL are completely bypassed.

Step 1: Create the Cache Directory

sudo mkdir -p /var/cache/nginx/fastcgi
sudo chown www-data:www-data /var/cache/nginx/fastcgi

Step 2: Configure the FastCGI Cache Zone (nginx.conf)

Add the following to the http {} block in /etc/nginx/nginx.conf:

http {
    # ...existing config...

    # Define a shared memory zone for cache keys (10MB = ~80,000 keys)
    # Store cached files in /var/cache/nginx/fastcgi
    # Cached files unused for 60 minutes will be purged
    # Maximum cache size is 1GB
    fastcgi_cache_path /var/cache/nginx/fastcgi
                       levels=1:2
                       keys_zone=WORDPRESS:10m
                       inactive=60m
                       max_size=1g;

    fastcgi_cache_key "$scheme$request_method$host$request_uri";
}

Step 3: Configure the WordPress Virtual Host

In your WordPress site’s Nginx server block (/etc/nginx/sites-available/yourdomain.conf):

server {
    listen 80;
    server_name yourdomain.com;
    root /var/www/yourdomain/public;
    index index.php;

    # --- FastCGI Cache Settings ---
    set $skip_cache 0;

    # Don't cache POST requests
    if ($request_method = POST) { set $skip_cache 1; }

    # Don't cache URLs with query strings (search, filters)
    if ($query_string != "") { set $skip_cache 1; }

    # Don't cache logged-in users or recent commenters
    if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
        set $skip_cache 1;
    }

    # Don't cache the WordPress admin or cart pages
    if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml|/cart/|/checkout/|/my-account/") {
        set $skip_cache 1;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.1-fpm.sock;

        # --- Apply Cache ---
        fastcgi_cache WORDPRESS;
        fastcgi_cache_valid 200 301 302 60m;  # Cache successful responses for 60 min
        fastcgi_cache_bypass $skip_cache;
        fastcgi_no_cache $skip_cache;

        # Add header to show cache status (HIT/MISS/BYPASS) for debugging
        add_header X-FastCGI-Cache $upstream_cache_status;
    }

    location / {
        try_files $uri $uri/ /index.php?$args;
    }
}

Step 4: Test and Reload Nginx

Always test your configuration before reloading:

sudo nginx -t
# If output is "test is successful", reload:
sudo systemctl reload nginx

Step 5: Verify the Cache is Working

Use curl to check the cache status header:

# First request — should be MISS (PHP executed)
curl -I https://yourdomain.com | grep X-FastCGI-Cache
# X-FastCGI-Cache: MISS

# Second request — should be HIT (served from disk cache)
curl -I https://yourdomain.com | grep X-FastCGI-Cache
# X-FastCGI-Cache: HIT

A HIT response confirms that Nginx is serving cached HTML directly from disk, completely bypassing PHP and MySQL.

Cache Invalidation Strategy

The main challenge with server-side caching is cache invalidation — purging stale cached pages when content is updated. You have two options:

  1. Short TTL: Set fastcgi_cache_valid to 5m or 10m for news-heavy sites. Slightly stale content is acceptable.
  2. Active Purge with ngx_cache_purge module: Install the nginx-extras package which includes the cache purge module, then use the nginx-helper WordPress plugin to automatically purge the correct cached URL whenever a post is published or updated.

For a complementary approach that reduces database load further, consider combining FastCGI cache with Redis Object Caching. FastCGI handles full-page cache, while Redis handles repeated database query caching for logged-in users and dynamic pages that bypass FastCGI.

Conclusion

Nginx FastCGI Cache is the most powerful server-side performance tool available for WordPress. By serving cached responses directly from disk before PHP even loads, you can achieve sub-20ms TTFB, handle sudden traffic spikes without crashing your server, and reduce database load by over 90% for typical content sites.

Disclaimer: This post is for informational and educational purposes only, accurate to the best of our knowledge at publication. It does not constitute advice. We do not guarantee accuracy or completeness and accept no liability for any decisions or losses resulting from reliance on this content.