Preventing 502 Errors with NGINX proxy_cache_use_stale
Learn how to use NGINX's proxy_cache_use_stale directive to serve cached content during backend failures, eliminating 502 errors during maintenance windows.
24 Jul 2025, 09:57 UTC

The Problem: Hard Failures During Backend Restarts
When a backend application restarts, undergoes patching, or scales down, NGINX typically returns 502 Bad Gateway, 503 Service Unavailable, or 504 Gateway Timeout errors to clients. This creates a window of visible downtime—even if the backend is only unavailable for a few seconds. For the end user, this means broken pages and failed requests; for the operator, it means unnecessary monitoring alerts during routine maintenance.
The Solution: Graceful Degradation via Stale Content
The proxy_cache_use_stale directive allows NGINX to serve a cached response even if that response has technically expired, provided the backend is currently unreachable or returning an error. Instead of passing a hard failure to the client, NGINX delivers the last successfully cached version of the resource. This transforms a total outage into a state of graceful degradation.
When Stale Serving Triggers
NGINX will serve stale content only if the following conditions are met:
- A
proxy_cachezone is configured and active for the request. - A previously cached response exists for the specific URI.
- The backend responds with one of the error codes specified in the directive, or the connection times out.
Implementation Example
The following configuration caches successful responses for 10 minutes and instructs NGINX to serve stale content if the backend returns a 500-series error or if the connection times out.
# Define the cache path in the http block
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=STATIC:10m inactive=60m use_temp_path=off;
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend_upstream;
proxy_cache STATIC;
# Cache successful responses for 10 minutes
proxy_cache_valid 200 10m;
# Serve stale content on these specific conditions
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
# Add a header to verify cache status in the browser/curl
add_header X-Cache-Status $upstream_cache_status;
}
}
Verifying the Configuration
To ensure this is working as intended, perform these steps on a test environment:
- Populate the Cache: Request a page that returns dynamic data (like a timestamp). Verify the
X-Cache-Statusheader showsHITon the second request. - Simulate Failure: Stop the backend service or block the upstream port.
- Test Availability: Request the same page. The response should still return HTTP 200 with the old timestamp, and
X-Cache-Statusshould beSTALE. - Check Logs: Inspect
/var/log/nginx/error.logfor entries indicating that a stale response was served.
Trade-offs and Limitations
The primary trade-off is availability vs. freshness. Serving stale content is a strategic choice to keep the site online, but it may result in users seeing outdated information.
Critical Considerations
- Data Sensitivity: Do not use this for endpoints serving real-time financial data, user-specific session data, or authentication tokens. For these, it is better to return an error than incorrect data.
- Bypass Rules: If you use
proxy_no_cacheorproxy_cache_bypassfor certain requests,proxy_cache_use_stalewill not apply to those requests. - Version Requirements: The
updatingflag (which serves stale content while NGINX fetches a fresh copy in the background) requires NGINX Open Source 1.7.5 or later.
Applying the Changes
To deploy this configuration, follow these steps:
- Check Version: Run
nginx -vto ensure you are on a supported version. - Validate Syntax: Run
sudo nginx -tto check for configuration errors. - Reload Service: Apply changes without dropping connections using
sudo nginx -s reload.
By implementing proxy_cache_use_stale, you remove the pressure of zero-second cutovers during backend deployments, ensuring your users see a functional page rather than a gateway error.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.