Nginx by examples: caching
Nginx offers out of the box very efficient caching support where
- the cache index is stored in a memory mapped files
- all cache files reside on the filesystem.
As usual the setup is fairly trivial:
server {
proxy_cache_path /tmp/nginx-cache levels=1:2
keys_zone=api_cache:10m max_size=10g inactive=60m;
...
location /api {
proxy_cache api_cache;
# we allow only 1 req per URI to hit origin
# in case of a cache miss
proxy_cache_lock on;
# we add the X-Proxy-Cache header to our response to the client
add_header X-Proxy-Cache $upstream_cache_status;
...
proxy_pass http://127.0.0.1:8080;
}
}
In this example
- we setup one
proxy_cache
location calledapi_cache
- with key size: 10mb and cache size 1gb
- in the
/tmp/cache
folder with a 2 level directory hierarchy - where cached data is purged every 60min regardless of freshness.
- using the same location for the memory mapped cache file and the storage area
By default Nginx will respect the cache headers are returned by the downstream server and the preferred way to manage the caching of replies is to set a Cache-Control
header in the reply
Force cache
In some cases we can’t modify our downstream servers to serve appropriate Cache-Control
headers
In these circumstances we can force some generic caching policies as follows
location /api {
proxy_cache api_cache;
# we ask Nginx to ignore the Cache-Control header
proxy_ignore_headers Cache-Control;
# we cache any 200 or 302 response for up to 10 minutes
proxy_cache_valid 200 302 10m;
# any 404 response is cached for 1 minute
proxy_cache_valid 404 1m;
...
proxy_pass http://127.0.0.1:8080;
}
Notes
-
By default only
GET
andHEAD
requests are cached but this behaviour can be tweaked -
The cache key and the cache filenames are calculated using the following formula:
md5($scheme$proxy_host$request_uri)
.
Cookies and cache
For obvious reasons by default Nginx will not cache requests where the Set-Cookie
header is set.
Unfortunately many server side technologies (PHP, Java etc) create a cookie based session with each request by default thus preventing Nginx from caching pretty much any request even if the Cache-Control
header is set
In these circumstances it’s useful to setup a different cache punching header to send with not cacheable responses
# we ignore the Set-Cookie header
proxy_ignore_headers Set-Cookie;
# we hit origin every time a X-No-Cache custom header is set
proxy_no_cache $http_x_no_cache
Invalidating the cache
The opensource version of Nginx doesn’t come out of the box with many ways to invalidate the cache except proxy_cache_bypass
# Trigger a synchronous cache update
# when a specific `X-No-Cache` header
# or if a `nocache` GET parameter are set
proxy_cache_bypass $http_x_no_cache $arg_nocache;
Unfortunately proxy_cache_bypass
does not update the internal cache reference if a 404 response code is returned
We have a few options
- Use a Nginx version with the
ngx_cache_purge
module bundled in - Use a script to delete the file corresponding to a specific URI from the filesystem cache location
- Use OpenResty to delete the cache file via HTTP request (
os.remove (filename)
)