This post is an experiment in getting a Vanilla WordPress installation as fast as possible. Why? – Speed is Good.
Update: You can read part two on images here.
A new WordPress install was set up on a test domain. The 2015 theme was activated, and all plugins were uninstalled. This is what we’re benchmarking:
You’ll note that there really isn’t anything to it at the moment. This is intentional – if we can get this as fast as possible, then we have a foundation to work from as the site grows.
Pingdom’s webpage speed test gave us the following benchmark from their six locations (Australia, Netherlands, Sweden, Texas, California, New York):
Our absolute fastest benchmark (Amsterdam) loaded as follows –
Unlike static content, WordPress (the application) has to communicate with it’s database, which takes time, in order to assemble the html file it sends to the browser. Even for commonly requested resources like the homepage.
This is the first thing we tackle in the search for speed – if we can tackle the most significant delay for our fastest users, it should also have an impact on our slowest.
Server Side Caching
By default, W3 Total Cache will enable GZIP compression and browser-based caching. For the first test, this has been disabled.
At this point we install W3 Total Cache, which will allow us to make a number of performance changes. We first enable the ‘Page Cache’ feature:
Page Caching primes WordPress to prepare ‘here’s one I made earlier’ copies of more commonly requested resources – like the homepage and our ‘hello world’ post.
Once the cache has been created, and we wait a few minutes, we undergo another round of speed tests:
Our fastest page has dropped from 450ms to 257ms:
Not bad. Our server wait time for the homepage has dropped substantially, from ~0.25 to ~0.025 seconds:
Can we break 200ms? In the search for speed we must explore some additional options.
Concatenation and Minification
Minification is a process of removing unnecessary characters (spaces, indentation, comments) from text files in order to reduce their size. They still (hopefully) function as intended. We use W3 Total Cache to perform minification for external JS & CSS files, and our HTML (including inline CSS and JS):
Our homepage drops from 117 lines of html to 47. This knocks 22kb off the Page size. Concatenation means that 2 fewer requests are made:
In terms of speed gains, we’ve shaved a few ms off, but nothing to get excited about.
Using the Browser Cache settings we then encourage browsers to cache all static assets, and disable cookies setting for static files. Browser based caching shouldn’t make a difference to speed tests (as they typically represent a fresh user), but should make a massive difference to actual users viewing more than one page or returning to the site. This is also where we enable GZIP compression, which can have a substantial impact on filesize for text-based resources.
After another round of tests we find GZIP compression has taken us from 452.9kB to 273.3kB:
Load in Amsterdam and Sweden drops below 0.25 seconds. For our Australian friends, this makes the biggest difference, dropping a second off the load time:
Still – you can see a pattern with the connection and response (blue|yellow) being consistently the same speed:
It’s the negotiation of each request here that’s costly. It has to come from Australia (where the internet isn’t great) and then go back to Australia, and then come from Australia and then go back to Australia.
Content Delivery Network (CDN)
A Content Delivery Network keeps copies of your assets on servers around the world. Requests for resources on your domain are directed to the most suitable (read: most local) cached copy. This can lead to faster delivery, among other benefits.
Cloudflare have a free CDN. We sign up for an account and enter our domain name, opting for the free plan. As part of the setup we update our nameservers at our registrar to those supplied by Cloudflare.
By default Cloudflare will serve your static assets (images, css, js), but will not be caching your html. This would keep our first Australian request slow. Luckily with the free account you get three rules, which is just enough to get the pages cached without breaking your wordpress access in the process:
- yourdomain.com/wp-login.php* – bypass cache
- yourdomain.com/wp-admin.php* – bypass cache
- yourdomain.com/* – cache everything
It can take a little while for them to cache the static resources. You can check that Cloudflare is firing correctly by examining the headers either in browser, or with a utility like curl:
curl -svo /dev/null http://yourdomain.tld/resource
Once this is done, and to the best of our knowledge Cloudflare is up and running and caching the html, we retest.
I experienced similar performance gains across the board, the largest being in the US (which makes sense to me).
This is actually a bad test, Cloudflare needs enough requests from each location to make caching assets at each datacenter ‘worth it’. This wasn’t happening consistently, and this is a test domain with no traffic.
I also took internal benchmarks in Firefox using my own machine (in the UK, using UK hosting). These saw some substantial gains:
We can load the optimised version 68 times in the time it would take to load the unoptimised version. While this is clearly not going to happen in the real world, it’s not a bad place to start a new domain.
One of the post-minification tests for Amsterdam saw the following:
That’s a lot of waiting for the server, and an outlier in my tests. It does, however, illustrate the downside of shared hosting – at that moment the server was probably busy, which meant my performance suffered significantly.
In the next post I’ll discuss some of the experiments I’m running on this site for speed.