nginx, query strings, and “Vary Accept Encoding” – the fix

Just spent a while diagnosing this issue on a testbed, so hopefully this helps someone else.

Here was the situation:

  • Running nginx
  • Using WordPress with W3TC which tends to add that query string with a version number to each CSS and JS file.
  • GTMetrix and were both telling me to Specify a Vary: Accept-Encoding header.


So I had this:



…And needed to get this:



A little researched showed that the gzip part of nginx is what sets this – “gzip_vary”. The first problem was determining what the query string should look like in “nginx terms”. This was my first time really dabbling in something other than Apache, so it took me quite awhile to figure out. In any case, something like this is what you need:

location ~ \.(?:css|htc|js|js2|js3|js4)$ {
     gzip_vary on;

That goes within your server block. The key part is the ?: in the \.(?:css|…… section. Coming from Apache, I’d always managed to muddle things onto the *end*, but in this case the question mark seemingly has to come before the css/js/etc.

Worth noting that I’d actually pulled the location line from the .conf file that W3TC spits out – adding the ?: to the front was the only modification necessary if you decide to go that route.

A couple other important things to mention:

  • If you reference that “location” elsewhere in your nginx config, make sure you add gzip_vary on to the existing block. If you have 2 location blocks pointing to the same place, it tends to only use the 1st one specified. That means if you’re using W3TC and are using an include for the .conf file it generated, your best bet might be to mod the nginx.conf that it generated, rather than creating a new location block elsewhere.
  • The nginx docs for gzip_vary state that the header causes IE4-6 not to cache the content due to a bug. That said, most anything running IE4-6 is probably a zombie participating in a botnet, and even the few “real” IE visitors are going to be used to a broken web, so I wouldn’t worry too much about it (that their browser doesn’t cache a CSS/JS file will be the least of their concerns).

Anyway, hopefully that aids someone trying to solve the same issue. If it works for you (or doesn’t), feel free to leave a comment! And if there are any nginx wizards out there that know of a smarter/better way to go about it, feel free to share!