I am in the fortunate situation that, for the most part, I can trust my backend responses regarding the Cache-Control headers. This spares me the tedious work of setting a proper ttl and cleaning up the response headers. Let’s face it, the cache layer cannot (and should not) always know how long a certain response can be safely cached. In my case there is an Apache web server between Varnish and the application server so even if the application itself won’t set the correct Cache-Control header, Apache can and will.
<Location ~ "^/(apple-touch-icon.*\.png|favicon\.ico)$"> Header set Cache-Control "max-age=21600, s-maxage=21600, public" </Location>
However there is a situation which Varnish has to be prepared for so not to do “the wrong thing” (TM). Imagine your beloved favicon.ico gets deleted somehow. Varnish forwards the request to Apache which in turn will get a “404 Not Found” response from its application server. Next the Apache configuration hits and that very 404 will be augmented with a nice Cache-Control header allowing this response to be cached for the next 6 hours. And that is exactly what Varnish will do. Not good. To work around this little snafu you could implement the following:
sub vcl_fetch {
if (beresp.status >= 400) {
unset beresp.http.Expires;
unset beresp.http.Cache-Control;
if (beresp.ttl > 60s) {
set beresp.http.Cache-Control = "public, max-age=0, s-maxage=60";
set beresp.ttl = 60s;
}
}
}
This way an erroneous response cache time will at least be lowered to one minute, if cached at all. That is actually a good thing because that poor, always overwhelmed, application servers should not be bothered a hundred times a second just to spit out a “404 Not Found”. Let them be busy garbage collecting, or whatever it is they do nowadays.