Scalable WordPress with AWS Elastic Beanstalk

Since releasing Suzie, I’ve been asked the same question a lot — "How do I use Suzie with AWS/Elastic Beanstalk to make a scalable WordPress site?". With Suzie I purposely left a few vendor/providor specific features out, the idea was if you knew AWS well you’d adapt Suzie a little to suit your needs.

However, I’ve listened to feedback added a few AWS tweaks to help. In this tutorial, I’ll walk you through setting up a WordPress site to run on multiple EC2 instances while enjoying the simplicity of Elastic Beanstalk. We’ll be storing Media uploads and other assets on S3, using CloudFront as a CDN, and adding SSL & Varnish. If you wonder what sort of speed you can expect, our site — where you’re reading this — is using the same setup.

Costs

Don’t let the AWS pricing tables put you off – AWS is actually pretty good value for money. The setup we will create with this tutorial will run for around $30-40 per month, basing this of the assumption that most of the time the site operates with one instance.

Caveats

With most complex set ups there some drawbacks – perhaps deal breakers for some:

  • Plugins can’t be installed on the production site – plugins must be committed to git and deployed.
  • Some plugins may not be compatible, as there’s no permanent filesystem.

Here at Big Bite, we believe it to be good practice to test plugins on a staging server before moving them into production, so the first point isn’t a big concern for us. If a plugin requires that its settings are stored in a config file, simply committing that file to the repository solves the latter issue.

Note: Elastic File System can be an alternative solution to the above caveats but, as it’s not currently available in all regions, I haven’t included it.

AWS

Sign in to your AWS account, at which point you should be presented with the main AWS Dashboard. At first, it looks a little overwhelming seeing how many options there are, but you’ll barely touch most of it for this setup.

Once thing to note is the region in the top right — I’ve marked it in blue — make sure it’s the closest either to yourself or the receiver. Being in the UK, we’ll use Ireland.

AWS Dashboard

Route 53

The first thing we’ll tackle is your domain. Unfortunately, to use AWS with your root domain, you need use AWS Route 53 nameservers. Navigate to Route 53 → Hosted Zones → Create Hosted Zone. You will be given a box in which you need to input your domain. Let’s add bigbitecreative.com.

Route 53

Now it’s been created, you will be given a new set of nameservers. That should be enough for you to configure your domain’s nameservers with your provider.

Nameservers

S3

Let’s go through setting up a bucket to use with Suzie. For this example, I’ll set one up for to use with bigbitecreative.com. From the main AWS dashboard, navigate to the S3 section:

alt text

Select Create Bucket:

alt text

Let’s enter assets.bigbitecreative.com, select Ireland again, and click Create. Once created, we need to edit the bucket’s access policy and CORS config. We’ll start with the bucket policy by navigating to bucket properties and selecting Edit bucket policy.

alt text

Now we need to give everyone read access. Paste the following in, replacing bucket.name:

{
  "Version":"2012-10-17",
  "Statement":[
    {
      "Sid":"AddPerm",
      "Effect":"Allow",
      "Principal": "*",
      "Action":["s3:GetObject"],
      "Resource":["arn:aws:s3:::bucket.name/*"]
    }
  ]
}

And click Save. Just like you did with Edit bucket policy, select Add CORS Configuration and paste the following in:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Authorization</AllowedHeader>
        <AllowedHeader>Content-*</AllowedHeader>
        <AllowedHeader>Host</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

Now the last thing you will need is your access details to allow WordPress to upload files. At the top of window click on your name, then Security Credentials. On the left of the new screen select Users

alt text

Select Create New Users:

alt text

Let’s enter WordPress-BigBite and select Create:

alt text

Make a note of your Access Key ID and Secret Access Key, you’ll need them later.

alt text

It’s time to give that user access to your S3 bucket. Click Attach Policy

alt text

Select AmazonS3FullAccess then Attach Policy. It’s important to note that this gives this user access to all buckets, so you may wish to refine this later.

Elastic Beanstalk

