How to Setup Nginx FastCGI Cache on Ubuntu 26.04, 24.04 and 22.04

Set up Nginx FastCGI Cache on Ubuntu 26.04, 24.04 and 22.04 to speed up PHP and WordPress sites. Covers configuration, cache exclusions, and verification.

Last updatedAuthorJoshua JamesRead time9 minGuide typeUbuntu

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_purge is 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 releaseDefault 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:

DirectiveValid contextDefault or package noteUsed for
fastcgi_cache_pathhttpNo default path.Creates the cache directory settings and shared memory zone.
fastcgi_cache_keyhttp, server, locationNo default key.Defines the unique key for each cached response.
fastcgi_cachehttp, server, locationDefault is off.Enables a named cache zone for matching requests.
fastcgi_cache_validhttp, server, locationNo default cache time.Sets how long selected response codes stay cached.
fastcgi_cache_lockhttp, server, locationDefault is off.Allows one request to populate a missing cache item while similar requests wait.
fastcgi_cache_bypasshttp, server, locationNo default skip condition.Prevents serving a cached response when a condition matches.
fastcgi_no_cachehttp, server, locationNo default store condition.Prevents saving a response when a condition matches.
fastcgi_cache_purgehttp, server, locationUpstream 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 named fcgicache for 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 in nginx.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 are MISS, HIT, BYPASS, EXPIRED, STALE, and UPDATING.

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:

  1. Logged-in cookies: Clear browser cookies or test from a private browser window.
  2. Query strings: URLs with parameters, such as ?preview=true, bypass cache in this configuration.
  3. Cache directory permissions: Reapply ownership and mode on the cache directory.
  4. Skip-cache rules: Review the $skip_cache conditions 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-Cache header, access logs, or monitoring tools to confirm repeat public traffic becomes HIT.
  • Size the cache conservatively: Start with a modest max_size and 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

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.

Share this guide

Help another Linux user troubleshoot faster

Share this guide with someone troubleshooting Linux systems or saving it for later.

Follow LinuxCapable

Want more LinuxCapable guides in Google?

Add LinuxCapable as a preferred source so Google can show our tutorials more often in Top Stories and mark them as preferred in AI Mode and AI Overviews when relevant.

Add LinuxCapable as a preferred source on Google
Search LinuxCapable

Need another guide?

Search LinuxCapable for package installs, commands, troubleshooting, and follow-up guides related to what you just read.

Found this guide useful?

Support LinuxCapable to keep tutorials free and up to date.

Buy me a coffeeBuy me a coffee
Before commenting, please review our Comments Policy.
Formatting tips for your comment

You can use basic HTML to format your comment. Useful tags currently allowed in published comments:

You type Result
<code>command</code> command
<strong>bold</strong> bold
<em>italic</em> italic
<a href="https://example.com">link</a> link
<blockquote>quote</blockquote> quote block

Add to the discussion

Questions, fixes, command output, and version notes help keep this guide current.

Verify before posting: