NGINX : Cache when X-Accel-Expires is set

cachenginxPROXY

I have added a X-Accel-Expires header on my static contents as well as a Last-Modified header.
I would like to know whats the correct setting to cache those elements without caching anything else.

This is what I have at the moment but it doesn't cache anything :

http {
include       /etc/nginx/mime.types;

access_log  /var/log/nginx/access.log;

sendfile        on;
client_max_body_size 2000m; 
keepalive_timeout  65;
tcp_nodelay        on;

gzip  on;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;

ssl_certificate /etc/nginx/chain.pem; 
ssl_certificate_key /etc/nginx/key.key;

proxy_cache_path /var/lib/nginx/cache levels=1:2 keys_zone=cache:30m max_size=1G;
proxy_temp_path /var/lib/nginx/proxy 1 2;
proxy_cache_use_stale error timeout invalid_header http_502;

server {
    listen       80;
    server_name domain;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header  X-Real-IP  $remote_addr;
        proxy_read_timeout 700;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Best Answer

To cache stuff, first you need to create a proxy cache path within the http context, like this:

proxy_cache_path    /var/cache/nginx/site1    levels=1:2    keys_zone=site1:10m max_size=1G;

Then you can also optionally define the proxy cache key. Any request that has the same cache key as a cached entry, will receive the cached reply, if there is one. But default may already be good enough, so, that's entirely optional.

Then to enable the cache in a given context, just mention which cache should be used, like this:

proxy_cache    site1;

According to the description of the proxy cache valid directive, nginx already respects X-Accel-Expires and acts on it, so, you're basically done at this point. Since you don't want to cache anything that doesn't include X-Accel-Expires, then you probably want to add a value of 0 as the default valid time (setting X-Accel-Expires within your content should overwrite this default value).

proxy_cache_valid    0m;

I shall presume that other than for the lack of any caching, your config file is otherwise valid, and your proxying itself already works.

Then, basically, all you need to do to fix your config is add the following to your http, server or location context:

proxy_cache    cache;
proxy_cache_valid    0m;

(Also, you might want to ensure that the cache path exists and has correct permissions, of course.)


Regarding the mentioned habrahabr article/example, I don't think it's actually correct to be including $http_if_modified_since in the cache key, because you can potentially end up with a lot of multi-cached entries, effectively wasting your cache.


Also note that nginx likely doesn't proxy X-Accel-Expires header -- it only uses it internally, and IIRC may not serve this header forward. To alter such behaviour, you have to explicitly ask for it to be proxied, too (in case you want to debug your content through nginx, and see how your app sets the header etc):

proxy_pass_header "X-Accel-Expires";