If you’re a regular around these parts, you may have noticed that this blog recently got a complete overhaul. But we didn’t just refresh the design with a new theme – we also completely revamped how it’s hosted to set us in good stead for anything we might want to do with it in the future.
For years this blog has been running on a third-party managed WordPress solution, with a messy arrangement of reverse-proxy servers and caching layers to keep it running smoothly and without falling over every time we had a mild traffic spike. With this new version, we’re now running everything inside our own infrastructure on AWS, which gives us much more comprehensive control over how everything is managed and scaled.
If you’re just interested in how you can do this for yourself, jump straight to the CloudFormation template at the end of this post. If you’re interested in some of the potential gotchas and caveats involved, read on.
Should I even be running WordPress myself?
If you’re thinking of setting up and hosting your own WordPress, the very first question you should probably ask yourself is: should I even be doing this? There are plenty of managed WordPress hosting solutions available — companies that specialise entirely in hosting and managing WordPress at scale. In almost all scenarios, the setup will be easier, and these solutions will do a much better job than you can do trying to host things yourself.
In our case, we were migrating an existing setup, we already had a lot of the necessary moving parts in place for directly integrating with our load balancers and CDNs, and decent knowledge of setting up and running fault-tolerant MySQL databases. Even still, it was a very close decision between spinning up our own infrastructure vs. integrating a third-party hosted solution.
So if you’re thinking of starting a WordPress site / blog from scratch, or if you don’t already have a decent amount of infrastructure and team knowledge around running scalable web servers, CDNs, and databases, you probably don’t want to be running your own WordPress. Instead, pick a hosted provider, point blog.yourdomain.com at it, and let them take care of the rest.
Batteries not included
The template we provide here is based on AWS’s existing WordPress Reference Architecture but drastically simplified to remove anything we didn’t need. In essence it only contains the parts relevant to the actual hosting of the WordPress instance itself. All the parts around CloudWatch alarms, CloudFront for CDN, setting various options via the CloudFormation console, and even integrating that hosting into our existing ELB infrastructure is not included.
So, in this template you can expect to find:
- MySQL database on Aurora
- Elasticache for memcached
- Auto-scaled web tier servers, with a single PHP version
- An ELB target group
That’s it. Nothing else. So if you need any of the following, you’re probably better off trying with the reference architecture
- CloudFront distribution setup
- Point-and-click setup using the CloudFormation console to choose PHP versions or other options
- A full CloudFormation stack including ELBs, security groups, and subnet setup
If you’re not sure what any of these things are, or if you’re unsure of whether you need them – again, you’re probably better off going with a third-party hosted system so you don’t have to worry about any of the details.
Making it fast
There’s a lot bunch more to hosting WordPress than standing up an Apache server and uploading the PHP files somewhere. It also needs to perform reasonably well and be resilient to failure. Here are a few of the things we did, both inside this CloudFormation template and in addition to it, to make that happen.
Aurora for MySQL
Aurora is AWS’s MySQL-compatible database engine which comes with better performance and availability out-of-the-box than running standard MySQL on RDS. The actual performance benefits of Aurora over standard MySQL are unlikely to be noticeable on a simple WordPress-based workload, but the convenience of durability and flexibility we get from Aurora was enticing.
Scalable and redundant web tier
When it’s optimised well, a WordPress installation should take fairly little load. In fact this whole blog should be able to run on a single t3.micro EC2 instance if we wanted it to. But we wanted to run this blog with the same philosophy as our other systems in AWS — that every single customer-facing web server should be behind a load balancer, in an auto-scaling group, with at least two instances running at all times. This means we can scale it up or down, and survive failures on a web server, without the whole blog disappearing from the internet.
EFS for shared file system
There are many different ways to scale a PHP-based application where you want to make in-place modifications to the source (e.g. in WordPress if you want to use the built-in plugin management and upgrade systems). One way would be to have a single “admin” server that can handle the read/write part of the workloads, and have the source replicated over to the public-facing web servers, which would treat it as read-only. However, we instead decided to run a shared filesystem on Amazon EFS so all the web servers have the same view of the files. There are plenty of reasons why you might notwant to do this, which we weighed up before deciding to run with this solution. EFS can be slow – especially in any sort of IO-intensive workload this can be absolutely killer. But with the various levels of caching we have in place we’ve not found this to be a problem. The benefit we get is a simplified system where all servers in our web tier look the same, and we can use all WordPress’s built-in features without any special treatment.
OPcache is PHP’s mechanism to cache the compiled opcode version of a file rather than having to continually read and re-interpret it whenever it’s needed.
W3 Total Cache & ElastiCache
W3 Total Cache is a WordPress extension that handles caching of pretty much every single thing in WordPress in a variety of ways. By setting it up to point at the ElastiCache node in the stack, WordPress very rarely actually needs to go to the MySQL database or do any expensive computation when serving a request. The plugin handles all the necessary processes of invalidating the cache whenever anything changes, so there’s no special settings to tweak or buttons to press when making changes such as publishing a new post.
W3 Total Cache & CloudFront
W3 Total Cache also includes options for offloading static assets such as theme files and images to a CDN such as Amazon CloudFront. We already have a CloudFront distribution set up on cdn.gosquared.com as a mirror of www.gosquared.com, so it was a simple matter of enabling the necessary settings, and now practically everything can be cached and served through this distribution.
Our priorities when making these choices
In making the choices around using EFS, W3 Total Cache, and others, our primary concern was making sure that we didn’t introduce any “magic” into the process of writing and editing on this blog. As far as our content-writers and editors are concerned, everything is just “normal” WordPress. It can be used the same as if none of these extra moving parts were there — cache invalidation is automatic; installation and updates for plugins is point-and-click in the WP admin UI, and there’s no special features they have to rely on. Our company’s business is not in WordPress hosting – any extra overhead to running this blog is, in AWS’s terms – undifferentiated heavy lifting.
There are definitely things we could do to further improve performance, resilience, or security, but many of these would sacrifice that convenience. So we’ve priorities making sure things are good enough in those regards but no more. Again, if we wanted something significantly better than where we’re currently at, we would instead seek out a third-party solution.
So here it is, the CloudFormation template for running a barebones scalable WordPress installation on EC2. It’s what we’re currently using for this blog, and it seems to be serving us reasonably well so far.
Could we do better?
There’s almost certainly plenty of ways this can be improved. We know we’re not experts in WordPress hosting and optimisation, which is why we’ve gone for barebones and simple here. But if you think there’s anything we can improve, or add, then let us know on twitter.