Varnish config for WordPress
The server that hosts this website was configured from the ground up by myself. The purpose was to configure a server with a rather limited resource set that was able to serve a few websites without handing in on performance and page speed.
One of the ways to maintain a good performance of the server and websites is to ease the web server from its tasks by implementing a caching proxy. In this case I used Varnish Cache to accelerate my websites.
Installation
First of all I created a new entry in my Debian apt sources to be able to install the latests stable release of Varnish:
~$ cat /etc/apt/sources.list.d/varnish.list deb http://repo.varnish-cache.org/debian/ wheezy varnish-3.0 ~$ apt-get update ~$ apt-get install varnish |
Configuration
Next on was the creation of the Varnish configuration itself. This configuration is optimised for WordPress powered websites.
This is the content of my /etc/varnish/default.vcl (a download link to this file can be found at the bottom of this page):
backend default { .host = "127.0.0.1"; .port = "8080"; } # Who is allowed to purge? acl purgers { "localhost"; "88.151.240.193"; # Change this by the ip address(es) from where you would want to perform PURGE operations } sub vcl_recv { if (req.request == "PURGE") { if (!client.ip ~ purgers) { error 405 "You are not allowed to purge"; } return(lookup); } # Set proxied ip header to original remote address set req.http.X-Forwarded-For = client.ip; # If the backend fails, keep serving out of the cache for 30m set req.grace = 30m; # Remove has_js and Google Analytics cookies set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(__[a-z]+|__utm*|has_js)=[^;]*", ""); # Remove a ";" prefix, if present. set req.http.Cookie = regsub(req.http.Cookie, "^;\s*", ""); # Remove empty cookies. if (req.http.Cookie ~ "^\s*$") { unset req.http.Cookie; } # remove double // in urls, set req.url = regsuball( req.url, "//", "/" ); # Normalize Accept-Encoding if (req.http.Accept-Encoding) { if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") { # No point in compressing these 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 { # unknown algorithm remove req.http.Accept-Encoding; } } # Remove cookies for static files if (req.url ~ "\.(gif|jpg|jpeg|swf|css|js|flv|mp3|mp4|pdf|ico|png|tif|tiff|mp3|htm|html)(\?.*|)$") { unset req.http.cookie; return(lookup); } # Disable caching for backend parts if ( req.url ~ "^/[^?]+/wp-(login|admin)" || req.url ~ "^/wp-(login|admin)" || req.url ~ "preview=true" ) { return(pass); } # always pass through posted requests and those with basic auth if ( req.request == "POST" || req.http.Authorization ) { return (pass); } # Strip cookies for cached content unset req.http.Cookie; return(lookup); } sub vcl_fetch { # If the backend fails, keep serving out of the cache for 30m set beresp.grace = 30m; set beresp.ttl = 48h; # Remove some unwanted headers unset beresp.http.Server; unset beresp.http.X-Powered-By; # Respect the Cache-Control=private header from the backend if (beresp.http.Cache-Control ~ "private") { set beresp.http.X-Cacheable = "NO:Cache-Control=private"; } elsif (beresp.ttl < 1s) { set beresp.ttl = 5s; set beresp.grace = 5s; set beresp.http.X-Cacheable = "YES:FORCED"; } else { set beresp.http.X-Cacheable = "YES"; } # Don't cache responses to posted requests or requests with basic auth if ( req.request == "POST" || req.http.Authorization ) { return (hit_for_pass); } # Cache error pages for a short while if( beresp.status == 404 || beresp.status == 500 || beresp.status == 301 || beresp.status == 302 ){ set beresp.ttl = 1m; return(deliver); } # Do not cache non-success response if( beresp.status != 200 ){ return(hit_for_pass); } return(deliver); } sub vcl_deliver { # Add debugging headers to cache requests if (obj.hits > 0) { set resp.http.X-Cache = "HIT"; } else { set resp.http.X-Cache = "MISS"; } } sub vcl_error { # Try connecting to apache 3 times before giving up if (obj.status == 503 && req.restarts < 2) { set obj.http.X-Restarts = req.restarts; return(restart); } if (obj.status == 301) { set obj.http.Location = req.url; set obj.status = 301; return(deliver); } } sub vcl_hit { if (req.request == "PURGE"){ set obj.ttl = 0s; error 200 "Varnish cache has been purged for this object."; } } sub vcl_miss { if (req.request == "PURGE") { error 404 "Object not in cache."; } } |
Activation
After this configuration I changed Apache and my vhosts to run on port 8080 and Varnish on port 80.
~$ vi /etc/apache2/ports.conf ... NameVirtualHost *:8080 Listen 8080 ... ~$ vi /etc/apache2/sites-enabled/dimitrieu ... ~$ vi /etc/default/varnish ... DAEMON_OPTS="-a :80 \ -T localhost:6082 \ -f /etc/varnish/default.vcl \ -S /etc/varnish/secret \ -s malloc,256m" ... ~$ /etc/init.d/apache2 restart ~$ /etc/init.d/varnish restart |
OpenVZ tweak for Varnish
On a side note; in order to prevent Varnish from eating all of your memory on an OpenVZ platform like Parallels Virtuozzo (where my server is hosted on) you should modify your Varnish init script. Just add the following code somewhere in your init script (/etc/init.d/varnish):
# Make sure OpenVZ does not use up all memory ulimit -s 2048 |
If you just want to download my Varnish configuration file you can just click on this link: Varnish vcl for WordPress
- Configure Ruby on Rails with Phusion Passenger (mod_rails)
- PHP-FPM on Apache with split configuration per site
Be familiar with more upon http://baclofen2510.forumcircle.com/portal.php order baclofen without-prescription cheap
Pingback: How to purge the Varnish cache | Dimitri.eu