How to set up Nginx as a caching reverse proxy?

Solution 1:

I don't think that there is a way to explicitly invalidate cached items, but here is an example of how to do the rest. Update: As mentioned by Piotr in another answer, there is a cache purge module that you can use. You can also force a refresh of a cached item using nginx's proxy_cache_bypass - see Cherian's answer for more information.

In this configuration, items that aren't cached will be retrieved from example.net and stored. The cached versions will be served up to future clients until they are no longer valid (60 minutes).

Your Cache-Control and Expires HTTP headers will be honored, so if you want to explicitly set an expiration date, you can do that by setting the correct headers in whatever you are proxying to.

There are lots of parameters that you can tune - see the nginx Proxy module documentation for more information about all of this including details on the meaning of the different settings/parameters: http://nginx.org/r/proxy_cache_path

http {
  proxy_cache_path  /var/www/cache levels=1:2 keys_zone=my-cache:8m max_size=1000m inactive=600m;
  proxy_temp_path /var/www/cache/tmp; 


  server {
    location / {
      proxy_pass http://example.net;
      proxy_cache my-cache;
      proxy_cache_valid  200 302  60m;
      proxy_cache_valid  404      1m;
    }
  }
}

Solution 2:

You can specifically invalidate cached pages through

proxy_cache_bypass       

Say you want to cache a page, set cache this way

location = /pageid {
  proxy_pass http://localhost:82;
  proxy_set_header   Host             $host;
  proxy_set_header   X-Real-IP        $remote_addr;
  proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
  proxy_ignore_headers Set-Cookie; 
  proxy_ignore_headers Cache-Control; 
  proxy_cache_bypass        $http_secret_header;
  add_header X-Cache-Status $upstream_cache_status;
}

Now, when you want to invalidate that page and cache again

Do a secret curl call with the header

curl "www.site.com/pageid" -s -I -H "secret_header:true" 

It will invalidate and cache it.

Works from nginx 0.7.

As an added bonus the add_header X-Cache-Status can be used to check if the page is from cache or not.


Solution 3:

I suggest you give Varnish a try. Varnish is specifically designed as a reverse proxy cache. It will honor all cache control headers you send from the origin server, which satisfies your first request.

For your second request, explicit invalidation. My strong recommendation is to change the name of the url of the resource you want to invalidate, either by renaming the file or using some form of query string cache buster. Varnish does have a PURGE operation that will remove the resource from Varnish's cache, but it will not give you control over any other caches between you and the user. As you've said you want to explicitly purge a resource, then standard http control headers won't help you. In that cases the most foolproof way to defeat the caching of a resource is to rename it.


Solution 4:

Most caching tools (Citrix) allow a force-refresh (Ctrl+r) to repopulate a cached page.

Here's a trick I found to do something similar in nginx.

server  {
        # Other settings
        proxy_pass_header       Set-Cookie; # I want to cache logged-in users
        proxy_ignore_headers    X-Accel-Redirect;
        proxy_ignore_headers    X-Accel-Expires Expires Cache-Control;
        if ($http_cache_control ~ "max-age=0") {set $eac 1;}
        proxy_cache_bypass $eac;
}

This assumes that when you do a Ctrl+r in your browser, the Cache-Control header has max-age=0 in its request. I know Chrome does this, but I have not tried in other browsers. Adding more header fields can be easy, by just adding more if statements that set the $eac variable to 1.


Solution 5:

For invalidating selected pages you can use "cache_purge" patch for nginx-0.8.x which does exacly what you want ;)

It's available here.