Configure Nginx as a caching reverse proxy
Set up a bounded response cache, exclude personalized requests, inspect cache status, and manage expiry without confusing bypass with purge.
Define a cache path and shared index in http, then enable that zone in the proxied location. Start with content that is safe to share. A cached personalized response is a correctness problem even when it improves the hit rate.
Configure a public-content cache
This example keeps requests carrying cookies or Authorization out of both cache lookup and storage:
http {
proxy_cache_path /var/cache/nginx/public
levels=1:2
keys_zone=public_cache:10m
max_size=10g
inactive=60m
use_temp_path=off;
map $http_cookie $has_cookie {
"" 0;
default 1;
}
map $http_authorization $has_auth {
"" 0;
default 1;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cache public_cache;
proxy_cache_key "$scheme$host$request_uri";
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_bypass $has_cookie $has_auth;
proxy_no_cache $has_cookie $has_auth;
proxy_cache_lock on;
add_header X-Cache-Status $upstream_cache_status always;
}
}
}
Adapt the handler and cacheable statuses to the application. This is conservative: even a non-personalizing cookie bypasses the cache. If response selection depends on other inputs, account for them in cache variation or bypass rules before enabling caching.
Understand the settings
levels=1:2 spreads cache files across two directory levels. keys_zone stores the in-memory index, not all response bodies. max_size controls cache-manager cleanup rather than reserving disk or imposing an instantaneous hard ceiling. inactive=60m removes entries not accessed for that period, regardless of whether they remain fresh.
The explicit key includes the public host because the backend receives that host and may vary its response accordingly. The default key uses $proxy_host, not automatically the client-facing $host. Never assume those are interchangeable in a multi-tenant setup.
Upstream Cache-Control, Expires, and X-Accel-Expires can affect caching. Set-Cookie responses are not normally cached. Do not disable those protections merely to obtain more HITs.
Verify cache behavior
Request an eligible URL twice and inspect X-Cache-Status and logs. A MISS followed by HIT is useful evidence for that request, not a guarantee that every response is cacheable. Test cookies, Authorization, different hosts, query parameters, and error responses separately.
proxy_cache_bypass controls reading from cache; proxy_no_cache controls storing the fetched response. A response excluded from storage by its headers does not necessarily show BYPASS. Check both request conditions and upstream headers when investigating persistent misses.
Use stale content only where acceptable
proxy_cache_use_stale error timeout http_500 http_502;
This can serve an existing stale response during selected failures. Decide whether stale content is acceptable for the endpoint; it is a poor default for sensitive or rapidly changing state. proxy_cache_lock on reduces simultaneous population of the same new key, subject to its configured timeouts.
Plan invalidation and capacity
Use versioned asset URLs, a cache-key version, or a supported restricted purge interface. NGINX Plus and third-party purge modules have different syntax. Reloading Nginx is not a purge, and deleting a live cache directory is neither atomic nor free of load consequences.
Ensure the worker can use the cache and temporary directories and that the filesystem has enough free space. Monitor origin traffic after invalidation because a cold cache can produce a sudden load increase.
FAQ
Why is every request BYPASS?
Inspect the evaluated bypass variables. Set-Cookie and private cache-control responses concern storage eligibility and are not equivalent to a bypass-condition match.
Are POST requests cached?
By default, only GET and HEAD are cacheable. Adding POST requires a deliberate cache-key and response-semantics design, including request-body differences; simply adding the method can serve the wrong response.
How much faster will caching be?
Measure your workload. An eligible HIT avoids that origin fetch, but the effect on end-to-end latency and resource use depends on hit rate, response size, and the rest of the request path.
Reference: Nginx proxy cache directives.
Contact us
Join the community
to join the community
Try Guance
Start online and pay only for what you use.
Get startedChoose a Guance plan