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.