Updated Varnish WordPress VCL

THIS VARNISH CONFIG HAS BEEN UPDATED AND IS AVAILABLE HERE

I have been tweaking a varnish vcl config for WordPress for quite some time and I wanted to share it..  Thanks to everyone(especially DocWilco)  in #varnish on Linpro IRC for helping

Features:

  1. Load balancing
  2. Probing
  3. Does not cache wp-admin
  4. Puts all uploads/content requests onto one server
  5. Purging
  6. Long timeout for file uploads
  7. XML RPC support
  8. Custom 404 and 500 message
  9. Forwards user IP address for comments

First of all.. Let’s define some backends..

// BACKEND CONFIGS
backend server1 {
  .host = "server1.example.com";
  .port = "8080";
  .probe = {
                .url = "/";
                .interval = 5s;
                .timeout = 1 s;
                .window = 5;
                .threshold = 3;
  }
// we include time outs so uploads don't time out
 .connect_timeout = 600s;
 .first_byte_timeout = 600s;
 .between_bytes_timeout = 600s;
}

backend server2 {
  .host = "server2.example.com;
  .port = "8080";
  .probe = {
                .url = "/";
                .interval = 5s;
                .timeout = 1 s;
                .window = 5;
                .threshold = 3;
  }
// we include time outs so uploads don't time out
 .connect_timeout = 600s;
 .first_byte_timeout = 600s;
 .between_bytes_timeout = 600s;
}

// define round-robin for backends
director cluster round-robin {
        {.backend = server1;}
        {.backend = server2;}
}

// set the servers wordpress can purge from
acl purge {
        "server1.example.com";
        "server2.example.com";
}

sub vcl_fetch {
 if (req.http.host ~ "ourdomain.com"
     || req.http.host ~ "ourotherdomain.com"
// don't cache wp-admin ever cause that's not cool
     && req.url !~ "wp-admin")
{
// we cache these domains for 8 hours unless they are purged.
        set beresp.ttl = 8h;
        set beresp.grace = 600s;
// don't cache 404 or 500 errors
        if (beresp.status == 404 || beresp.status >= 500) {
                  set beresp.ttl = 0s;
        }
}
// tell all of the files to use server1
if (req.url ~ "files") {set req.backend = server;set beresp.ttl = 8h;}
}

sub vcl_recv {
// Purge WordPress requests for purge
  if (req.request == "PURGE") {
                if (!client.ip ~ purge) {
                        error 405 "Not allowed.";
                }
                purge("req.url == " req.url " && req.http.host == " req.http.host);
                error 200 "Purged.";
        }

// forward the client IP so comments show up properly
set req.http.X-Forwarded-For = client.ip;

// let server2 handle all feeds
    if (req.url ~ "/feed/")
    {set req.backend = server2;}

// server1 must handle file uploads
    if (req.url ~ "media-upload.php"
    || req.url ~ "file.php"
    || req.url ~ "async-upload.php")
    {set req.backend = server1;return(pass);}

// server1 can serve all files.
    if (req.url ~ "/files/")
    {set req.backend = server1;}

// do not cache xmlrpc.php
    if (req.url ~ "xmlrpc.php")
    {return(pass);}

// strip cookies from xmlrpc
    if (req.request == "GET" && req.url ~ "xmlrpc.php")
    remove req.http.cookie;return(pass);}

// caching these files is fine
if (req.http.Accept-Encoding) {
        if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|lzma|tbz)(\?.*|)$") {
            remove req.http.Accept-Encoding;
        } elsif (req.http.Accept-Encoding ~ "gzip") {
            set req.http.Accept-Encoding = "gzip";
        } elsif (req.http.Accept-Encoding ~ "deflate") {
            set req.http.Accept-Encoding = "deflate";
        } else {
            remove req.http.Accept-Encoding;
        }
}

// Remove cookies and query string for real static files
    if (req.url ~ "^/[^?]+\.(jpeg|jpg|png|gif|ico|js|css|txt|gz|zip|lzma|bz2|tgz|tbz|html|htm)(\?.*|)$") {
       unset req.http.cookie;
       set req.url = regsub(req.url, "\?.*$", "");
    }

