Enabling nginx cache system is simple, just follow the official tutorial step by step, and you're ready to go. Or is it?

Here is a typical nginx conf file configured as a reverse proxy with cache enabled:

http {
    proxy_cache_path  /data/nginx/cache  levels=1:2    keys_zone=STATIC:10m
    inactive=24h  max_size=1g  use_temp_path=off;
    server {
        location / {
            proxy_pass             http://1.2.3.4;
            proxy_set_header       Host $host;
            proxy_cache            STATIC;
            proxy_cache_valid      200  1d;
            proxy_cache_lock on;
            proxy_cache_background_update on;
            proxy_cache_use_stale  error timeout invalid_header updating
                                   http_500 http_502 http_503 http_504;
        }
    }
}

This configures nginx to forward requests to the upstream server at http://1.2.3.4 and cache it as files in /data/nginx/cache with a maximum size of 1GB, inactive time of 24hours and in memory key cache up to 10MB, and it indeed works.

However, if you copy these to your exist confs, and you'll probably find out that your cache folder is always empty. That's because there are 2 exceptions that under which the caching system won't work:

  1. Upstream server's response contains the header "Set-Cookies"
  2. proxy_buffering sets to off.

Also, here are two more tips to let your nginx handles the cache request more appropriately:

  • add directive
add_header X-Proxy-Cache $upstream_cache_status;

This will add an extra header to your response to give you an explicit vision of what your cache state is.

  • add directive
proxy_cache_bypass $http_cache_control;

This will make nginx ignore/bypass its cache when browsers/clients request resources with a no-cache header (this happens to every main page in Chrome browser).

  • add directive:

    proxy_cache_purge PURGE purge_all from all;
    proxy_pass {your upstream server here};

This will purge the entire cache if your visit the specific URL by a special PURGE request via

curl -X PURGE yoururlhere

You can also purge only one page at a time by removing the purge_all option as well.

Notice:

  1. proxy_cache_purge is not available for nginx free version, you need to add THIS MODULE to make it work.
  2. the proxy_pass below/above the purge directive is a necessity. The purge module needs it to identify the correct cache, or it'll return 405 Not Allow instead.
  3. On a successful purge, you'll receive a page saying successful purge.
  4. The original free purge module is not under development anymore. Please use my forked version instead which has got all the necessary commits merged.

Here is the final version:

http {
    proxy_cache_path  /data/nginx/cache  levels=1:2    keys_zone=STATIC:10m
    inactive=24h  max_size=1g  use_temp_path=off;
    server {
        location / {
            proxy_pass             http://1.2.3.4;
            proxy_buffering            on;
            proxy_set_header       Host $host;
            proxy_cache            STATIC;
            proxy_cache_valid      200  1d;
            proxy_cache_lock on;
            proxy_cache_background_update on;
            proxy_cache_use_stale  error timeout invalid_header updating
                                   http_500 http_502 http_503 http_504;
            proxy_cache_bypass $http_cache_control;
            add_header X-Proxy-Cache $upstream_cache_status;
            proxy_cache_purge PURGE from 127.0.0.1;    #purge this page only
        }
        location /purge {    #any url you like.
            proxy_cache_purge PURGE purge_all from all;
            proxy_pass http://1.2.3.4;    #it's a must
        }
    }
}

Thank you for Justin for figuring out the proxy_buffering part as it's still not officially documented.