Varnish is an Apache service that can improve your site’s performance by serving cached files. When a user requests a file from your site, Varnish checks its cache; if it finds a cached version of the file it returns that file, else it forwards the request to the server as usual and potentially caches the response.
Varnish & WordPress
Varnish can lead to big performance gains for a WordPress site in particular, since WordPress isn’t serving any static files that can be cached by the browser. Instead, when request hits the server for a webpage, WordPress has to load, find the appropriate template, and run a bunch of PHP to service the request. With Varnish installed, when a request first comes in for a page WordPress renders it but Varnish stores the finished product; for subsequent requests for the same page Varnish can just return the cached file, bypassing WordPress entirely.
We don’t want to cache all files, however, as some return dynamic content based on the request: in particular, we don’t want to cache files when a user is logged in. Fortunately Varnish allows for configuration to do just that.
Another consideration are WordPress’s use of nonce fields. A nonce is valid for 12 hours, and, despite its name, can be used more than once. If you configure Varnish to cache pages for less than 12 hours you should be fine. In the below configuration we specify a 1-hour caching period.
Elastic Beanstalk configuration
Note that a bad configuration can take your site down. To properly configure Varnish we have to tell it to listen on port 80, where httpd usually listens, and tell httpd to listen on another port where we forward requests. If the Varnish configuration isn’t working, requests to port 80 will return 503 errors. Ideally you’d test Varnish on a staging site first to ensure proper configuration.
Add all of the following configuration files to your .ebextensions directory. The files could be combined into a single file but are broken out here for explanatory purposes.
The above simply installs Varnish on your instances. This tutorial assumes you are running Amazon Linux 2017.09, which supports Varnish 3.0.7.
Varnish requires minimum ulimits for the number of files it can create, its memory allocation, and its number of processes. If we don’t update these Varnish will complain and won’t start.
This is the Varnish configuration file, written using the Varnish Configuration Language (VCL).
Line 2 Varnish will look for a configuration file at this location.
Lines 3-5 Set permissions and user and group for the configuration file.
Lines 10-13 Of note is line 12, where we tell Varnish to forward requests to port 81. Later we’ll instruct httpd to listen on this port.
Line 17 The vcl_recv function handles requests. This is where we make modifications and decide what to do with various requests.
Lines 20-25 Varnish provides a method to purge files from the cache if need be. For instance, if you update a post and want the new version immediately available you could send a PURGE request to your server at the address of the post. This request will only be honored if it includes a custom header X-Purge-Token with the value “XXX”. Change the “XXX” to your own secret value so third parties can’t purge pages from your site.
Lines 28-37 Varnish includes a special “pipe” command that we should use for non-standard requests. This pipes the request to our server.
Lines 40-42 Only cache GET and HEAD requests.
Lines 45-50 This assumes you’ve completed both Add a Custom Domain and Force HTTPS tutorials. Replace “example.com” with your domain. If the request is not over HTTPS or lacks “www” we redirect to “https://www.example.com”. The custom error 750 is handled later on.
Lines 53-55 We don’t want to cache any of the admin or login pages.
Line 58 Remove the WordPress test cookie so we don’t match it below when checking whether user is logged in.
Lines 61-63 Don’t cache objects if the user is logged in.
Line 66 Remove all client cookies from request.
Line 69 Return object from cache if available else from backend server.
Lines 74-79 Handle purge request on cache hit.
Lines 83-88 Handle purge request on cache miss.
Lines 92-94 Cache objects for 1 hour.
Lines 98-105 Set custom header so we can see if returned page was a hit (cached) or miss (not cached).
Lines 109-115 Handle our custom “error” to return a redirect that we defined in lines 45-50.
Note that there may be additional pages that you don’t want to cache. For instance, if you’re using WooCommerce you’ll want to exclude at least the cart and checkout pages from caching. You can achieve this by adding additional rules to the vcl_recv function.
Lines 2-5 Modify httpd.conf to tell httpd to listen on port 81.
Lines 6-7 Modify the configuration to tell varnish to listen on port 80.
Lines 8-9 Modify the configuration to tell varnish admin to listen on port 2000.
Starting the service
The above is based on this post from junkheap.net. It makes use of the special /opt/elasticbeanstalk/hooks/appdeploy/post directory by adding a simple shell script that restarts Varnish.
When you re-deploy to your environment you should have Varnish up and running. You can check its behavior by looking for the X-Cache response headers. Remember that if you’re logged in Varnish will not cache pages. If you have questions or suggestions please feel free to leave comments below.