WordPress and AWS CloudFormation

When I first started working with WordPress hosted on AWS I began by deploying an EC2 instance and running a LAMP stack on this instance, this is of course fine when you first start out.  I then migrated the database off of the local server and onto an RDS instance and the media into S3.  From there I wanted a better way to manage the large numbers of sites that we deploy so we moved the server deployment into CloudFormation and started using other services such as CodeDeploy, Elastic Load Balance, Auto Scaling etc.

In this blog post I wanted to cover how to approach deploying your first WordPress site using CloudFormation and provide some extra information and tips not included with the example templates that I have linked below.  This is information I would have found useful when I first started and is aimed at people new to AWS and CloudFormation.

Example Application Frameworks

Example Sample Solutions

At this point I would also recommend reading the following from Amazon.

WordPress Best Practives On AWS

These examples are very good but not 100% complete, which is to be expected, even my example is not fully functional.  Instead it should act as a guide for your own template.  We will use the WordPress scalable and durable example as the basis of the discussion in this blog post.

What changes should we make?

Now we have downloaded the example template and read about best practices, what do we need to think about changing and what are some import considerations missing from it?

  1. Remove RDS from the template
  2. Pull sources and files from S3 including plugins
  3. Disk Space
  4. .htaccess file
  5. PHP upload_max_filesize
  6. File permissions

1. Remove RDS from the Template

I would highly recommend removing RDS setup from the template and setting this up separately.  This is because when you delete a CloudFormation stack all assets are destroyed, this would include your database.  By setting up both RDS and S3 buckets separately you can delete and recreate your stack at will without fear of loosing the database or media.

It can also save money in the early days as you can point multiple CloudFormation stacks at the same RDS server.

2. Pull sources and files from S3 including plugins

The example templates pulls the latest version of WordPress directly from the WordPress servers.

"sources" : {
 "/var/www/html" : "http://wordpress.org/latest.tar.gz"
 },

Running the latest version of WordPress is essential, however pulling a specific version from an S3 bucket gives you greater control over which version you run.  It allows you to spin up testing stacks running different versions allowing you to check the compatibility or any themes or plugins before pushing them to live.  It also removes a dependency on an external site.

To achieve this you will need to add some resources to the template.

  • AWS::IAM::User
  • AWS::IAM::AccessKey
  • AWS::S3::BucketPolicy
  • AWS::CloudFormation::Authentication

More details on these can be found here and in the example template attached to this blog post.

Once you have added these you can modify the Parameters and Sources sections to include the following:

"BucketName" : {
 "Description" : "Name of bucket containing source files",
 "Type" : "String"
 }
"sources" : {
 "/var/www/html" : { "Fn::Join" : ["", ["http://", { "Ref" : "BucketName" }, ".s3.amazonaws.com/wordpress-4.5.3.zip"]]}
 },

You can use the same process for plugins and themes as well, for example:

"sources" : {
 "/var/www/html/wp-content/plugins" : { "Fn::Join" : ["", ["http://", { "Ref" : "BucketName" }, ".s3.amazonaws.com/plugin.zip"]]}
 },

This is very important as you will need a plugin to manage media on S3.  You can’t just store media on the local disk as it will not be synced between servers and lost if you replace your server for any reason.

Lastly I would add the following line to the WebServerGroup section below AWS::AutoScaling::AutoScalingGroup:

 "DependsOn" : "BucketPolicy",

This line will ensure that the various policies needed for the S3 authentication are created before the instances are created and try to pull the source files.

Lastly use a separate bucket for your sources and files not the same bucket as your WordPress media.

3. Disk Space

Amazon Linux has a default root volume size of 8Gb, not really large enough for an active site.  You also have to remember that S3 plugins such as W3 Total Cache don’t upload directly to S3 instead users upload to the server and then media is moved to S3.  If you only allow small media uploads this might not be an issue but if you allow video or larger uploads this could not be enough.

Depending on the instance and OS your root volume is likely to either be /dev/sda1 or /dev/xvda.

To create a EBS root volume for your EC2 instances add the following code to the properties section within the “LaunchConfig”.

"BlockDeviceMappings" : [
{
"DeviceName": "/dev/xvda",
"Ebs": {
"VolumeSize": "40",
"VolumeType": "gp2"
}
}
],

Remember this EBS volume will be destroyed when the server is terminated so don’t store anything that isn’t created by your template on there.

4. .htaccess file

In the example template they do not include a .htaccess, this is a must for WordPress especially if you are running a multisite install.  So you should create one and upload it to your S3 bucket.  You can then use the files section of the template to pull in this file to your WordPress install, which something like the following:

"/var/www/html/wordpress/.htaccess":{
"source": { "Fn::Join" : ["", ["http://", { "Ref" : "BucketName" }, ".s3.amazonaws.com/htaccess"]]},
"mode":"000644",
"owner":"apache",
"group":"apache"
},

There are plenty of sites out there that discuss what should be in your htaccess file, a good place to start is here.

5. PHP upload_max_filesize

Another consideration at this point is your PHP config.  By default PHP on Amazon Linux is configured with a upload_max_filesize of only 8Mb.  If you want to allow large uploads you will need to change this.

In another blog post on Increasing the WordPress File Size Upload Limit I discuss the various methods for making this change.  You can pick the solution that best suits your and pull in the correct file from S3.

6. File permissions

One of the most important areas not discussed in the example templates is file permissions, ownership and security.  You will want to change these from the default set during the CloudFormation setup, to do this you will need a script.  This script can be created and run by CloudFormation.

Whats in the script? Something like the following:

#!/bin/bash -ex

cd /var/www/html/wordpress/
chown -R apache:apache *
find . -type f -exec chmod 644 {} +
find . -type d -exec chmod 755 {} +
chmod 400 wp-config.php

You can also use this script to setup things like Amazons Cloud Watch monitoring scripts or other third party monitoring agents such as DataDog.

How to run the script?

Cloud formation can do this for you.  I copy to the script to the server then use the commands section to run it.

"/tmp/myscript.sh":{
"source": { "Fn::Join" : ["", ["http://", { "Ref" : "BucketName" }, ".s3.amazonaws.com/myscript.sh"]]},
"mode":"000700",
"owner":"root",
"group":"root"
}

and run it…

"commands" : {
"02_myscript" : {
"command" : "/tmp/myscript.sh"
}
},

Scripts like this are very powerful and can do pretty much anything you want.

Conclusion and Example

The above should be enough to get you started in deploying a WordPress site using CloudFormation.  I has attached an example template to this blog post as well, which will demonstrate how to setup a lot of the examples within this blog, feel free to use it as a reference in creating your own CloudFormation template.  It is not a fully functional template that you can just deploy, so please bear that in mind when using it.

View Example Template

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s