Nginx FastCGI Cache on Ubuntu reduces PHP-FPM work by storing repeat dynamic responses in an Nginx-managed cache directory. For WordPress, Laravel, phpMyAdmin, and similar PHP applications, this can turn later visits to the same anonymous page into a fast Nginx cache HIT instead of another backend PHP request.
This setup uses Ubuntu’s packaged Nginx, keeps admin and logged-in traffic out of cache, exposes an X-FastCGI-Cache response header for verification, and includes a stock-safe way to clear cached files when content changes.
These steps support Ubuntu 26.04 LTS, 24.04 LTS, and 22.04 LTS with Ubuntu’s stock Nginx packages. Standard FastCGI caching works across this scope, but URL-based
fastcgi_cache_purgeis not available in stock Nginx unless you add a separate cache-purge module or use a commercial Nginx build.
Prerequisites
Start with a working Nginx and PHP-FPM site on Ubuntu. If you still need the base web server, use Install Nginx on Ubuntu. If PHP-FPM is not configured yet, use Install PHP on Ubuntu, the full Install WordPress with Nginx on Ubuntu stack guide, or Install phpMyAdmin with LEMP on Ubuntu.
You also need an existing Nginx server block for the site you want to cache. The examples use example.com.conf and www.example.com as placeholders; replace them with your real server block filename and hostname.
FastCGI Cache vs Static File Caching
FastCGI Cache stores dynamic responses generated through PHP-FPM. It does not cache normal static files such as images, CSS, JavaScript, fonts, or downloads because those files should be served directly by Nginx without reaching PHP-FPM.
It is also separate from PHP OPcache, directio, and the Linux page cache. OPcache stores compiled PHP bytecode inside PHP, while directio and the Linux page cache affect file I/O for static or large file reads rather than full PHP-generated HTTP responses.
If your goal is static-file performance, use browser cache headers, enable open file cache in Nginx, enable the Nginx sendfile directive, or enable Gzip compression in Nginx. Use FastCGI Cache when repeat PHP pages are the slow part.
Confirm Your PHP-FPM Socket
Before editing the PHP location block, confirm the socket path your PHP-FPM pool exposes. Ubuntu’s default PHP branch differs by LTS release, so the safest path is to inspect the running socket files:
ls -l /run/php/*.sock
Default Ubuntu packages normally use these versioned sockets:
| Ubuntu release | Default PHP-FPM socket |
|---|---|
| Ubuntu 26.04 LTS | /run/php/php8.5-fpm.sock |
| Ubuntu 24.04 LTS | /run/php/php8.3-fpm.sock |
| Ubuntu 22.04 LTS | /run/php/php8.1-fpm.sock |
If /run/php/php-fpm.sock exists as a symlink on your server, you can use it. Otherwise, use the versioned socket shown by ls -l /run/php/*.sock in the Nginx fastcgi_pass line.
Create the FastCGI Cache Directory
Create a dedicated cache directory under /var/cache/nginx and give the Nginx worker user permission to write cache files:
sudo install -d -o www-data -g www-data -m 0750 /var/cache/nginx/fastcgi
Confirm the directory ownership before adding it to nginx.conf:
sudo ls -ld /var/cache/nginx/fastcgi
drwxr-x--- 2 www-data www-data 4096 Apr 28 10:00 /var/cache/nginx/fastcgi
Configure the Cache Zone in nginx.conf
Open the main Nginx configuration file and add the cache zone inside the top-level http block. The fastcgi_cache_path directive belongs in http, not inside an individual server or location block.
sudo nano /etc/nginx/nginx.conf
Add these lines inside the http block, before the final include lines if possible:
fastcgi_cache_path /var/cache/nginx/fastcgi 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";
Save and close the file. In nano, press Ctrl+O, press Enter, then press Ctrl+X.
FastCGI Directive Placement Reference
The official Nginx FastCGI module documentation defines where each directive is allowed. These are the placement rules used in this configuration:
| Directive | Valid context | Default or package note | Used for |
|---|---|---|---|
fastcgi_cache_path | http | No default path. | Creates the cache directory settings and shared memory zone. |
fastcgi_cache_key | http, server, location | No default key. | Defines the unique key for each cached response. |
fastcgi_cache | http, server, location | Default is off. | Enables a named cache zone for matching requests. |
fastcgi_cache_valid | http, server, location | No default cache time. | Sets how long selected response codes stay cached. |
fastcgi_cache_lock | http, server, location | Default is off. | Allows one request to populate a missing cache item while similar requests wait. |
fastcgi_cache_bypass | http, server, location | No default skip condition. | Prevents serving a cached response when a condition matches. |
fastcgi_no_cache | http, server, location | No default store condition. | Prevents saving a response when a condition matches. |
fastcgi_cache_purge | http, server, location | Upstream directive exists, but stock Ubuntu Nginx does not include the purge feature by default. | Not used here; clear cache files directly unless you knowingly install a purge-enabled build. |
Understanding the Cache Path Parameters
/var/cache/nginx/fastcgi: Stores cached FastCGI response files under a dedicated Nginx cache path.levels=1:2: Splits cached files into a two-level directory tree so one directory does not contain too many entries.keys_zone=fcgicache:150m: Creates a shared memory zone namedfcgicachefor cache keys and metadata.max_size=20g: Caps the on-disk cache size. Nginx removes least recently used entries as the cache approaches this limit.inactive=60m: Removes cached entries that have not been requested for 60 minutes, even if their normal cache lifetime has not expired.use_temp_path=off: Writes cache files directly under the cache directory instead of staging them in a separate temporary path first.
The cache key combines the request scheme, method, host, and URI. Including $request_method keeps GET and HEAD cache entries separate from other methods, while the skip rules below keep POST responses out of cache entirely.
Configure FastCGI Cache in Your Server Block
Open the server block for the site you want to cache:
sudo nano /etc/nginx/sites-available/example.com.conf
If your server uses a different layout, such as an nginx.org package with /etc/nginx/conf.d/, edit the active site file used by that package instead of forcing the Debian-style sites-available path.
Add Cache Exclusion Rules
Add the skip-cache rules inside the server block, before the PHP location block. These rules keep WordPress admin pages, logged-in sessions, POST requests, and query-string URLs out of cache.
# Cache by default
set $skip_cache 0;
# Do not cache WordPress admin, feeds, sitemaps, or PHP utility endpoints
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*\.php|^/feed/|/tag/.*/feed/|index.php|/.*sitemap.*\.(xml|xsl)") {
set $skip_cache 1;
}
# Do not cache logged-in users, comment authors, or password-protected posts
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $skip_cache 1;
}
# Do not cache POST requests or query-string URLs
if ($request_method = POST) {
set $skip_cache 1;
}
if ($query_string != "") {
set $skip_cache 1;
}
This is a limited and common Nginx if use: each condition only changes the $skip_cache variable. Avoid turning this block into complex rewrite logic.
Enable Caching in the PHP Location Block
Add the cache directives inside your existing location ~ \.php$ block. Keep your current include, fastcgi_param, and fastcgi_pass settings, but connect them to the cache zone and skip-cache variable.
location ~ \.php$ {
include snippets/fastcgi-php.conf;
# Use the PHP-FPM socket you confirmed earlier.
fastcgi_pass unix:/run/php/php-fpm.sock;
# FastCGI cache settings
fastcgi_cache fcgicache;
fastcgi_cache_valid 200 60m;
fastcgi_cache_valid 301 302 10m;
fastcgi_cache_use_stale error timeout updating invalid_header http_500 http_503;
fastcgi_cache_min_uses 1;
fastcgi_cache_lock on;
# Connect skip-cache rules to read and write behavior
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
# Show cache state in response headers
add_header X-FastCGI-Cache $upstream_cache_status always;
}
If /run/php/php-fpm.sock is not present, replace that line with your versioned socket, such as fastcgi_pass unix:/run/php/php8.3-fpm.sock; on a default Ubuntu 24.04 PHP-FPM install.
Understanding the Cache Directives
fastcgi_cache fcgicache: Enables caching with the shared memory zone defined innginx.conf.fastcgi_cache_valid 200 60m: Caches successful PHP responses for 60 minutes. For microcaching, use a much shorter value, such as seconds instead of minutes.fastcgi_cache_valid 301 302 10m: Caches PHP-generated redirects briefly so stale redirect behavior is less likely to linger.fastcgi_cache_use_stale: Allows Nginx to serve stale cached content during selected PHP-FPM errors or updates.fastcgi_cache_lock on: Lets one request populate a missing cache entry while matching concurrent requests wait, reducing backend spikes.fastcgi_cache_bypass $skip_cache: Prevents Nginx from reading from cache when the request should stay dynamic.fastcgi_no_cache $skip_cache: Prevents Nginx from saving the response when the request should stay dynamic.X-FastCGI-Cache: Adds a visible response header. Common values areMISS,HIT,BYPASS,EXPIRED,STALE, andUPDATING.
This setup intentionally does not cache POST responses. Caching POST traffic can expose user-specific form, login, checkout, or account state on dynamic sites.
Test and Apply the Configuration
Test the Nginx configuration before applying it:
sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
Reload Nginx after the syntax test passes:
sudo systemctl reload nginx
Verify FastCGI Cache is Working
Send a header-only request to a public page that anonymous visitors can view. Use the same hostname and scheme your real site uses; if the site does not already use TLS, keep the test URL on http://:
curl -I http://www.example.com/
The first eligible request usually shows MISS because Nginx has not cached the response yet:
HTTP/1.1 200 OK Server: nginx X-FastCGI-Cache: MISS
Run the same command again:
curl -I http://www.example.com/
HTTP/1.1 200 OK Server: nginx X-FastCGI-Cache: HIT
A later HIT confirms that Nginx served the response from FastCGI Cache. A BYPASS value is expected for logged-in sessions, POST requests, WordPress admin URLs, and query-string URLs.
Inspect Cached Files
List a few cache files to confirm Nginx is writing response entries under the cache directory:
sudo find /var/cache/nginx/fastcgi -type f | head -5
/var/cache/nginx/fastcgi/9/c2/b7f54b2df7773722d382f4809d65029c2 /var/cache/nginx/fastcgi/a/17/8b3f9e4c2a1d876f5e0c9d4b3a2f17a17
Clear FastCGI Cache on Ubuntu
Stock Ubuntu Nginx does not provide URL-based fastcgi_cache_purge in the default package. If you add that directive without the required module, sudo nginx -t fails with an unknown directive error.
For a stock Ubuntu setup, clear cached FastCGI response files directly from the dedicated cache directory. This command clears only the FastCGI response cache used in this guide; it does not clear browser cache headers, CDN cache, static-file tuning, or a separate proxy_cache path.
sudo find /var/cache/nginx/fastcgi -type f -delete
Run the delete command only against the dedicated FastCGI cache directory. Do not run broad cleanup commands against
/var/cache/nginx,/etc/nginx, or your web root.
Do not substitute proxy_cache_purge for this FastCGI setup. Proxy cache and FastCGI cache use different upstream modules even though their cache concepts look similar.
After clearing files, the next eligible request should show MISS, and the following request should return to HIT. CMS plugins can coordinate purge behavior only when your server exposes a supported purge method or lets the application safely remove local cache files.
Optimize with RAM-Based Cache Storage
A tmpfs mount can keep the FastCGI cache in RAM. This is optional and works best when the server has enough free memory for both the application and cached responses.
RAM-based cache files disappear on reboot. That is acceptable for many sites because the cache rebuilds from traffic, but it is not a substitute for persistent application data.
Open /etc/fstab:
sudo nano /etc/fstab
Add a line for the cache mount. Adjust size=512M for your server:
tmpfs /var/cache/nginx/fastcgi tmpfs defaults,size=512M 0 0
Stop Nginx, mount the cache path, restore ownership on the mounted directory, and start Nginx again:
sudo systemctl stop nginx
sudo mount /var/cache/nginx/fastcgi
sudo install -d -o www-data -g www-data -m 0750 /var/cache/nginx/fastcgi
sudo systemctl start nginx
Verify the cache path now uses tmpfs:
df -h /var/cache/nginx/fastcgi
Filesystem Size Used Avail Use% Mounted on tmpfs 512M 0 512M 0% /var/cache/nginx/fastcgi
Troubleshoot FastCGI Cache Issues
Cache Always Shows MISS
If every request returns X-FastCGI-Cache: MISS, first test a public page while logged out. Then check these common causes:
- Logged-in cookies: Clear browser cookies or test from a private browser window.
- Query strings: URLs with parameters, such as
?preview=true, bypass cache in this configuration. - Cache directory permissions: Reapply ownership and mode on the cache directory.
- Skip-cache rules: Review the
$skip_cacheconditions for a pattern that matches every request.
sudo install -d -o www-data -g www-data -m 0750 /var/cache/nginx/fastcgi
fastcgi_cache_path Directive Is Not Allowed Here
If sudo nginx -t reports that fastcgi_cache_path is not allowed, the directive is probably inside a server or location block. Move it to the top-level http block in /etc/nginx/nginx.conf.
nginx: [emerg] "fastcgi_cache_path" directive is not allowed here
Unknown Directive fastcgi_cache_purge
If Nginx reports an unknown fastcgi_cache_purge directive, remove that purge block from the stock configuration. The directive appears in the official FastCGI module reference, but the purge functionality is not included in Ubuntu’s default Nginx package.
nginx: [emerg] unknown directive "fastcgi_cache_purge"
Configuration Test Fails with mkdir()
If Nginx cannot create or open the cache path, recreate the directory with the expected ownership:
nginx: [emerg] mkdir() "/var/cache/nginx/fastcgi" failed (2: No such file or directory)
sudo install -d -o www-data -g www-data -m 0750 /var/cache/nginx/fastcgi
sudo nginx -t
Cache Shows BYPASS Instead of HIT
A BYPASS status means one of the skip-cache rules matched. Common triggers are WordPress login cookies, comment-author cookies, password-protected content, POST requests, query strings, and admin paths such as /wp-admin/.
Test again from a logged-out browser or with a clean curl request to a public URL before changing the rules. Do not remove logged-in or POST bypass logic unless you are certain the page never returns user-specific content.
Remove FastCGI Cache Configuration
To disable FastCGI Cache, remove the fastcgi_cache_path and fastcgi_cache_key lines from the http block in /etc/nginx/nginx.conf. Then remove the $skip_cache rules, fastcgi_cache* directives, fastcgi_no_cache, and X-FastCGI-Cache header line from the site server block.
Test and reload Nginx after removing the directives:
sudo nginx -t
sudo systemctl reload nginx
Clear remaining cache files only after the active configuration no longer references this cache path:
sudo rm -rf /var/cache/nginx/fastcgi
If you configured the optional tmpfs mount, remove the matching /var/cache/nginx/fastcgi line from /etc/fstab and unmount the cache path before deleting the directory. Back up the server block first if you may need to re-enable caching later.
Best Practices
- Cache only anonymous pages: Keep logged-in users, comments, carts, checkout pages, admin URLs, previews, and POST requests out of cache.
- Watch HIT ratios: Use the
X-FastCGI-Cacheheader, access logs, or monitoring tools to confirm repeat public traffic becomesHIT. - Size the cache conservatively: Start with a modest
max_sizeand adjust after watching disk or RAM use. - Coordinate with CDN caching: FastCGI Cache controls origin PHP responses. Cloudflare, reverse proxies, hosting panels, and application caches may add their own cache layer.
- Secure dynamic areas first: Pair caching with configure security headers in Nginx and rate limit in Nginx when public forms or login pages receive traffic.
Further Reading
- Nginx FastCGI module documentation – Official directive reference for
fastcgi_cache_path,fastcgi_cache_key,fastcgi_cache_bypass, and related FastCGI cache settings. - Install Nginx on Ubuntu – Base Nginx setup before adding FastCGI caching.
- curl command in Linux – Header checks for cache status, redirects, and response debugging.
- Enable open file cache in Nginx – Static-file metadata caching for images, CSS, JavaScript, and other non-PHP assets.
Conclusion
Nginx FastCGI Cache is now configured on Ubuntu with a writable cache directory, safe bypass rules for dynamic WordPress and PHP requests, a visible HIT/MISS header, and a stock-safe cache clearing workflow. Static assets remain a separate Nginx tuning path, while PHP-generated pages can now be served from cache when anonymous repeat traffic requests the same URL.


Formatting tips for your comment
You can use basic HTML to format your comment. Useful tags currently allowed in published comments:
<code>command</code>command<strong>bold</strong><em>italic</em><a href="https://example.com">link</a><blockquote>quote</blockquote>