Low cost, scalable self-hosting on AWS.
In evaluating our options for hosting Celtic3d, we wanted something that would start off relatively low cost, but could be scaled up without having to completely re-building the site later and we had a rough idea of the sort of environment we wanted down the road.
We had already played about with an Elastic Load-balancer and some EC2 instances on AWS. It is straight-forward to get a test environment running with AWS Elastic Load Balancer where all traffic could be directed to a single address and then the load balancer fans the traffic out to a number of servers. Servers could be automatically added or taken away in response to a server fail or periods of fluctuating load. Instructions for getting an AWS account and for setting up an Elastic Load Balancer are well documented on the AWS site.
All good stuff and something we wanted to aim for in the longer-term. But how do we get this working with WordPress? And how do we start small with our costs under control, yet make some smart choices that give us flexibility later?
|A) Low cost hosting||Take the low cost web hosting bundled with domain provider / ISP..||Lowest cost||Inflexible. No control over server settings, or what is installed, or whether shared with others.|
|B) Microsoft Azure||Free web hosting on Azure.||Low cost. Fast to set up. Easy to add additional services like e-mail.||Less documentation and community support for open source.|
|C) AWS single server||Web and database on same server||Low cost. Fast to set up. Easy to add additional services like e-mail.||Scaling up requires reforming the whole solution. Hosting the Database on same server as the web is not recommended practice.|
|D) AWS single server + dB. ✔||AWS single server + separate dB + offload media and user files to S3.||Low(ish) cost. Fast to set-up, easy to (manually) scale from.||Needs manual intervention to scale.|
|E) AWS load balanced and autoscaled||AWS minimum configuration, load balancer + web server + dB + offload media and user files to S3.||Best set-up for future, but need enough load to justify setup effort and running costs of the load-balancer.||Medium cost, need to run a controller node for configuration of WordPress.|
|F) Fully automated scaling and code deployment on AWS||Hosting scales automatically and updates to web configuration can be pushed out in a publishing process.||Ultimate goal when working at high volumes.||Medium cost. Initial setup time detracts from time available to develop product line. Not needed if usage remains low.|
An Elastic Load Balancer costs around $18 per month. Not much, but we wanted to minimise the costs at the start, so this was stripped that out of our initial build.
Given our envisioned future state (multiple web servers with an Elastic Load Balancer in-front), we need a configuration where all dynamic data is kept in-sync regardless of which web server a user connected to. This would be very complicated to unpick later if we don't make some smart choices up-front.
- The database needs to be separate from the web server on it's own server, with each web-server connecting to it.
- Media files, also needed to be off-server so that the same file can be accessed no matter what server the user was connected to.
- WordPress will need to be configured to point to the database on a separate server and the location of the media files.
- A separate VPC for the solution so that we keep related resources together and don't mix traffic and security groups for other applications.
- Prefer multiple small servers that can be switched on and off quickly to big servers that cost a lot and under-utilized.
Let's look at how to set that up.
Refer to the AWS tutorial on how to Create a Web Server and an Amazon RDS Database. Conveniently for WordPress purposes, the tutorial uses Apache, PHP and MySQL as an example.
When reaching the MySQL choices, we would eventually want multiple Availability Zones and replication, but to begin with we are OK relying on database backups and accepting a measured risk that it would take us an hour or so to respond to a failure, configure a replacement database, and re-load the data from backup. To minimise the cost for early days, we are going with a single availability zone and no replication but will configure daily backups with a 20 day retention. You might have a different judgement on the risks and decide to go with a replicated database from the start.
There are a number of guides online on how to set-up and install WordPress, including how to connect to your EC2 instance using SSH. For the most part, the generic guidance will work. The key difference being that you need to specify the path to your RDS version of MySQL rather than a local MySQL database.
When accessing mysql from the command line, use the format:
mysql --host=<insert the full end-point to your database here> -u <insert-username> -p
You need to use the same format to configure the end-point for your MySQL database in your wp-config.php file on your web server, replacing the default reference to localhost to the full end-point of your database .
Offloading media files to S3 can be achieved with a WordPress plug-in "WP Offload S3" by Delicious Brains which is available in both free and paid versions. We started off with the intent of coding this ourselves, but having tried the free version of this plug-in, it works very well. In our case, we particularly wanted the paid version handling which handles the S3 permissions for downloadable content, so we upgraded. You may not have have that same requirement for your own site.
Map your domain
To use your site in a production context, you will need an Elastic IP Address and a DNS mapping of your domain to that address. You need to associate your Elastic IP address with a specific web server, and your domain mapping will point to that address. Because of the way WordPress dynamically creates pages, no matter what server you start on, WordPress will send you back to the main server with the attached Elastic IP address the first time a page refreshes.
The DNS name for your server and the Wordpress Address URL in the settings panel must match. Messing up the WordPress Address (URL) is a very quick way to lock yourself out of the web interface for your site. The WordPress.org site has instructions to help you recover if you have messed that up.
Take a snapshot
Once you have your WordPress configuration looking the way you like it, with all your bells and whistles added on. Take a snapshot of the EC2 instance so that you can got back to it at any time. You may also create an AMI (Amazon Machine Image) from the EC2 instance, so that you can quickly and easily launch more instances. Each new instance that you start will connect to the database to pull the content automatically, and pull media and images from S3.
If you have multiple servers running, you need to put the Elastic Load Balancer back in the picture before you can make use of the additional servers. Otherwise, WordPress will direct traffic back to the specific server with the mapped DNS name and IP address.
With the Elastic IP Address attached to the Load Balancer, the Load Balancer directs traffic to one of any number of web servers.
Quick and easy Development box (with a health warning)
If you need to run a development server alongside your production server, you can quickly create one from the AMI In that scenario, on the development server, you need to edit the wp-config.php file to hard-wire the server-name. Add the following two rows to your wp-config.php to match the public DNS of your server.
Warning: Be aware that you are still connected to the production copy of your database - so any and all configuration changes (including changes in the admin menus) will be instantly reflected in your production system. You should make a dump of your production database and import it into a new and separate development database. A reminder: your database connection is defined in your wp-config.php file.
Caution: Your development system also shares media files in S3 with your production system. This might be desirable, but be aware that renaming or moving files will break links on production.
My recommendation is that you create your AMI with the wp-config.php configured in the development state or without a wp-config.php file. That way you don't risk your production system by bringing up a new server and inadvertently changing production settings. To add a server to the production landscape, the correct wp-config.php file could be added in with a script.
The usefulness of AWS does not stop at the web-server / database and S3 components, we also make use of AWS SES for e-mail integration and are looking at CodeCommit for Source Code Management and we are tinkering with AWS Lambda to see if we can make use of that triggered by new objects being loaded into S3.
Some quick notes on pricing. Both EC2 and RDS offer Reserved Instances where you can pre-pay usage for a discount. We did the math and for our small EC2 servers pre-paying did not have much benefit, but for our RDS database, were able to save a significant amount by pre-paying for usage. It is well worth digging into the details to see what savings are possible.