Slapping some Varnish on WordPress
So last week I published my review of PHPNW12 and instantly my whole server went down in flames. My current WP setup has a few issues with multi-lingual plugins which I can’t get over yet, as it requires a bit more of invested time. But this can’t go on, I needed a solution, a fast and simple one to give my blog a fighting chance.
As it stood I already had caching, but i’m guessing that was not enough or decently handled, so I gave a shout out to @thijsferyn to see if putting up Varnish would be a simple enough task. This is BTW one of the reasons I dedicate so much time to helping and growing the community, because when I tread into new waters like this, I can call on smart people who are always willing to lend me a hand. It was no different with Thijs and by the next day I had a recommended setup to try and get Varnish up.
Varnish + WP + ServerGrove
My server is a 1Gb VPS with Servergrove and it runs 3 blogs and a personal website, all smallish with the occasional peak access, so I went on to get things up. Thijs had recommended running Apache on 8080 and leaving Varnish on port 80, but Servergrove is still working on alternative port configuration in their dashboard and they quickly got back to me with the suggestion of putting Apache to listen to localhost on 80 and leaving varnish to handle outside requests. This change was pretty simple I just had to tell Apache to listen to that and change my vhosts:
NameVirtualHost 127.0.0.1:80 Listen 127.0.0.1:80
Problem solved. Now to get varnish. Thijs pointed me to some easy to follow tutorials for each common OS: Ubuntu , Debian , Redhat or CentOS .
Once that was done, I needed to do was configure the basic setup, so I basically had to edit /etc/default/varnish
to listen to external requests on port 80:
DAEMON\_OPTS="-a <external-ip>:80 \\ -T localhost:6082 \\ -f /etc/varnish/default.vcl \\ -S /etc/varnish/secret \\ -s malloc,256m"
This is enough to get Varnish listening and do the trick, but now the important part is to get the right VCL configuration so that you don’t run into troubles with your admin pages, cookies being ignored and so forth. If you want more details on the out-of-the-box setup, go see Thijs’ Vanish in Action slides . So next step, the vcl: I had a gist from Thijs to get is sorted, but I had to make a few changes to it to get it just right, but in general its very straight forward, the main highlights are:
- It ignores admin pages
- It ignores logged users
- It allows purges from WP
- It adds a HIT/MISS header you can track to see if its being effective.
backend default { .host = "127.0.0.1"; .port = "80"; } acl purge { "localhost"; "<external-ip>"; } sub vcl\_recv {
\# Allow purging if(req.request == "PURGE"){ if(!client.ip ~ purge){ error 405 "Purging not allowed."; } return(lookup); }
\# Always cache the following file types for all users. if ( req.url ~ "(?i)\\.(png|gif|jpeg|jpg|ico|swf|css|js|html|htm)(\\?\[a-z0-9\]+)?$" ) { unset req.http.cookie; }
\# Don't serve cached pages to logged in users if ( req.http.cookie ~ "wordpress\_logged\_in" || req.url ~ "vaultpress=true" ) { return( pass ); }
\# Drop any cookies sent to WordPress. if ( ! ( req.url ~ "wp-(login|admin)" ) ) { unset req.http.cookie; }
\# Handle compression correctly. Different browsers send different # "Accept-Encoding" headers, even though they mostly all support the same # compression mechanisms. By consolidating these compression headers into # a consistent format, we can reduce the size of the cache and get more hits. # @see: http://varnish.projects.linpro.no/wiki/FAQ/Compression if ( req.http.Accept-Encoding ) {
if ( req.http.Accept-Encoding ~ "gzip" ) { # If the browser supports it, we'll use gzip. set req.http.Accept-Encoding = "gzip"; }
else if ( req.http.Accept-Encoding ~ "deflate" ) { # Next, try deflate if it is supported. set req.http.Accept-Encoding = "deflate"; }
else { # Unknown algorithm. Remove it and send unencoded. unset req.http.Accept-Encoding; }
}
}
sub vcl\_fetch {
\# Allow items to be stale if needed. set beresp.grace = 2m;
\# Drop any cookies WordPress tries to send back to the client. if ( ! req.url ~ "wp-(login|admin)" && ! req.http.cookie ~ "wordpress\_logged\_in" ) { unset beresp.http.set-cookie; }
}
sub vcl\_miss { if(req.request == "PURGE"){ purge; error 200 "Purged"; } }
sub vcl\_hit { if(req.request == "PURGE"){ purge; error 200 "Purged"; } }
sub vcl\_deliver { if(obj.hits > 0) { set resp.http.X-Varnish-Cache = "HIT ("+obj.hits+")"; } else { set resp.http.X-Varnish-Cache = "MISS"; } }
That was pretty much it. It was then a matter of restarting the services, getting rid of WP cookies so it would not ignore me and asking people to hit the blog up, which showed me a nicely growing hit count on the HIT header and a significant lack of stress on the server. As an extra resource, check this post it has some nice information and configuration settings.
Hopefully the result will be that when I release this post, I will not get lots of replies of my blog being down, but rather Varnish will take care of all of you. The PHP community is truly a remarkable one and it never ceases to amaze me how much we are willing to do for each other and lend a helping hand, so thank you Thijs for the leads.
Also, if you are looking for VPS hosting, I can recommend two services for you: Combell employers of Thijs and Servergrove current hosters of this blog.