I have an issue where Chrome browsers do not reload updated javascripts.

This is because, in Chrome, the request is never sent to the server.

The other browsers I support (Firefox, Edge, Safari) work fine; this appears to be because they send an If-Modified-Since header.

The file is served as part of a collection of static assets. Everything is gzipped by nginx.


root /var/www;
index index.php index.html index.htm;
// some php stuff ...

A (maybe?) relevant line from /etc/nginx.conf

# Proxy cache
proxy_cache_path /var/tmp/nginxcache keys_zone=one:10m;

Curl output for a get on the javascript:

< HTTP/1.1 200 OK
* Server nginx/1.4.6 (Ubuntu) is not blacklisted
< Server: nginx/1.4.6 (Ubuntu)
< Date: Sun, 05 Aug 2018 11:52:44 GMT
< Content-Type: application/x-javascript
< Content-Length: 2350005
< Last-Modified: Sun, 05 Aug 2018 11:38:36 GMT
< Connection: keep-alive
< Vary: Accept-Encoding
< ETag: "5b66e1bc-23dbb5"
< Accept-Ranges: bytes

Is there a configuration in nginx that can persuade Chrome to do likewise? I have explored these answers: Setting expires headers for static content served from nginx and https://stackoverflow.com/questions/17251503/set-expires-to-max-for-all-images-of-all-servers-in-nginx/17253805#17253805 but my regex skills are rather poor, and the answers are quite old. Should I try:

location ~ \.js {
    expires 1d;
    add-header Pragma public
    add-header Cache-control "public"
  • 1
    This is a harder problem than it seems. Look up "cache busting" and read the first 50-100 results. – Michael Hampton Aug 5 '18 at 12:48
  • Yes, this is what I've now done (I think!) - a build process that names the relevant javascript based on a hash, that I then have to update in index.html. . Thanks for the tip. I wanted to double-check - index.html never gets cached, right? – minisaurus Aug 6 '18 at 13:15
  • That depends on what you have configured in nginx, whether you use https, etc. For index.html in a single page app I suggest setting a relatively short max-age. But that's a tradeoff between reducing load to the server and being able to deploy changes quickly. – Michael Hampton Aug 6 '18 at 13:17
  • Ok, thanks Michael - it is https, and also a PWA. Think I've sorted it - I added a location blah { expires 1d; } and am now getting Cache-Control: max-age=86400 with curl. I'll increase this when the app has "stabilised", ha-ha. So, just to try and understand better, if one doesn't configure anything, does nginx cache indefinitely by default? – minisaurus Aug 6 '18 at 14:31
  • If you don't send a Cache-Control header, the default is determined by the caching entity, e.g. the browser. For HTTP the default is public, and for HTTPS the default is no-cache. So you should always set a Cache-Control header. – Michael Hampton Aug 6 '18 at 14:33

Thanks to help from @Michael Hampton, I added this location block to the server:

    location ~* \.(:manifest|html?|json)$ {
        expires 1d;

So my index.html expires after one day.

I also started building the app with gulp and gulp-rev to get a version hash on the app name, such as app-xyzz56464.js, which then sits in index.html.

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.