I was recently using Nginx to serve some static files as configuration payloads. Since Nginx has supported ETags by default since version 1.3.3, it is convenient to let browsers fetch a new file automatically when the configuration changes.
But after deploying to a test environment, I ran into a problem. There were two Nginx nodes behind a load balancer, and the same static file returned different ETags depending on which node handled the request. As a result, the browser kept receiving 200 responses instead of 304, so caching was effectively broken.
After looking into how Nginx calculates ETags, I found that Nginx uses the file size and the file modification time. The ngx_http_set_etag function in the Nginx source contains code like this:
1 | etag->value.len = ngx_sprintf(etag->value.data, "\"%xT-%xO\"", |
Full source reference:
That makes it pretty clear: if two Nginx nodes return different ETags, the file modification time is probably different on each node.
Fortunately, changing file modification times is easy. You can use touch. The -t option is documented like this:
-t STAMP
use[[CC]YY]MMDDhhmm[.ss]instead of current time
So on both nodes, the following command sets the file timestamp to 2022-02-25 13:13:
1 | touch -t 202202251313 myconf.json |
If you want to do the same thing in Python, you can use os.utime:
1 | import os |
After doing that, both Nginx nodes returned the same ETag, and the second request correctly came back as 304 instead of 200.
Reference: