Proxy Caching: Serve Safe Stale Assets and Pages
Cache static assets and API answers at the proxy with stale-while-revalidate so a slow or broken upstream never becomes a slow user experience.
Netbay Engineering
Netbay Engineering
On this page
Caching at the reverse proxy is the cheapest performance win available on a single server. Static assets are fetched from your app once and served from the proxy's memory or disk for the next hundred identical requests. Dynamic pages are riskier to cache, but with stale-while-revalidate you can serve an old copy instantly while a background request refreshes it — which is how many slow page experiences simply disappear.
What belongs in a proxy cache
- **Static files:** images, fonts, CSS, and JavaScript with long-lived cache headers.
- **GET responses with idempotent semantics:** read-only API data that does not change with the requester.
- **Pages you can tolerate being a few seconds old:** dashboards, feeds, and pricing pages rather than cart contents or per-user state.
Anything tied to a logged-in user, a session cookie, or a side effect should stay out of the proxy cache. The cache key must reflect what changes the output: URL plus relevant query string at minimum.
The headers that make caching work
The proxy only caches when the origin says it is allowed to. The two headers that matter are Cache-Control on the response and the max-age value within it.
- **Cache-Control: public, max-age=300** lets any cache, including the proxy, reuse the response for five minutes.
- **Cache-Control: private** tells every cache to keep the response out — sessions belong only to the requesting user.
- **ETag** lets the proxy revalidate cheaply: a 304 response confirms the cached copy is still fresh without downloading the body again.
Get these right and the proxy becomes a participant in your caching hierarchy instead of a dumb relay.
Nginx cache with stale-while-revalidate
The cache is defined at the http level with a path, a key scheme, and sizes; a location then opts into using it.
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=zone_web:10m max_size=1g inactive=60m;
server {
listen 80;
server_name docs.example.com;
location /assets/ {
proxy_pass http://127.0.0.1:8080;
proxy_cache zone_web;
proxy_cache_valid 200 10m;
proxy_cache_revalidate on;
add_header X-Cache-Status $upstream_cache_status;
}
}proxy_cache_valid says which status codes to cache and for how long. proxy_cache_revalidate turns a fresh ENTRY into a cheap 304 handshake with the origin instead of a full refetch, which is the "revalidate" half. The X-Cache-Status header exposes HIT, MISS, and EXPIRED states so you can watch the cache work.
Serving stale instead of failing
Stale-while-revalidate is the safety net: when a cached entry expires and the upstream is slow or down, the proxy can serve the old copy immediately and refresh it in the background.
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
server {
listen 80;
server_name feed.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_cache zone_web;
proxy_cache_valid 200 1m;
proxy_cache_use_stale error timeout due_to_error http_500;
}
}Now an upstream crash does not convert into a 502 for your users — they get the last good copy, updated when the origin recovers. The trade-off is freshness, which is why stale serving belongs on content pages and read models rather than on anything transactional.
Verify what is actually cached
curl -sI http://localhost/assets/app.css | grep -i cache
curl -sI http://localhost/assets/app.css | grep -i x-cacheRun the first request, then the second, and the X-Cache-Status line should move from MISS to HIT. If it stays MISS, the origin response probably lacks a cacheable Cache-Control header or carries Set-Cookie, either of which tells the proxy to stand aside.
Takeaway
Proxy caching turns repeat traffic into a near-instant response and, with stale-while-revalidate, makes transient upstream failures invisible. The discipline is in the headers: cache what is idempotent, label the rest private, and pin a TTL you can live with. Anything a Netbay VPS can serve is a candidate — deploy Nginx with a proxy cache zone and watch the HIT ratio climb at netbayhosts.in.
Keep reading
Follow along on a real VPS
Deploy Linux in under 60 seconds
These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.
Deploy an instance