Custom WordPress Varnish VCL v1

Over the last couple of days I’ve been struggling with getting my dev WordPress environment set up with Varnish (2.1.3) Out of the box with minimal config it provides great speed and hitrate but zero functionality together with the cookie-laden WordPress. So far I have tested a bunch of VCL:s found online but here’s my take (based on practically every nice example found out there).

To get WordPress to purge when you create or edit posts, I have tried W3 Total Cache, but the Varnish implementation doesn’t seem to work that well. The only plug-in that I have gotten to work with this setup is WP-Varnish by Pål-Kristian Hamre.

The single specified backend config has to do with another test I’m working on with getting Varnish to serve different sites running for example Drupal and WordPress, with a single VCL. I’ll get back to that one.

backend wp1 {.host = "";.port = "8080";}
sub vcl_recv {
if ( == "") {set = "";set req.backend = wp1;}
acl purge {
sub vcl_recv {
 set req.grace = 6h;
 if (req.request == "PURGE") {
if (!client.ip ~ purge) {error 405 "Not allowed.";}purge("req.url ~ " req.url " && == ";error 200 "Purged.";
# Do the PURGE thing
sub vcl_hit {if (req.request == "PURGE") {set obj.ttl = 0s;error 200 "Purged";}}
sub vcl_miss {if (req.request == "PURGE") {error 404 "Not in cache";}}
sub vcl_recv {
 # set standard proxied ip header for getting original remote address
set req.http.X-Forwarded-For = client.ip;
 # logged in users must always pass
if( req.url ~ "^/wp-(login|admin)" || req.http.Cookie ~ "wordpress_logged_in_" ){return (pass);}
 # don't cache search results
if( req.url ~ "\?s=" ){return (pass);}
 # always pass through posted requests and those with basic auth
if ( req.request == "POST" || req.http.Authorization ) {return (pass);}
 # else ok to fetch a cached page
unset req.http.Cookie;
return (lookup);
sub vcl_fetch {
 # remove some headers we never want to see
unset beresp.http.Server;
unset beresp.http.X-Powered-By;
 # only allow cookies to be set if we're in admin area - i.e. commenters stay logged out
if( beresp.http.Set-Cookie && req.url !~ "^/wp-(login|admin)" ){unset beresp.http.Set-Cookie;}
 # don't cache response to posted requests or those with basic auth
if ( req.request == "POST" || req.http.Authorization ) {return (pass);}
 # Trust Varnish if it says this is not cacheable
if ( ! beresp.cacheable ) {return (pass);}
 # only cache status ok
if ( beresp.status != 200 ) {return (pass);}
 # don't cache search results
if( req.url ~ "\?s=" ){return (pass);}
 # else ok to cache the response
set beresp.ttl = 24h;
return (deliver);
sub vcl_deliver {
# add debugging headers, so we can see what's cached
if (obj.hits > 0) {set resp.http.X-Cache = "HIT";set resp.http.X-Cache-Hits = obj.hits;}
else {set resp.http.X-Cache = "MISS";}
# remove some headers added by varnish
unset resp.http.Via;
unset resp.http.X-Varnish;

One comment

  1. Helllo! Nice job. This setup worked fine for me.

Post a comment

You may use the following HTML:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>