Server Fault is a question and answer site for system and network administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have a requirement where I need to support downgrading of my server code.

I have the following line in my nginx configuration file, indicating that the browser can cache the page but has to validate with server to check if the file changed.

add_header Cache-Control "no-cache";

This setup works perfectly fine for me with all the upgrades done on my server code.

But when it comes to downgrading a resource to an older version, when the browser tries to validate the resource change, nginx says that the resource hasn't changed, so the browser shows the cached(newer) resource instead of the downgraded(older) resource.

As a workaround, I could use the following setting to disable cache completely, but its not efficient, and I would like to have caching.

add_header Cache-Control "no-store";

So how would I make nginx recognize downgrades??

share|improve this question
Just to add mode retails. With "no-cache" setting, when a resource is upgraded, browser gets 200 OK status and when a resource is downgraded, browser get 304 NOT MODIFIED status. – Schu Jan 7 '12 at 21:08
I believe nginx uses timestamps to determine modification - try to 'touch' the file - update the timestamp - and see if it fixes your issue. (I haven't quite managed to figure out your scenario - but I am presuming you have older static files, you upgrade them (keeping the old files), and then at some point change your links to point back to the older files). Add some detail to your question describing whether these are static or dyanmic files, a sample url (do you use query strings), and something about this 'downgrade' process. (Also see if you have any luck with adding 'must-revalidate'). – cyberx86 Jan 8 '12 at 2:52
By upgrade I mean, replace the server code(includes static resources) with newer version from source control, By downgrade I mean the opposite, replace the code with older version from source control. At any point of time, there is only one set of files on the server. No I dont have any query strings. All references are from html files to javascript files using script tags. – Schu Jan 9 '12 at 4:05
I use dpkg for upgrade/downgrade process and it also probably uses timestamps to detect code change. I fear 'touch'ing the file would mess it up. I will try it though. – Schu Jan 9 '12 at 4:09
I tried must-revalidate, it behaves identical to no-cache, so it doesn't work. I tried touching the files and it work fine, i still have to verify its impact on dpkg though. – Schu Jan 9 '12 at 14:44
up vote 1 down vote accepted

In a no-cache scenario, the browser will usually issue an If-Modified-Since header with a GET request, to see if the file in question has changed from the cached copy.

The server will either:

  1. return a 304 - Not Modified response
  2. return another code:
    • 200 - OK if the modified date on the server is later than that passed with the header
    • Other - any other code that might be returned (4xx, 5xx, etc)

Nginx will use the modified timestamp on the file it is serving to generate the Last Modified header and for comparison against If-Modified-Since.

Due to this, updating the timestamp of a file with touch /path/to/myfile.ext will cause nginx to identify it as having been modified after the If-Modified-Since date and will allow nginx to serve the file.

Alternatively, you should be able to force a re-fetch by explicitly specifying a 'Last Modified' header in your nginx config that is after the anticipated date of If-Modified-Since. In your scenario, this would essentially entail:

  1. Downgrade your code
  2. Modify nginx config with current date (e.g.): add_header Last-Modified Mon, 09 Jan 2012 17:07:00 GMT
  3. Reload nginx

An important point of mention is that if your static assets change after this, the hard-coded header will not reflect the change (i.e. even when you 'upgrade' your code, you will still have to manually alter the config.

share|improve this answer
Actually in the scenario of static file being updated after the Last-Modified being set on the config file, the server issues a 200-OK, given we also have the no-cache setting. This means that even if one of Cache-Control or Last-Modified says the file is modified, the final server response would be 200 OK. – Schu Jan 9 '12 at 17:41
@Schu: Interesting, no-cache only requires that the browser revalidate all requests with the origin server. I would expect that if Last-Modified can override an 'older' timestamp, that it should also do the same for a newer one (and therefore return 304). I think there is something additional going on - as I usually would not expect setting a response header to alter the way a request header is processed. – cyberx86 Jan 9 '12 at 17:53
I was thinking of it as "override" as well, but its the server response that led me to the conclusion of "either-or". Assuming older version is in cache, i get the following responses 1. just no-cache - 200 ;2. just last-modified - 304; 3. both no-cache and last-modified - 200 – Schu Jan 9 '12 at 20:27

First of all, "no-cache" doesn't necessarily mean what you think it means in practice. I suspect you really want to use "Cache-Control: max-age=0, must-revalidate". Some browsers (Firefox) incorrectly treat "no-cache" as an equivalent of "no-store", and don't cache anything on disk at all. They simply re-fetch all content from the source at every page load, which is a terrible waste of bandwidth and sucks for the user experience.

Secondly, your particular use case is exactly what ETags were designed for, rather than the simple forward-only date logic that is used without them. (The entire linked site is great reading on caching, not just on e-tags).

Finally, you should consider naming your resources with some form of date identifier (or better yet content hash) so that you never have to worry about this sort of thing. You can then set cache-control to 1 year. This requires workflow changes and build scripts though for many sites to rename files and replace links. But that is what Google and the other big boys do...

share|improve this answer
Thanks for site link. There's lot of stuff there for me to know. I was testing on chrome and its doing it right ie., can cache but re-validate. But you are right, I have to avoid no-cache for efficiency on browsers with no-store interpretation. Coming to Etags, unfortunately the nginx I use doesn't generate them, so all I can do is put a static ETag which in essence would be equal to a LastModified setting. – Schu Jan 11 '12 at 22:11

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.