Nginx FastCGI Cache stores PHP responses directly in memory or on disk, allowing Nginx to serve repeated requests without invoking PHP-FPM. This reduces backend load, speeds up page delivery, and helps WordPress, Laravel, and other PHP applications handle higher traffic with fewer resources. By the end of this guide, you will have FastCGI caching configured with cache exclusions for dynamic content, optional RAM-based storage for faster access, and verification steps to confirm everything works.
These steps cover Ubuntu 22.04 LTS, 24.04 LTS, and 26.04 LTS. The commands work identically across all supported LTS releases, and the cache purge functionality requires Nginx 1.5.7 or later (all Ubuntu LTS versions ship with compatible Nginx versions).
Prerequisites
Before configuring FastCGI Cache, ensure you have Nginx and PHP-FPM installed on your Ubuntu server. If you need to install Nginx, follow our guide on how to install Nginx on Ubuntu Linux. This tutorial assumes you already have a working LEMP stack (Linux, Nginx, MariaDB/MySQL, PHP) or at minimum Nginx with PHP-FPM configured.
Additionally, you need an existing Nginx server block configuration for your site. The examples in this guide use example.com.conf as a placeholder, so replace this with your actual server block filename.
Create the FastCGI Cache Directory
First, create the directory where Nginx will store cached responses. This directory must exist before you add the cache configuration to nginx.conf, otherwise the configuration test will fail:
sudo mkdir -p /var/nginx/fastcgi_cache
Confirm the directory exists:
ls -la /var/nginx/
total 12 drwxr-xr-x 3 root root 4096 Dec 28 10:00 . drwxr-xr-x 15 root root 4096 Dec 28 10:00 .. drwxr-xr-x 2 root root 4096 Dec 28 10:00 fastcgi_cache
Configure the Cache Path in nginx.conf
With the cache directory in place, open the main Nginx configuration file to define the cache zone. This configuration goes in the http block and applies globally to all server blocks that reference it:
sudo nano /etc/nginx/nginx.conf
Locate the http block and add the following two lines inside it, before any include statements:
fastcgi_cache_path /var/nginx/fastcgi_cache levels=1:2 keys_zone=fcgicache:150m max_size=20g inactive=60m use_temp_path=off;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
Press Ctrl+O, then Enter to save, and Ctrl+X to exit nano.
Understanding the Cache Path Parameters
Each parameter in the fastcgi_cache_path directive controls a specific aspect of cache behavior:
/var/nginx/fastcgi_cache: The filesystem path where Nginx stores cached responses. Nginx creates subdirectories here based on thelevelsparameter.levels=1:2: Creates a two-level directory hierarchy using the last characters of the MD5 hash of each cache key. This prevents any single directory from containing too many files, which would slow down filesystem operations.keys_zone=fcgicache:150m: Allocates 150MB of shared memory for storing cache keys and metadata. One megabyte can hold approximately 8,000 keys. You reference this zone name (fcgicache) later in server block configurations.max_size=20g: Limits the total cache size to 20GB on disk. When cache size reaches this limit, Nginx removes the least recently used entries first.inactive=60m: Removes cached entries that have not been accessed within 60 minutes, regardless of whether they are still valid.use_temp_path=off: Writes cached responses directly to the cache directory instead of using a temporary location first. This avoids unnecessary file moves and improves performance when the cache is on the same filesystem.
The fastcgi_cache_key directive defines what makes each cached response unique. The combination of scheme (HTTP/HTTPS), request method (GET/POST), hostname, and URI ensures that different pages and different access methods are cached separately.
Configure FastCGI Cache in Your Server Block
Next, modify your site’s server block to enable caching for PHP requests. Open your server block configuration file:
sudo nano /etc/nginx/sites-available/example.com.conf
Add Cache Exclusion Rules
Before the PHP location block, add variables to control which requests should bypass the cache. WordPress admin pages, logged-in users, and POST requests should never be cached because they contain dynamic or user-specific content:
# Cache by default
set $skip_cache 0;
# Don't cache URIs containing the following
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|^/feed/|/tag/.*/feed/|index.php|/.*sitemap.*\.(xml|xsl)") {
set $skip_cache 1;
}
# Don't cache for logged-in users or comment authors
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $skip_cache 1;
}
# POST requests and URIs with a query string should bypass the cache
if ($request_method = POST) {
set $skip_cache 1;
}
if ($query_string != "") {
set $skip_cache 1;
}
Enable Caching in the PHP Location Block
Inside your existing location ~ \.php$ block, add the FastCGI cache directives. These must appear alongside your existing fastcgi_pass and fastcgi_param directives:
location ~ \.php$ {
# Existing FastCGI configuration
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php-fpm.sock;
# FastCGI Cache settings
fastcgi_cache fcgicache;
fastcgi_cache_valid 200 60m;
fastcgi_cache_use_stale error timeout updating invalid_header http_500 http_503;
fastcgi_cache_min_uses 1;
fastcgi_cache_lock on;
# Connect the skip_cache variable to bypass and no_cache directives
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
# Add header to show cache status in responses
add_header X-FastCGI-Cache $upstream_cache_status always;
}
Understanding the Cache Directives
fastcgi_cache fcgicache: Enables caching using the zone defined earlier innginx.conf.fastcgi_cache_valid 200 60m: Caches responses with HTTP 200 status for 60 minutes. You can add multiple lines for different status codes (e.g.,fastcgi_cache_valid 301 302 10m;).fastcgi_cache_use_stale: Serves stale cached content when PHP-FPM is unavailable, returns errors, or is currently updating the cache. This improves availability during backend issues.fastcgi_cache_min_uses 1: Caches a response after just one request. Increase this value on high-traffic sites to avoid caching one-off requests.fastcgi_cache_lock on: When multiple requests arrive for the same uncached content simultaneously, Nginx sends only one request to PHP-FPM. The others wait for the cache to populate, preventing a “cache stampede.”fastcgi_cache_bypass $skip_cache: Tells Nginx not to serve cached content when$skip_cacheis 1. The request still goes to PHP-FPM.fastcgi_no_cache $skip_cache: Tells Nginx not to save the response to cache when$skip_cacheis 1. You need both directives together for full bypass functionality.add_header X-FastCGI-Cache ... always: Adds a response header showing the cache status. Thealwaysparameter ensures the header appears even on error responses. Possible values are: HIT (served from cache), MISS (not cached, response now stored), BYPASS (cache skipped due to skip_cache rules), EXPIRED (served stale content while revalidating), STALE (served expired content due to backend error), UPDATING (served stale content while cache updates), and REVALIDATED (cache entry was revalidated with backend).
Press Ctrl+O, then Enter to save, and Ctrl+X to exit.
Configure Cache Purging (Optional)
Cache purging allows you to manually invalidate cached content when you update a page or post. This feature is available in Nginx 1.5.7 and later, which all Ubuntu LTS versions provide. Add this location block to your server block configuration:
location ~ /purge(/.*) {
# Only allow purge requests from localhost
allow 127.0.0.1;
deny all;
fastcgi_cache_purge fcgicache "$scheme$request_method$host$1";
}
With this configuration, you can purge a specific cached page by requesting the purge URL. For example, to purge the cached version of /about/, you would access http://localhost/purge/about/ from the server itself.
This configuration restricts the purge location to localhost for security. If you need to purge cache from external systems, consider using a secret key parameter or integrating with WordPress plugins like Nginx Helper that handle cache invalidation automatically.
Test and Apply the Configuration
Before restarting Nginx, always test the configuration for syntax errors:
sudo nginx -t
If the configuration is valid, you will see:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
Now restart Nginx to apply the changes:
sudo systemctl restart nginx
Verify FastCGI Cache is Working
Test the cache by making HTTP requests and examining the response headers. The curl command shows the headers without downloading the full page:
curl -I https://www.example.com/
The first request will show a cache MISS because the page has not been cached yet:
HTTP/1.1 200 OK Server: nginx ... X-FastCGI-Cache: MISS
Run the same command again:
curl -I https://www.example.com/
The second request should show a cache HIT:
HTTP/1.1 200 OK Server: nginx ... X-FastCGI-Cache: HIT
If you see HIT on subsequent requests, FastCGI caching is working correctly. If you only see MISS, check that:
- You are not logged into WordPress (which sets cache-bypass cookies)
- The URL does not contain query strings
- The cache directory has proper write permissions for the
www-datauser
Inspect Cached Files
To see what Nginx has cached, list the contents of the cache directory. The levels=1:2 parameter creates a hierarchy of subdirectories based on the MD5 hash of each cache key:
sudo find /var/nginx/fastcgi_cache -type f | head -5
/var/nginx/fastcgi_cache/9/c2/b7f54b2df7773722d382f4809d65029c2 /var/nginx/fastcgi_cache/a/17/8b3f9e4c2a1d876f5e0c9d4b3a2f17a17
Each file contains the cached HTTP response, including headers and body. You can examine a cached entry with head to see the cache metadata Nginx stores:
sudo head -20 /var/nginx/fastcgi_cache/9/c2/b7f54b2df7773722d382f4809d65029c2
This is useful for debugging when you need to verify that specific pages are being cached or to understand why certain responses are being served.
Optimize with RAM-Based Cache Storage (Optional)
For servers with sufficient RAM, storing the cache in a tmpfs filesystem provides faster read and write speeds than disk storage. This is particularly beneficial for high-traffic sites where disk I/O can become a bottleneck.
RAM-based caching means cached content is lost on reboot. This is usually acceptable because the cache rebuilds quickly as requests come in. Ensure you have enough RAM for both your applications and the cache allocation.
Open the filesystem table for editing:
sudo nano /etc/fstab
Add the following line at the end of the file:
tmpfs /var/nginx/fastcgi_cache tmpfs defaults,size=512M 0 0
This allocates 512MB of RAM for the cache. Adjust the size based on your server’s available memory and expected cache requirements.
Press Ctrl+O, then Enter to save, and Ctrl+X to exit. Then mount the new filesystem:
sudo mount -a
Verify the tmpfs mount:
df -h /var/nginx/fastcgi_cache
Filesystem Size Used Avail Use% Mounted on tmpfs 512M 0 512M 0% /var/nginx/fastcgi_cache
Troubleshooting Common Issues
Cache Always Shows MISS
If every request returns X-FastCGI-Cache: MISS, check these common causes:
- Logged-in cookies: Clear your browser cookies or test from a different browser/incognito window.
- Query strings: URLs with query parameters (
?foo=bar) are not cached by default. Test with a clean URL. - Cache directory permissions: Ensure the Nginx worker process can write to the cache directory:
sudo chown -R www-data:www-data /var/nginx/fastcgi_cache - Skip cache rules too broad: Review your
$skip_cacheconditions to ensure they are not matching all requests.
Configuration Test Fails with “mkdir() failed”
If nginx -t fails with an error like:
nginx: [emerg] mkdir() "/var/nginx/fastcgi_cache" failed (2: No such file or directory)
The cache directory does not exist. Create it with:
sudo mkdir -p /var/nginx/fastcgi_cache
Cache Shows BYPASS Instead of HIT
A BYPASS status means the $skip_cache variable matched a bypass condition for that request. Common triggers include:
- WordPress login cookies present in the request
- The URL matches one of your skip patterns (wp-admin, xmlrpc.php, etc.)
- The request method is POST
Expect this behavior for dynamic or authenticated content.
Remove FastCGI Cache Configuration
If you need to disable FastCGI caching, remove or comment out the configuration in two locations:
1. Remove from nginx.conf: Delete or comment out the fastcgi_cache_path and fastcgi_cache_key lines from the http block.
2. Remove from server block: Delete or comment out all fastcgi_cache* directives, the $skip_cache variable block, and the purge location block.
Then test and restart Nginx:
sudo nginx -t
sudo systemctl restart nginx
To clean up the cache files and directory:
This removes all cached responses. The cache will rebuild automatically when visitors access your site, so this is safe to run at any time.
sudo rm -rf /var/nginx/fastcgi_cache
If you configured tmpfs, remove the line from /etc/fstab as well.
Best Practices
- Monitor cache usage: Check cache hit rates periodically by examining access logs or using monitoring tools. A healthy cache should show high HIT ratios for repeat visitors.
- Size the cache appropriately: Start with conservative values and increase based on actual usage. Monitor disk space if using disk-based caching or RAM usage for tmpfs.
- Integrate with your CMS: WordPress plugins like Nginx Helper can automatically purge specific pages when content is updated, keeping the cache fresh without manual intervention.
- Consider separate cache zones: High-traffic sites may benefit from multiple cache zones with different retention policies. For example, a shorter cache time for news pages and longer for static content like documentation.
- Combine with other optimizations: FastCGI caching works well alongside Gzip compression, security headers, and static file caching for comprehensive performance improvements.
Further Reading
- Nginx FastCGI Module Documentation – Official reference for all FastCGI directives and parameters
- Install Nginx on Ubuntu Linux – Complete installation guide if you need to set up Nginx from scratch
- Rate Limiting in Nginx – Protect your server from abuse while caching helps with legitimate traffic
- Install WordPress with Nginx on Ubuntu Linux – Complete LEMP stack setup for WordPress if you are starting from scratch
Conclusion
FastCGI caching reduces PHP-FPM load by serving repeated requests directly from Nginx’s cache. With the cache zone configured in nginx.conf, exclusion rules protecting dynamic content, and the X-FastCGI-Cache header providing visibility into cache behavior, you have a complete caching setup ready for production WordPress or PHP sites. The optional tmpfs configuration provides additional performance for servers with available RAM, and the purge endpoint allows targeted cache invalidation when content changes.
Formatting tips for your comment
You can use basic HTML to format your comment. Useful tags currently allowed:
<code>command</code>command<strong>bold</strong><em>italic</em><blockquote>quote</blockquote>