Skip to main content
Picture going to a coffee shop every morning to get the exact same order — medium coffee, hot chocolate, whatever you like. The first time, the barista prepares it and it takes a bit of time. After a few visits, the barista remembers your order and has it ready before you even ask.
  • Server = coffee shop counter
  • Data (images, HTML, CSS) = your coffee and cookie
  • User = you
Without caching, every request forces the server to fetch or compute the response again. Caching is like the barista preparing your usual order in advance: responses are stored so repeated requests are served immediately, saving time and reducing backend load. Caching stores frequently requested assets — images, video, stylesheets, HTML fragments, or entire pages — and serves them quickly from a nearby store instead of re-generating them.
A diagram titled "Caching Explained" showing a central server receiving and serving images, video, and document files represented by three blue icons. Arrows illustrate data flowing to the server, with a caption noting web servers store files for quick access.
When a user revisits the same site, the server can serve the cached version instead of rebuilding or re-fetching everything. That reduces latency and backend resource usage.
A simple illustration showing a user on a laptop visiting the same website and a server supplying a saved (cached) version of the page. The diagram highlights faster loading/time saving when stored content is served.
One of NGINX’s most common roles is as a caching reverse proxy. NGINX sits in front of backend servers, accepts client requests, and can cache responses so repeated requests are served quickly without hitting upstream services. A typical NGINX caching configuration uses the proxy_cache family of directives. Below is a consolidated example showing the common directives placed in the http block, followed by a matching server block that uses that cache:
Below are the key directives explained and practical tips for configuring them.

proxy_cache_path (disk store and cache zone)

proxy_cache_path creates the on-disk cache store and a shared memory zone for metadata. Common options:
To clear the cache: stop NGINX (or ensure no writes), remove or rename the cache directory, then restart NGINX. NGINX will recreate the cache. Always check file permissions so the NGINX worker can write to the cache path.

proxy_cache_key (how requests map to cached entries)

proxy_cache_key controls the cache key NGINX uses to match requests to cached responses. A typical key combines protocol, method, host, and request URI:
  • $scheme — http or https
  • $request_method — GET, POST, etc.
  • $host — Host header (e.g., www.example.com)
  • $request_uri — Path + query string (e.g., /images/img.png?size=large)
Example from above:
If a request produces a key that already exists in the cache, it’s a cache hit; otherwise it’s a miss and NGINX fetches the response from the backend and stores it.
A diagram showing a request hitting NGINX which uses a proxy_cache_key to look up and serve cached assets. The cache contains files like HTML, JS, CSS and GIFs stored on backend cache servers.

proxy_cache_valid (how long to keep cached responses)

proxy_cache_valid sets TTLs (time-to-live) per HTTP status code. You can specify multiple lines:
  • In this example, 200 and 301 responses are cached for 10 minutes.
  • 404 responses are cached for 1 minute (useful to avoid repeat hits for missing resources).

Enabling caching in server/location blocks

Inside a server or location block, enable caching with the proxy_cache directive. Use add_header to expose a debug header that shows cache status to clients:
Common $upstream_cache_status values:

proxy_cache_bypass (conditional bypass)

proxy_cache_bypass allows you to skip the cache based on variables (for example, when clients send cache-control headers):
Use proxy_cache_bypass sparingly. Overuse defeats caching and increases backend load.
Avoid enabling proxy_cache_bypass for static assets (images, CSS, JS). Overuse of bypass conditions can negate caching benefits and increase backend traffic.

How to confirm caching is working

  • Browser: open DevTools → Network tab → inspect a resource’s response headers for X-Proxy-Cache, X-Cache, Cache-Status, or Age.
  • Logs: include $upstream_cache_status in your access log to track hits vs misses.
  • Use curl to inspect headers:
    • curl -I https://example.com/path and look for X-Proxy-Cache or Age.
A simple flow diagram showing a browser window on the left and a dotted arrow chain to boxes labeled "Network Tab", "Resource", and "X-Cache or Cache Status" on the right. The title at the top reads "Confirmation."
Example response headers when caching is active:
The line X-Proxy-Cache: HIT indicates the response was served from NGINX’s cache rather than the backend.

Quick checklist for production caching

  • Choose a cache path with sufficient disk and correct permissions.
  • Allocate an appropriate keys_zone size for your traffic.
  • Use levels to prevent filesystem performance issues.
  • Set conservative proxy_cache_valid TTLs for dynamic content.
  • Expose debug headers only in non-sensitive environments or remember to remove/secure them later.
  • Monitor cache hit ratio via logs and metrics.
This concludes the caching overview. Next: step-by-step configuration and verification of caching in a live NGINX environment, including safe testing practices and access log examples.

Watch Video