I have a REST API behind an nginx proxy. Proxying works fine, however I am unable to cache any responses. Any help would be much appreciated:

Nginx config:

worker_processes  10;
error_log  logs/error.log;
error_log  logs/error.log  notice;
error_log  logs/error.log  info;

pid        logs/nginx.pid;

events {
    worker_connections  1024;

http {
        proxy_cache_path /path/to/cache/dir keys_zone=one:60m;
        proxy_cache_methods GET HEAD POST;

     upstream backend {
        server server1 backup;
        server server2 weight=5;
    access_log  logs/access.log;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       7076;
        server_name  localhost;
        #charset koi8-r;
        access_log  logs/host.access.log;

        location / {
            add_header 'Access-Control-Allow-Origin' *;
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Headers' 'Content-Type,Accept';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';

            proxy_cache one;
            proxy_cache_key $host$uri$is_args$args;

            add_header X-Proxy-Cache $upstream_cache_status;

            proxy_ignore_headers X-Accel-Expires Expires Cache-Control Set-Cookie;
            proxy_ignore_headers Set-Cookie;
            proxy_ignore_headers Cache-Control;

            proxy_hide_header Cache-Control;
            proxy_hide_header Set-Cookie;
            proxy_pass http://backend;

No matter what I have tried, the Proxy-Cache always comes back as a MISS:

Request Headers are:

User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36

Reponse Headers are:

Access-Control-Allow-Methods:GET, POST, OPTIONS
Date:Wed, 15 Oct 2014 16:30:18 GMT

My suspicion is that it's something with the client headers, but even if I issue the call via curl and check out the headers, there is no response.

Thanks in advance

  • 1
    In the request header: Cache-Control:max-age=0 ...that implies "don't cache this request." – Nathan C Oct 15 '14 at 16:38
  • Is there a way for me to ignore that in the client header? This doesn't explain why it doesn't work through curl either though.... – user2630270 Oct 15 '14 at 16:50
  • @user2630270 What's the initial request URL & method ? What's the intermediate response ? – Xavier Lucas Oct 15 '14 at 16:57
  • @XavierLucas the methods for the headers above are GET since I am now troubleshooting the issue Chrome. The request is something along the lines of nginxserver:port/solr/asd/select?q=*:*. I don't know how to capture intermediate response. Where can I find instructions on this? – user2630270 Oct 15 '14 at 17:01
  • If I hit the application directly without going through nginx, with the exactly same query I get the following response headers: Content-Type: text/plain;charset=UTF-8 Transfer-Encoding: chunked – user2630270 Oct 15 '14 at 17:07

You didn't told nginx for how much time the response is valid and must be served from cache.

This must be specified with proxy_cache_valid directive.

proxy_cache one;
proxy_cache_key $host$uri$is_args$args;
proxy_cache_valid 200 10m;

But, this won't work for POST requests because you have no cache key that differs from a POST request to another on the same URL if they don't have same content.

So you will need to adjust the cache key to $host$request_uri|$request_body. You will have to monitor the cache size (proxy_cache_path parameter max_size) and proxy response buffer proxy_buffer_size so it suits your needs.

  • Nice, Thanks man! It worked. Wish it was documented somewhere a bit more explicitly. – user2630270 Oct 15 '14 at 17:39
  • Thanks a ton!! I was ready to pull my hairs out, until I came across this. – Adarsha Mar 24 '16 at 9:40
  • If this directive is not set then any response will be cached. But the one is overriden by the header X-Accel-Expire, Cache-Control or Expire of the app. At least, Set-Cookie and Vary could avoid the cache. These facts are exposed in the doc. I created a simple script to test because my framework, Laravel, always send the above headers. – Victor Aguilar Mar 22 '17 at 15:11

From: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_valid

Syntax: proxy_cache_valid [code ...] time;


Parameters of caching can also be set directly in the response header. This has higher priority than setting of caching time using the directive.

  • The “X-Accel-Expires” header field sets caching time of a response in seconds. The zero value disables caching for a response. If the value starts with the @ prefix, it sets an absolute time in seconds since Epoch, up to which the response may be cached.
  • If the header does not include the “X-Accel-Expires” field, parameters of caching may be set in the header fields “Expires” or
  • If the header includes the “Set-Cookie” field, such a response will not be cached.
  • If the header includes the “Vary” field with the special value “*”, such a response will not be cached (1.7.7). If the header includes
    the “Vary” field with another value, such a response will be cached
    taking into account the corresponding request header fields (1.7.7).

Processing of one or more of these response header fields can be disabled using the proxy_ignore_headers directive.

Most web apps set Set-Cookie header, so a response will not be cached. To fix that, use this directive:

proxy_ignore_headers Set-Cookie;

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.