Nginx FastCGI caching dramatically reduces PHP processing load by storing rendered responses on disk and serving them directly to subsequent visitors. On RHEL 8, combining Nginx with a PHP-FPM backend and a well-configured cache can cut backend response times by 80–95% for cacheable pages. This tutorial walks through configuring the fastcgi_cache_path directive, defining cache keys, bypassing the cache for authenticated users, and verifying hits with curl. By the end you will have a production-ready caching layer protecting your PHP application.
Prerequisites
- RHEL 8 server with a sudo-capable user
- Nginx installed and running (
dnf install -y nginx) - PHP-FPM installed and configured (
dnf install -y php-fpm) - A PHP application (WordPress or similar) accessible via PHP-FPM socket or TCP
- SELinux in enforcing mode (default on RHEL 8)
firewalldactive and HTTP/HTTPS ports open
Step 1 — Define the Cache Path in the http Block
Open the main Nginx configuration file and add the cache zone definition inside the http block. This allocates a 256 MB shared memory zone named PHP_CACHE and reserves 2 GB of disk storage under /var/cache/nginx/fastcgi.
sudo mkdir -p /var/cache/nginx/fastcgi
sudo chown nginx:nginx /var/cache/nginx/fastcgi
# Add inside the http { } block in /etc/nginx/nginx.conf
# fastcgi_cache_path /var/cache/nginx/fastcgi
# levels=1:2
# keys_zone=PHP_CACHE:256m
# max_size=2g
# inactive=60m
# use_temp_path=off;
Edit the file directly:
sudo nano /etc/nginx/nginx.conf
Add the fastcgi_cache_path line after the http { opening brace, then save.
Step 2 — Set the Cache Key and Global Cache Settings
Still inside the http block, define the cache key and a global ignore-headers directive so cookies do not accidentally fragment the cache.
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_use_stale error timeout updating invalid_header http_500;
fastcgi_cache_lock on;
add_header X-Cache-Status $upstream_cache_status;
Step 3 — Enable Caching in the Server Block
Inside your virtual-host server block, create two map variables that determine whether a request should bypass the cache — one for active PHP sessions, another for POST requests. Then enable caching in the PHP location block.
# /etc/nginx/conf.d/example.com.conf
map $http_cookie $no_cache_cookie {
default 0;
"~*wordpress_logged_in" 1;
"~*comment_author" 1;
}
map $request_method $no_cache_method {
default 0;
POST 1;
}
server {
listen 80;
server_name example.com www.example.com;
root /var/www/html;
index index.php;
location ~ .php$ {
fastcgi_pass unix:/run/php-fpm/www.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_cache PHP_CACHE;
fastcgi_cache_valid 200 301 302 10m;
fastcgi_cache_valid 404 1m;
fastcgi_cache_bypass $no_cache_cookie $no_cache_method;
fastcgi_no_cache $no_cache_cookie $no_cache_method;
}
}
Step 4 — Apply SELinux Context and Reload Nginx
RHEL 8 SELinux policy requires the cache directory to carry the httpd_cache_t context so Nginx can write to it.
sudo semanage fcontext -a -t httpd_cache_t "/var/cache/nginx/fastcgi(/.*)?"
sudo restorecon -Rv /var/cache/nginx/fastcgi
sudo nginx -t
sudo systemctl reload nginx
Step 5 — Test Cache Hits with curl
Send two requests to the same URL and inspect the X-Cache-Status response header. The first request populates the cache (MISS); subsequent requests return HIT.
curl -sI http://example.com/ | grep -i x-cache
# X-Cache-Status: MISS
curl -sI http://example.com/ | grep -i x-cache
# X-Cache-Status: HIT
Step 6 — Purge the Cache
Nginx open-source does not include a built-in purge module, but you can delete cache files directly. The cache path uses the MD5 of the cache key as its filename hierarchy.
# Remove all cached objects
sudo find /var/cache/nginx/fastcgi -type f -delete
sudo systemctl reload nginx
# Alternatively, install nginx-mod-http-cache-purge from EPEL
# and add `fastcgi_cache_purge PURGE from 127.0.0.1;` to the location block
Conclusion
You have configured Nginx FastCGI caching on RHEL 8, defined a per-request cache key, added bypass rules for logged-in users and POST submissions, applied the correct SELinux file context, and verified cache behavior with curl -I. The X-Cache-Status header gives you real-time visibility into cache hits and misses without touching log files. This setup is safe to deploy behind Cloudflare or any upstream CDN because the bypass logic prevents stale authenticated content from leaking to other users.
Next steps: How to Set Up Varnish Cache as a Reverse Proxy on RHEL 8, How to Configure HAProxy for HTTP and TCP Load Balancing on RHEL 8, and How to Set Up a LEMP Stack on RHEL 8.