I have decided to give my server the final boost in my quest for ultimate cachability and install Varnish cache. It was a toss up between doing this and installing NGINX but I have a reasonably large set of rules in my .htaccess to prevent hackers and 301s so I figured the migration would be a bit more than the few hours I had to spare.
First install varnish.
sudo yum install varnish
Make sure that it comes back on startup.
chkconfig varnish on
Now edit the following file.
sudo vim /etc/sysconfig/varnish
The below is what I ended up with in my file thanks to this. The main difference from the original is the change of the VARNISH_STORAGE_TYPE to malloc which means that it is stored in memory rather than disk. I chose 128MB as my blog is pretty small and I wanted to have a bit of room to spare.
# Varnish Users VARNISH_RUN_USER=varnish VARNISH_RUN_GROUP=varnish # Should we start varnishd at boot? Set to "yes" to enable. START=yes # Maximum number of open files (for ulimit -n) # NFILES=131072 # Locked shared memory (for ulimit -l) # Default log size is 82MB + header MEMLOCK=82000 # # Maximum number of threads (for ulimit -u) NPROCS="unlimited" # # Maximum size of corefile (for ulimit -c). Default in Fedora is 0 DAEMON_COREFILE_LIMIT="unlimited" RELOAD_VCL=1 # Should probably change this VARNISH_VCL_CONF=/etc/varnish/default.vcl # Not setting VARNISH_LISTEN_ADDRESS makes Varnish listen on all IPs on this box # (Both IPv4 and IPv6 if available). Set manually to override this. # VARNISH_LISTEN_ADDRESS= VARNISH_LISTEN_PORT=80 # Telnet admin interface listen address and port VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1 VARNISH_ADMIN_LISTEN_PORT=6082 # Shared secret file for admin interface VARNISH_SECRET_FILE=/etc/varnish/secret # The minimum number of worker threads to start VARNISH_MIN_THREADS=50 # The Maximum number of worker threads to start VARNISH_MAX_THREADS=5000 # Idle timeout for worker threads VARNISH_THREAD_TIMEOUT=120 # Best option is malloc if you can. malloc will make use of swap space smartly if # you have it and need it. VARNISH_STORAGE_TYPE=malloc # Cache file size: in bytes, optionally using k / M / G / T suffix, # or in percentage of available disk space using the % suffix. VARNISH_STORAGE_SIZE=128M VARNISH_STORAGE="${VARNISH_STORAGE_TYPE},${VARNISH_STORAGE_SIZE}" # Default TTL used when the backend does not specify one VARNISH_TTL=60 # DAEMON_OPTS is used by the init script. If you add or remove options, make # sure you update this section, too. DAEMON_OPTS="-a ${VARNISH_LISTEN_ADDRESS}:${VARNISH_LISTEN_PORT} \ -f ${VARNISH_VCL_CONF} \ -T ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT} \ -t ${VARNISH_TTL} \ -w ${VARNISH_MIN_THREADS},${VARNISH_MAX_THREADS},${VARNISH_THREAD_TIMEOUT} \ -u ${VARNISH_RUN_USER} -g ${VARNISH_RUN_GROUP} \ -S ${VARNISH_SECRET_FILE} \ -s ${VARNISH_STORAGE}"
Then you need to edit your /etc/varnish/default.vcl the below is what I ended up with which allows you to see the WordPress Admin Bar but caches most other bits. It also takes invalidation requests from the Varnish WordPress Plugin which is the easiest way to keep your content fresh.
backend default { .host = "127.0.0.1"; .port = "8080"; } acl purge { "localhost"; } sub vcl_recv { if (req.request == "BAN") { if(!client.ip ~ purge) { error 405 "Not allowed."; } ban("req.url ~ "+req.url+" && req.http.host == "+req.http.host); error 200 "Banned."; } if (req.request != "GET" && req.request != "HEAD" && req.request != "PUT" && req.request != "POST" && req.request != "TRACE" && req.request != "OPTIONS" && req.request != "DELETE") { return (pipe); } if (req.request != "GET" && req.request != "HEAD") { return (pass); } # don't cache authenticated sessions if (req.http.Cookie && req.http.Cookie ~ "(wordpress_|PHPSESSID)") { return(pass); } # don't cache ajax requests if(req.http.X-Requested-With == "XMLHttpRequest" || req.url ~ "nocache" || req.url ~ "(control.php|wp-comments-post.php|wp-login.php|bb-login.php|bb-reset-password.php|register.php)") { return (pass); } if (req.url ~ "wp-(login|admin)" || req.url ~ "preview=true") { return (pass); } remove req.http.cookie; return (lookup); } sub vcl_fetch { if (beresp.status => 400) { set beresp.ttl = 0m; return(hit_for_pass); } if (req.url ~ "wp-(login|admin)" || req.url ~ "preview=true") { return (hit_for_pass); } set beresp.ttl = 24h; return (deliver); }
You then need to update your Apache to listen to port 8080 as Varnish will be listening on port 80.
sudo vim /etc/httpd/conf/httpd.conf
Update Listen 80 to Listen 8080 and then restart Apache and Varnish and then you can run varnishstat to see the details of how your cache is performing.
sudo service httpd restart sudo service varnish restart varnishstat
I then installed the Varnish WordPress Plugin and then went to Dashboard -> Settings -> WP-Varnish and updated the following fields.
- Varnish Administration IP Address
- Varnish Administration Port
- Varnish Administration Secret
The secret is a GUID which is stored in the below.
sudo vim /etc/varnish/secret
These are some really useful Varnish commands to see how your cache is performing or check out the docs for full details.
- varnishtop: like top but for varnish.
- varnishhist: histogram of request time
- varnishstat: cache hits, resource consumption and many other data points
- varnishlog: log of all requests made to the cache
You should then have a super charged server where most of the files are coming from memory rather than disk. The below sites were helpful along this journey.
Install Varnish HTTP Accelerator with WordPress
Speed up WordPress with Apache and Varnish
WordPress Varnish Cache Config / VCL
Music to write this code to
Makoto the drum and bass maestro does some house and techno which always gets me going at the command line.
Great post! Thanks a lot.
how do you manage your iptables?
I haven’t had the need to alter my IP tables for this implementation.
here you can see why do you need it
http://stackoverflow.com/questions/27559340/varnish-4-0-1-fail-to-access-website-often-request-timeout
It seems that you are missing the creation of the varnish user and group in the instructions or did I miss it.
You are correct that it is missing, I didn’t need to create it to get this working. I was going to come back and fix that but as it was working haven’t managed to get around to it yet.
I have tried a three different default.vcl configurations and my cache hit rate stays well below 80 percent. It must be a black art to get the default.vcl right and not use too many plugins or have the configured so that they don’t lower the hit rate.
The only plugin that I use is the one that flushes Varnish, the default.vcl that I put in this post seems to keep mine around 97-99%. The only other caching I use is Batcache which doesn’t require a plugin either and these two combined have made an amazing difference to overall speed.