Elastic Beanstalk is a simplified way to manage load-balanced EC2 instances. Select it from the AWS Dashboard and create your first Application. In this case Big Bite Creative.

Create App

Next you will be asked to create an environment and pick which type you want; in this case, we want Web Server Environment.

Create Environment

Time to configure the type of web server. Change the Predefined configuration to PHP and double check that Environment type is set to Load balancing, auto scaling

Environment Type

After that, you have the chance to upload a copy of your application, but it’s best to select Sample application for now.

Sample App

Moving on, you can specify a name for your environment, which will give you a URL to access the app. As this will be the production environment for the Big Bite Creative app, I’ll use bigbite-production.

Sample App

On the additional resources screen, you want to add an RDS, which will be your MySQL database.

RDS

There is isn’t much you need to configure on EC2; update the Instance type to t2.micro and specify an EC2 ssh key to use.

EC2 Settings

You will be given the option to add environment tags, but it’s best left until later.

Environment Tags

RDS doesn’t require much configuration, either; update the Instance class to db.t2.micro, and generate a decent Username & Password

RDS Settings

The next screen lets you set up some permissions — AWS docs cover this, so I won’t bore you with the details. Finally, you should reach a review screen:

Review Screen

Once you’re happy with your configuration, click Launch. This can take some time, so don’t worry. Once it’s complete, you should see a Health status of Ok.

Finish

SSL

Both your Load balancer (Elastic Beanstalk) and your CDN (CloudFront) will need to access to your SSL certificate. Please ensure you’ve got a wildcard SSL certificate for your domain.

First, you’ll need the AWS Command Line Interface. To install this, follow the official instructions here. Once that’s set up, open up your terminal and cd to the folder containing your SSL certificate. You will need your Public Certificate, Private Key, and Intermediate CA — for more on this, read. Below is an example of us uploading the SSL certificate — make sure you replace bigbitecreative with your domain.

$ aws iam upload-server-certificate --server-certificate-name bigbitecreative --certificate-body file://public.crt --private-key file://private.key --certificate-chain file://intermediate.crt --path /cloudfront/bigbitecreative/

Now, you’ll need to go back to Elastic Beanstalk to enable SSL. Select your app, then Configuration; scroll down a bit until you see Load Balancer, and click on the gear. Update Secure listener port to 443, select the SSL certificate you uploaded earlier, and click apply.

EB

CloudFront

CloudFront is a CDN service offered by Amazon and has to be easiest way to put a CDN in front of an S3 bucket. Select it from the AWS Dashboard and create your first Distribution.

CloudFront

Next, you will be asked to select which type you want; in this case we want Web

CloudFront

The next screen can seem a bit overwhelming, but we will tackle each section one at a time. In Origin Settings, you will find Origin Domain Name , which is where you start typing the name of S3 bucket. Next you have the Origin ID, which is a name to remember what the distribution is used for.

Origin Settings

Under Default Cache Behavior Settings we need to configure the headers. Scroll down until you see Forward Headers and change it to Whitelist, at which point a Whitelist Headers field should appear; we need to add the following headers to the whitelist:

  • Access-Control-Request-Headers
  • Access-Control-Request-Method
  • Origin

Whitelist

Lastly, we’ll move on to the Distribution Settings. In the Alternate Domain Names field, we will enter the domain we wish to serve our content from — cdn.bigbitecreative.com, in this case. We want to use SSL with this domain so, under the SSL Certificate section, select Custom SSL Certificate, then select the SSL certificate we uploaded earlier from the drop down.

SSL Certificate

Whilst that’s being created, we can link up cdn.bigbitecreative.com to our new distribution. On the main CloudFront screen with your list of distributions, note your domain name for recent one you created. It should be formatted as:

xxxxxx.cloudfront.net

Go to Route 53, and Create Record Set:

CDN Record

Ready to Deploy

