> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Caching

> Explains HTTP caching with NGINX as a reverse proxy, configuration directives, TTLs, cache keys, bypass rules and verification tips

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.](https://mintcdn.com/kodekloud-c4ac6d9a/ij3FNIPjp1w0Myd0/images/Nginx-for-Beginners/Performance/Caching/caching-explained-server-media-files.jpg?fit=max\&auto=format\&n=ij3FNIPjp1w0Myd0\&q=85\&s=2951ccbd83c7d22586eb76284e723727)

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.](https://mintcdn.com/kodekloud-c4ac6d9a/ij3FNIPjp1w0Myd0/images/Nginx-for-Beginners/Performance/Caching/cached-page-server-fast-loading.jpg?fit=max\&auto=format\&n=ij3FNIPjp1w0Myd0\&q=85\&s=bd347253e9e4e9ce74fa54bb5e3eb21e)

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:

```nginx theme={null}
http {
    proxy_cache_path /var/lib/nginx/cache levels=1:2 keys_zone=app_cache:8m max_size=50m;
    proxy_cache_key "$scheme$request_method$host$request_uri";
    proxy_cache_valid 200 301 10m;
    proxy_cache_valid 404 1m;
}

server {
    listen 80;
    server_name example.com www.example.com;

    location / {
        proxy_cache app_cache;
        add_header X-Proxy-Cache $upstream_cache_status;

        proxy_pass http://backend/;
    }
}
```

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:

| Option | Purpose | Example / Notes |
| - | - | - |
| `path` | Filesystem directory where cache files are stored | `/var/lib/nginx/cache` — must be writable by NGINX |
| `levels` | Subdirectory layout to avoid too many files in one folder | `levels=1:2` produces a/b/ subfolders (improves disk I/O) |
| `keys_zone` | Name and size of the shared memory zone for keys/metadata | `keys_zone=app_cache:8m` (shared across worker processes) |
| `max_size` | On-disk quota for the cache; evicts older items when exceeded | `max_size=50m` (use `m` or `g`) |
| `inactive` (optional) | Time after which unused items are removed | `inactive=1d` |

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:

```nginx theme={null}
proxy_cache_key "$scheme$request_method$host$request_uri";
```

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.](https://mintcdn.com/kodekloud-c4ac6d9a/ij3FNIPjp1w0Myd0/images/Nginx-for-Beginners/Performance/Caching/nginx-proxy-cache-key-assets.jpg?fit=max\&auto=format\&n=ij3FNIPjp1w0Myd0\&q=85\&s=e5b4a806d931547b9ca64685ecfc1804)

## 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:

```nginx theme={null}
proxy_cache_valid 200 301 10m;
proxy_cache_valid 404 1m;
```

* 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:

```nginx theme={null}
location / {
    proxy_cache app_cache;
    add_header X-Proxy-Cache $upstream_cache_status;
    proxy_pass http://backend/;
}
```

Common `$upstream_cache_status` values:

| Value | Meaning |
| - | - |
| `HIT` | Served from cache |
| `MISS` | No cache entry; fetched from backend |
| `BYPASS` | Cache intentionally bypassed for this request |
| `EXPIRED` | Cached entry expired; backend was contacted |
| `STALE` | Serving stale response due to backend error |

## 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):

```nginx theme={null}
server {
    listen 80;
    server_name example.com www.example.com;

    location / {
        proxy_cache app_cache;
        proxy_cache_bypass $http_cache_control;

        add_header X-Proxy-Cache $upstream_cache_status;
        proxy_pass http://backend/;
    }
}
```

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."](https://mintcdn.com/kodekloud-c4ac6d9a/ij3FNIPjp1w0Myd0/images/Nginx-for-Beginners/Performance/Caching/confirmation-browser-network-tab-cache-flow.jpg?fit=max\&auto=format\&n=ij3FNIPjp1w0Myd0\&q=85\&s=5805d5660b5236c21538855036ca2d0b)

Example response headers when caching is active:

```text theme={null}
Response Headers
Accept-Ranges: bytes
Age: 10
Cache-Control: s-maxage=60
Content-Encoding: gzip
Content-Length: 103408
Content-Type: text/html; charset=iso-8859-15
Date: Fri, 24 Jan 2025 17:25:21 GMT
Referrer-Policy: unsafe-url
Vary: Accept-Encoding, User-Agent
X-Backend: CONTENT
X-Proxy-Cache: HIT
X-Cache-Hits: 1
X-Served-By: cache-ams21071-AMS
X-Timer: S1737739521.335220,VS0,VE2
```

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.

## Links and references

* [NGINX Caching Guide](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache)
* [NGINX proxy\_cache\_path docs](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_path)
* [Caching best practices (HTTP caching)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching)

> **[Watch Video](https://learn.kodekloud.com/user/courses/nginx-for-beginners/module/4a5db5c4-df5f-4291-84f0-013d1c4ce235/lesson/08d27eea-6435-4900-972f-8ace51a21922)**


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.