Using tengine (an awesome fork of Nginx, check it out), I found that it would cache HEAD requests even when I thought I explicitly told it not to.
Here’s the long story short.
What I expected to work
In the http section of /etc/nginx/nginx.conf
:
proxy_cache_min_uses 3;
proxy_cache_methods GET;
proxy_cache_valid 200 10m;
proxy_cache_valid 403 404 1m;
proxy_cache_path /var/cache/nginx/website/ levels=1:2 keys_zone=website:16m
loader_threshold=300 loader_files=200
max_size=20g;
Reading the above, I would expect nginx to only cache GET requests, as per configured through proxy_cache_methods after the third hit.
However, I would still get cache hits after the third HEAD request as well.
Confirming I’m not crazy
I confirmed the issue by adding a custom header in my vhost, /etc/nginx/sites-enabled/website
:
location / {
proxy_cache website;
proxy_pass http://website;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Custom header to show whether we're hitting cache or not
add_header X-Proxy-Cache $upstream_cache_status;
}
What do you know, after the third HEAD request, I’d get a X-Proxy-Cache: HIT
back from the webserver.
“Syntax sugar”
Now, looking closely at the documentation for proxy_cache_methods, you see the following:
If the client request method is listed in this directive then the response will be cached. “GET” and “HEAD” methods are always added to the list, though it is recommended to specify them explicitly. See also the proxy_no_cache directive.
No way. You tell it to cache only GET requests and it’ll add HEAD back in there ? This was further confirmed in an older mailing list e-mail from a nginx developer:
GET/HEAD is syntax sugar, i.e. you can not disable GET/HEAD even if you set just proxy_cache_methods POST;
The solution
If you find a better way, do tell me because otherwise this is what I ended up with. It works, though !
location / {
proxy_cache website;
# I TOLD YOU NOT TO CACHE HEAD REQUESTS !@#$%
if ($request_method = HEAD ) {
set $nocache 1;
}
proxy_pass http://website;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Custom header to show whether we're hitting cache or not
add_header X-Proxy-Cache $upstream_cache_status;
}
Share this post