WordPress Varnish Cache Config / VCL

Note: I am now providing VCLs in separate branches on github as the Varnish VCL syntax has changed.

Thanks to scoof for documenting the Varnish VCL changes.

What is this for non-technical folks?

WordPress sucks at delivering the same content over and over again, actually, I should rephrase that, wordpress rocks 99% of the time but if you serve a page over and over again it will quickly exhaust your servers resource which will mean wordpress will go slow.  Varnish Cache speeds up WordPress by serving pages from memory instead of doinmagicg a bunch of hard work.

Why should I use this VCL?

I have done a number of different VCLs that can be used with varnish and wordpress but this is the final revision for now. It is designed for Varnish 2 but should work on 3 with no to very little modifications, I have tweaked this VCL over a few years and I’m finally happy with it.


  • Supports multiple back-ends
  • Supports round-robin
  • Supports Purging using the Varnish WordPress plugin
  • Supports logged in users
  • Supports password protected pages
  • Supports Mobile devices
  • Provides long client side caching
  • Forwards the correct client IP to the web daemon.
  • Doesn’t cache 404s, 503, 500 etc.
  • Doesn’t cache wp-admin, login, preview, signup
  • Caches static objects such as images
  • Supports Multisite
  • Includes debug/log messages.
  • Really clean code, proper tabbing etc.


Varnish, WordPress, The Varnish WordPress plugin installed and working, mod_rpaf installed in apache or an nginx equivalent.

Why have I made this?

I was going to make a VCL generator but then I remembered most people will use this VCL as a point of reference and I’m lazy, let’s face it, being lazy is the biggest factor in me backing out of making a generator. The varnish configs I have done before have been overly verbose for what they did and rewriting them and cleaning them up means this config is much easier to understand and modify. Adding logging means that you can easily use varnishlog to debug any problems you have.

What isn’t included?

I didn’t include Custom error messages in this VCL.  It’s not because I’m lazy, it’s because custom error messages put a lot of cruft into the VCL and if you want custom error messages you should see this article.

Let me at it!

Varnish v3
Varnish v3.03
Which version of Varnish am I running?

varnishd -V

What do I need to change?

Search and replace myFirstServer and mySecondServer with your server names adding new backends where required. Make sure new backends are added to the round-robin cluster and the purge list.

Once you are happy with your VCL save it in as /etc/varnish/default.vcl (remember to make a backup of your original file) and restart Varnish.  Any problems try to debug yourself but if you are stuck just give me a shout, I will be happy to help!

How to install mod_rpaf Varnish WordPress Ubuntu

And the geekiest title of the week goes to me…

Add this line to your varnish VCL in sub_recv:

set req.http.X-Forwarded-For = client.ip;

Grab mod_rpaf:

wget http://ftp.debian.org/debian/pool/main/liba/libapache2-mod-rpaf/libapache2-mod-rpaf_0.6-7_amd64.deb

Install mod_rpaf

dpkg -i libapache2-mod-rpaf_0.6-1_amd64.deb

Enable mod_rpaf:

a2enmod rpaf

Your rpaf config (/etc/apache2/mods-enabled/rpaf.conf) should look awesome like this:

<IfModule mod_rpaf.c>
RPAFenable On
RPAFsethostname On

Note: RPAFproxy_ips is the ips of your varnish cache servers. Varnish is awesome.

Reload varnish and Apache the cool way.

/etc/init.d/varnish reload
/etc/init.d/apache reload

Test it by looking at your remote_addr variable:


WordPress mobile error: “the target server failed to respond”

When joining a new mobile device to wordpress it looks like the first request is a GET request.

My Varnish config only included support for POST requests to xmlrpc.php

I updated my config to read:

// set backend, pipe, strip cookies from xmlrpc 
  if (req.request == "POST" && req.url ~ "xmlrpc.php") {remove req.http.cookie;set req.backend = mainserver;return(pipe);}
  if (req.request == "GET" && req.url ~ "xmlrpc.php") {remove req.http.cookie;set req.backend = mainserver;return(pipe);}

and it sorted it! Huraa

Varnishlog cheat sheet


Look at an incoming client request of a specific URL:

varnishlog -c -m RxURL:"readysetlearn/readysetlearn.htm"

Look at a a backend request of a specific URL:

varnishlog -b -m TxURL:"readysetlearn/readysetlearn.htm"

See requests for one specific Hostname:

varnishlog -c -m RxHeader:"Host: etherpad.org"

See the age of the cache objects for a specific hostname:

varnishlog -c -m RxHeader:"Host: etherpad.org" | grep Age

Look at an incoming client request of a specific URL:

varnishlog -c -o RxURL readysetlearn/readysetlearn.htm

Look at a a backend request of a specific URL:

varnishlog -b -o TxURL readysetlearn/readysetlearn.htm

See requests for one specific Hostname:

varnishlog -c -o RxHeader "Host: etherpad.org"

See the age of the cache objects for a specific hostname:

varnishlog -c -o RxHeader "Host: etherpad.org" | grep Age

If an item has a high age it means that varnish is hitting the cache for it.

Thanks to Mithrandir from the #Varnish IRC channel for helping out and thanks to Tomnomnom for V3 help!.