0

I have Nginx sitting in front of gunicorn, which in turn sits in front of a django application.

The core question is "Why are my responses not being cached?" However, I'm pretty green at this, so here are my assumptions on what should happen (in case my core understanding is flawed).

Request A hits Nginx asking for, say, some json from a REST service. Nginx doesn't have this in its cache, so it passes it onto Gunicorn/Django. A response is generated, passed back through Nginx, where it is cached, and finally back out to the client.

Then!

Request B comes in asking for the same resource. Nginx has it in its cache and thus serves it directly, never hitting the django application.

Based on that assumption, and after much reading I ended up with this minimal nginx configuration in my sites-enabled:

proxy_cache_path /tmp/nginx keys_zone=one:20m inactive=60m;
proxy_cache_key "$host$request_uri";


server {
    listen 8080;
    server_name localhost;

    proxy_cache one;

    location / {
        add_header X-Proxy-Cache $upstream_cache_status;
        proxy_ignore_headers X-Accel-Expires Expires Cache-Control;
        proxy_pass http://127.0.0.1:8000;
    }
}

This code is based on the docs for nginx caching, and the tutorial here.

If I test a few requests, I get this response:

curl -X GET -I http://localhost:8080

HTTP/1.1 200 OK
Server: nginx/1.4.6 (Ubuntu)
Date: Wed, 06 May 2015 01:35:38 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Cookie
X-Frame-Options: SAMEORIGIN
Set-Cookie: csrftoken=b6UG5X4ZlGwVUYfHSIkq4PKBIxicpWxc; expires=Wed, 04-May-2016 01:35:38 GMT; Max-Age=31449600; Path=/
X-Proxy-Cache: MISS

Note: I think the cookie is fine since I don't include it in the cache_key directive. I could be wrong though.

Despite numerous request for the same resource, I never get a cache hit. Further, no cache files are written in the proxy_cache_path directory.

Could someone point me towards why no responses are being cached?

Thanks!

2

Trying to cache an entity which holds a Set-Cookie header is quite a bad idea. This is natively forbidden by nginx unless told with the proxy_ignore_headers directive.

This header ignored plus the Vary: Cookie header in replies would make your cache quite ineffective since a sole resource will have as many cache entries as the amount of visitors asking for it.

Also note that the Vary header is taken into account in the caching algorithm since version 1.7.7 only. Using a previous nginx version with proxy_ignore_headers Set-Cookie; would result in massive cookie duplication as the Set-Cookie header from the cached reply would be sent back to all requests hitting the cache entry.

1

It looks to me like the issue is that the upstream server is just not sending response that contain an expiration date (Expires:) or a cache validator (for instance, Last-Modified:). (The cookie expiration time has nothing to do with caching.)

The HTTP 1.1 spec says:

If there is neither a cache validator nor an explicit expiration time associated with a response, we do not expect it to be cached, but certain caches MAY violate this expectation (for example, when little or no network connectivity is available).

(Emphasis added.)

So it looks like your Django setup does not have caching turned on. I suggest you turn on per-site caching. If you do this, Django will generate in its response the headers that Nginx needs for caching.

Another option would be to use the proxy_cache_valid option in your Nginx configuration. I used a setup similar to yours and replicated the behavior you got, then I added proxy_cache_valid any 5m; which tells Nginx to cache responses that have any status code (any) for 5 minutes 5m. Once, I did that, I got cache hits.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.