Varnish Cache and Cache-Control

Cache what cache can and not what it can't.

In our quest for speed, making websites faster relies on telling browsers when content is new and when it’s not, allowing them to only download the new stuff. At their heart, Cache Headers are what tell the browser how long to cache content. There’s a special header called Cache-Control which allows each resource to decide it’s own policy, such as who can cache the response, when, where, and for how long. By default, they time we set for the cache to expire is how old a visitor’s copy can be before it needs a refresh.

A lot of the time, I see people setting Cache-Control to none and wondering why their site is slow.

Since I spend a lot of time working on DreamPress, which uses Varnish, I do a lot of diagnostics on people with slow sites. One of my internal scripts checks for Cache-Control so I can explain to people that setting it to none will tell Varnish (and browsers) literally not to cache the content.

The way it works is that they actually set things to ‘no-cache’ or ‘no-store.’ The first one says that the content can actually be cached, but it’s going to check and make sure the resources haven’t changed. It’s not really ‘no-cache’ but ‘check-cache.’ If nothing’s changed, there’s no new download of content, which is good, but it’s still not caching.

On the other hand, ‘no-store’ is really what we think about when we say not to cache. That tells the browser and all intermediate caches that every time someone wants this resource, download it from the server. Each. Time.

What does this have to do with Varnish? Well here’s the Varnish doc on Cache-Control:

no-store: The response body must not be stored by any cache mechanism;

no-cache: Authorizes a cache mechanism to store the response in its cache but it must not reuse it without validating it with the origin server first. In order to avoid any confusion with this argument think of it as a “store-but-do-no-serve-from-cache-without-revalidation” instruction.

Since Cache-Control always overrides Expires, setting things not to cache or store means you’re slowing down your site. Related to this, if you set your Max-Age to 0, then you’re telling visitors that the page’s cache is only valid for 0 seconds…

And some of you just said “Oh.”

Out of the box, WordPress actually doesn’t set these things poorly. That generally means if your site kicks out those horrible messages, it’s a plugin or a theme or, worst of all, a rogue Javascript that’s doing it. The last one is nigh-impossible to sort out. I’ve only been able to do it when I disable plugins and narrow down what does it. The problem is that just searching for ‘Cache-control’ can come up short when things are stashed in Javascript.

But there’s some kind of cool news. You can tell Wordpress to override and not send those headers. I’ve not had great success with using this when it’s a script being an idiot, but it works well for most plugins and themes that seem to think not caching is the way to go.

From StackExchange:

function varnish_safe_http_headers() {
    header( 'X-UA-Compatible: IE=edge,chrome=1' );
    session_cache_limiter('');
    header("Cache-Control: public, s-maxage=120");
  if( !session_id() )
  {
    session_start();
  }
}
add_action( 'send_headers', 'varnish_safe_http_headers' );

And yes, it works on DreamPress.

%d bloggers like this: