Nginx caching with django

For a small django site I run, I'd like to add nginx caching in front of my django server. Here's the setup I ended up with.

The pages I want to cache are available for both anonymous and logged in users. The majority of traffic is from anonymous users and since they all get the same contents I'd like to serve it from the cache. Contents for logged in users should never be cached.

Because we show different content to logged in users, and therefore check e.g. request.user.is_authenticated, the SessionMiddleware correctly sets a Vary: cookie header.

As an extra spanner in the works, we use google analytics which adds its own cookies. These aren't used by the django server but means that even anonymous visitors submit cookies with their request.

By default, nginx respects the vary header and adds the cookies to the cache key, effectively giving everyone their own cache entry which is useless.

The fix is to ignore the Vary header, and instead bypass the cache for anyone with a sessionid cookie.

The nginx blog had a nice guide on how to configure caching where i got most of the settings from, though it unhelpfully doesn't mention the need for a proxy_cache_valid entry.

Final nginx config:

proxy_cache_path /tmp/nginx-cache levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m use_temp_path=off;

server {
    ...
    proxy_cache my_cache;
    proxy_cache_valid 200 10m;
    # ignore "Vary: cookie" from django and instead use
    # cache_bypass for the sessionid cookie
    proxy_ignore_headers Vary;
    proxy_cache_bypass $cookie_sessionid;
    # add a custom header with cache status, for debugging
    add_header X-Cache-Status $upstream_cache_status;
}

Result:

$ curl -s -i  -b _utm=foo https://site | head
HTTP/1.1 200 OK
...
X-Cache-Status: HIT

$ curl -s -i  -b sessionid=bar https://site | head
HTTP/1.1 200 OK
...
X-Cache-Status: BYPASS

Comments !