// Remove cookies from front page
    if (req.url ~ "^/$") {
       unset req.http.cookie;
    }

// if the request is for our domain and not for wp-admin then load balance it to a server that is responding or send it to server1
if (req.http.host ~ "ourdomain.com"
    || req.http.host ~ "ourotherdomain.com"
    && req.url !~ "wp-admin")
{
        set req.http.X-Forwarded-For = client.ip;
        set req.backend = cluster;
        } else {
        set req.http.X-Forwarded-For = client.ip;
        set req.backend = server1;
}

// Custom error message
sub vcl_error {
if(obj.status == 404) {
        set obj.ttl = 0s;
  set obj.http.Content-Type = "text/html; charset=utf-8";
    synthetic {" <!--?xml version="1.0" encoding="utf-8"?-->

    "} obj.status " " obj.response {"
</pre>
<div style="background-color: white;"><center>
 <img src="http://whatever.com/heavyload.jpg" alt="" width="600px" /></center>
<h1>This page is unavailable</h1>
If you are seeing this page, either maintenance is being
performed or you are trying to access a file that doesn't exist. Please <a href="http://whatever.com/contact.html">contact us</a> if you believe this is an error
<h2>Error "} obj.status " " obj.response {"</h2>
"} obj.response {" on server "} req.backend {"
<address><a href="http://whatever.com/">Us.</a></address></div>
<pre>
  "};
    return (deliver);
error 404 "Not found";
 }
else
{
    set obj.http.Content-Type = "text/html; charset=utf-8";
    synthetic {" <!--?xml version="1.0" encoding="utf-8"?-->  
  
    "} obj.status " " obj.response {"
  

</pre>
<div style="background-color: white;"><center>
 <img src="http://whatever.com/heavyload.jpg" alt="" width="600px" /></center>
<h1>This website is unavailable</h1>
If you are seeing this page, either maintenance is being
performed
 or something really bad has happened. Try returning in a few
minutes. If you still see this error in a few minutes please <a href="http://whatever.com/contact.html">contact us</a>
<h2>Error "} obj.status " " obj.response {"</h2>
"} obj.response {" on server "} req.backend {"
<address><a href="http://whatever.com/">Us.</a></address></div>
<pre>
  "};
    return (deliver);
}
}

5 thoughts on “Updated Varnish WordPress VCL

  1. Thanks for this – I’m looking at doing the same so sure it will be helpful. Can I ask though… am I right in thinking you need to allow admin connections from any IP to allow the backend servers to issue a purge request e.g. -T 0.0.0.0:6082. Obviously this is not very secure so I’d like to explicitly set the IPs to the wordpress backend servers but not sure if it’s possible to specify this in varnish. Have you managed to get around this issue? Thanks John

  2. I’m pretty sure you could just do this in the VCL

    if (req.http.backend == “atrustedbackend”){//issue purge}

    something like that?

  3. Great I’ll this a try on my server. However your links to whateverDOTcom/heavyload.jpg bring back a stop sopa img . or is this just an example link?

  4. I am currently on holiday away from work with no access to any internet enabled devices.

    Please forward any Technical support queries to adammc@primaryt.co.uk
    Please forward any installation/projector maintinance/av queries to dally@primaryt.co.uk
    Please forward any other service queries to josh@primaryt.co.uk

    For all urgent enquiries use contact@primaryt.co.uk
    This email and its attachments may be confidential and are intended solely for the use of the individual to whom it is addressed. Any views or opinions expressed are solely those of the author and do not necessarily represent those of the organisation from which this email originated. If you are not the intended recipient of this email and its attachments, you must take no action based upon them, nor must you copy or show them to anyone. Please contact the sender if you believe you have received this email in error. This email was sent by School Email – Safe Webmail and Hosted Email for Schools

  5. This is the old config.  Don’t use it.  It’s evil.  See the big orange link at the top.

Leave a Reply

Your email address will not be published. Required fields are marked *