Okay at this stage, with most of the set up done, we’re almost ready to deploy — we just need to configure our code. I’m assuming you already have Suzie set up; if not go check it out. To deploy to Elastic Beanstalk we need to install their CLI. It’s easier to install this with pip – if you do not have pip installed you can use Homebrew to install it:

$ brew install python

Or using easy install:

$ sudo easy_install pip

Let’s set up the AWS EB CLI:

$ sudo pip install awsebcli

Now we’re ready to move to our project directory and run:

$ eb init

You will be asked a number of questions. For regions we’re using Ireland, and for application we select Big Bite Creative. Once completed, you will see a new folder in your project: .elasticbeanstalk. This folder contains some basic information about your new app. The next step is to add configuration for Varnish, Composer etc. To save some time, I’ve created a repo with a folder you need to add to your project:

.ebextensions
https://github.com/getsuzie/aws

You will also find a file cron.yaml in the repo — which we’ll talk about in more detail further on — which you’ll need to copy across to the project as well.

We have a few edits to make before we’re ready to deploy. Open .ebextensions/app.config. We’ll start by replacing domain.com with our actual domain (bigbitecreative.com). After that find the line:

if (req.http.X-Purge-Token == "xxxx")

Generate yourself a token like P54Paqg6cC5OBDWp replace the xxxx so:

if (req.http.X-Purge-Token == "P54Paqg6cC5OBDWp")

Our next step is to set which IPs are allowed to clear Varnish. Find the section:

acl elb {
  "172.22.0.0"/20;
  "172.22.16.0"/20;
  "172.22.32.0"/20;
}

To get these IPs, you will need to revisit the AWS Dashboard and navigate to Select VPC. In here you will want to select Subnets on the left hand side. The values you are looking for are under the CIDR column. It is possible to restrict what IPs the EC2 will use and, in turn, tighten up who can clear Varnish; however, as we also require a token to clear the cache, it’s not strictly necessary.

VPC IPs

Now, the moment you’ve been waiting for: deploying. Run:

$ eb deploy

It will take some time, and don’t expect your site to work right away — we still have the environment variables to add. Once the deploy is finished, visit the AWS Dashboard and go to Elastic Beanstalk. Select your application, go to Configuration, then scroll down to Software Configuration. First, let’s update Document root to /public. Under Environment Properties you will see a list of fields that need completing, most of which are straightforward. The following are AWS/Varnish specific:

VARNISH_AWS=true
VARNISH_AWS_LB=
VARNISH_AWS_REGION=eu-west-1
VARNISH_ENABLED=true
VARNISH_PATH=https://bb3.bigbite.so/.*
VARNISH_TOKEN=P54Paqg6cC5OBDWp

Most are easy enough to understand; the one which requires a little more work is your load balancer name VARNISH_AWS_LB. Let jump back into AWS Dashboard and select EC2. At the top you should see a list of options, select Load Balancers.

EC2

Next we’ll copy the name of load balancer:

LB

And update our environment variable:

VARNISH_AWS_LB=awseb-e-y-AWSEBLoa-aabbccddeeff

Remember earlier, when we added a cron.yaml to our project? We now need to set that up. Open it up in your editor and find the line:

url: "/?suzie=scheduler&token=EIE1AsOQtvYY2yas"

We need to set up our token for this, so please generate a new one like 5DTIWmtGM9wPc43w, then update the line:

url: "/?suzie=scheduler&token=5DTIWmtGM9wPc43w"

There’s a few environment variables to update to match:

SCHEDULER_ROUTE=true
SCHEDULER_TOKEN=5DTIWmtGM9wPc43w

Now we’re ready to deploy again.

$ eb deploy

Closing

I hope this tutorial is enough to make you realise AWS isn’t that hard to configure, and the amazing performance it offers is worth the time spent. If you happen to know a better way to set up WordPress on AWS, please drop me email. Thanks for reading.

Want to know a little more about us?

We are a friendly bunch and love talking all things WordPress. Whether you’re using one of our open source projects, want to discuss a blog article or hire us for your next project, we would love to hear from you.

Contact us