Nginx Cheatsheet
Caching
Use this Nginx reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Proxy Cache Setup
http {
# Define a cache zone (put this in http {}, outside server {})
proxy_cache_path /var/cache/nginx
levels=1:2
keys_zone=my_cache:10m
max_size=1g
inactive=60m
use_temp_path=off;
}| Parameter | Example | Meaning |
|---|---|---|
| path | /var/cache/nginx | Directory for cache files |
levels | 1:2 | 2-level subdirectory hierarchy (avoids huge single dirs) |
keys_zone | my_cache:10m | Name and shared memory size for keys |
max_size | 1g | Max disk usage; LRU eviction when exceeded |
inactive | 60m | Remove items not accessed within this window |
use_temp_path | off | Write directly to cache dir (avoids extra copy) |
Enabling Cache in a Location
location / {
proxy_pass http://backend;
proxy_cache my_cache;
proxy_cache_valid 200 302 10m; # Cache 200/302 for 10 min
proxy_cache_valid 301 1h;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on; # Prevent thundering herd on cold cache
proxy_cache_min_uses 1; # Cache after 1 request
add_header X-Cache-Status $upstream_cache_status;
}$upstream_cache_status Values
| Value | Meaning |
|---|---|
HIT | Served from cache |
MISS | Not in cache; fetched from upstream |
EXPIRED | In cache but expired; re-fetched |
STALE | Served stale copy while re-fetching |
UPDATING | Stale; background update in progress |
REVALIDATED | Cache validated with upstream (304) |
BYPASS | Cache bypassed (see below) |
Bypassing Cache
# Bypass when client sends Pragma: no-cache or Cache-Control: no-cache
map $http_cache_control $bypass {
"no-cache" 1;
default 0;
}
location / {
proxy_cache my_cache;
proxy_cache_bypass $bypass $cookie_session; # Bypass if either is non-empty
proxy_no_cache $bypass $cookie_session; # Don't store response either
}Common bypass variables: $cookie_session, $http_authorization, $arg_nocache.
Serving Stale Content
proxy_cache_use_stale error timeout updating
http_500 http_502 http_503 http_504;
# Extend stale serving time even if upstream is reachable
proxy_cache_background_update on;
proxy_cache_revalidate on; # Use conditional GET (If-Modified-Since)Cache Key
# Default key: scheme + method + host + URI proxy_cache_key "$scheme$request_method$host$request_uri"; # Custom key (ignore query string) proxy_cache_key "$host$uri"; # Include auth for per-user caching (expensive — large key space) proxy_cache_key "$host$uri$http_authorization";
Cache Purge
Nginx OSS has no built-in purge. Cache files are extensionless, named by the MD5 of the cache key (there is no *.cache suffix), stored under the levels hierarchy.
# Path for one URL: md5 of the proxy_cache_key value echo -n "httpGETexample.com/page" | md5sum # → 8f7e...c2a1b → with levels=1:2 the file lives at # /var/cache/nginx/b/a1/8f7e...c2a1b (last char / previous 2 chars) # Or grep for the KEY line embedded in each cache file grep -lr "KEY: httpGETexample.com/page" /var/cache/nginx | xargs rm -f # Nuke the whole cache (nginx recreates entries on demand) rm -rf /var/cache/nginx/*
Use the ngx_cache_purge module for PURGE method support, or use Nginx Plus (proxy_cache_purge).
FastCGI Cache (PHP-FPM)
http {
fastcgi_cache_path /var/cache/nginx/fastcgi
levels=1:2 keys_zone=php_cache:10m max_size=512m;
}
server {
set $skip_cache 0;
if ($request_method = POST) { set $skip_cache 1; }
if ($query_string != "") { set $skip_cache 1; }
if ($request_uri ~* "wp-admin|login") { set $skip_cache 1; }
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
include fastcgi_params;
fastcgi_cache php_cache;
fastcgi_cache_valid 200 1h;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
add_header X-Cache $upstream_cache_status;
}
}Browser Cache (via expires)
location ~* \.(css|js)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
location ~* \.(html)$ {
expires -1; # no-cache
add_header Cache-Control "no-store";
}expires | Cache-Control result |
|---|---|
1h | max-age=3600 |
1y | max-age=31536000 |
-1 | no-cache |
epoch | no-cache (date in the past) |
max | max-age=315360000 |
off | No header added |