Getting Started with WordPress and Elastic Beanstalk

Updated Jan 25, 2018

This article describes how to serve a WordPress application from Amazon Web Service’s Elastic Beanstalk, using Amazon RDS for the MySQL database and S3 for static media files. The hope is that this article is accessible to a large audience, though it assumes the following:

  • Basic familiarity with WordPress.
  • An active AWS account. If you do not have an account, you can get started here.
  • Access to a Bash shell (eg, Terminal in Mac OSX).

Click on the icons to view screenshots of related steps.

Table of Contents

Create an RDS instance

WordPress requires a MySQL database that we’ll create using Amazon RDS. While it’s possible to create a database as part of an Elastic Beanstalk instance, creating our own standalone RDS instance offers greater flexibility and means data won’t be lost if we terminate our Elastic Beanstalk instance.

Open the RDS dashboard, click “Instances” in the menu on the left , and click the “Launch DB instance” button . You will be guided through four configuration pages detailed below.

1. Select Engine

Choose “MySQL” and click the “Next” button.

2. Choose Use Case

Choose “Production – MySQL” and click the “Next” button.

3. Specify Instance Details

There are a number of settings here that will affect your database performance and pricing. The below suggested configuration is really designed to get a test site up and running; modify the below selections accordingly for your use case.

Instance specifications

DB instance class Choose d2.t2.micro
Multi-AZ deployment Choose no
Storage type Choose General Purpose (SSD)
Allocated storage Enter 20GB

Settings

DB instance identifier This can be any name you choose, eg, “myDbInstance”.
Master username Enter a DB username. You’ll need this later.
Master password Enter a DB password. You’ll need this later.

Click the “Next” button.

4. Configure advanced settings

Network & Security

Public accessibility Choose no
VPC security groups Choose Create new VPC security group

Database options

Database name Can be anything but “wordpress” works. You’ll need this later.
Database port Confirm that it’s set to 3306.

Click the “Launch DB Instance” button.

Above we’ve set publicly accessible to “no”, meaning that the database will only be accessible by instances in the same VPC security group. Later we’ll add Elastic Beanstalk to the security group so WordPress can access the database.

It will probably take 10 minutes or so for your instance to launch. Continue on to the next section while this is in progress.

Create an S3 bucket for media files

By default WordPress stores your media files (eg, images, pdfs, etc.) in the file system. But any uploaded files will be lost when you deploy a new application version to Elastic Beanstalk. The simplest solution is to instead store your media files in an S3 bucket, which has other advantages as well. This can be achieved using the plugin WP Offload S3. Once activated and configured, WordPress will store media files in your S3 bucket.

Create the S3 bucket

Go to the S3 dashboard and click the “Create Bucket” button.

Bucket name and region Can be anything but “wordpress-uploads” works. Choose a region close to your target audience.
Set properties You can accept the defaults.
Manage public permissions Choose Grant public read access to this bucket.

Create a new IAM policy

Create a new policy granting permissions to your S3 bucket. Go to the IAM dashboard, select “Policies” from the menu at left , and click the “Create Policy” button .

Select the “JSON” tab and copy and paste the following. Replace “YOUR-BUCKET-NAME” with your S3 bucket name.

IAM Policy Download Copy
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:DeleteObject",
        "s3:GetObject",
        "s3:GetObjectAcl",
        "s3:ListBucket",
        "s3:PutObject",
        "s3:PutObjectAcl",
        "s3:GetBucketLocation"
      ],
      "Resource": [
        "arn:aws:s3:::YOUR-BUCKET-NAME",
        "arn:aws:s3:::YOUR-BUCKET-NAME/*"
      ]
    }
  ]
}

This policy will grant access to our S3 bucket:

  • Line 2 This is versioning internal to AWS.
  • Line 5 We want to allow the following actions on the resource.
  • Lines 7-13 Allow the user to get, put, and delete files in our bucket. “s3:GetBucketLocation” is included because the WP Offload S3 plugin requires location access.
  • Line 16 Allow the actions on the bucket itself.
  • Line 17 Allow the actions on all files within the bucket.

Click the “Review Policy” button at bottom and create a name for your policy.

Create a new IAM user

Create a new IAM user to provide access to your S3 bucket. Go to the IAM dashboard, select “Users” from the menu at left , and click the “Add User” button .

User name Enter something descriptive, like “wordpress-s3”
Access type Choose Programmatic access
Permissions Select Attach existing policies directly and add the policy you created in the previous step.

Once the new user is created you should be presented with an Access Key Id and Secret Access Key. Store these values in a safe place as you will need them later .

Create your source bundle

We need an application to deploy to Elastic Beanstalk. In this section we’ll create the needed files to compose the source bundle we’ll upload to Elastic Beanstalk.

Download WordPress

Download the latest version of WordPress or install it from the command line:

curl https://wordpress.org/latest.tar.gz | tar -xvz

You should now have a directory named wordpress.

Install plugins

We need to install the WP Offload S3 plugin that we’ll be using to store media files in S3. Go to the plugin page and download the latest version. Unzip the package and save the plugin to wordpress/wp-content/plugins/.

The WP Offload S3 plugin requires the Amazon Web Services plugin. Download this plugin as well, unzip the package, and save to wordpress/wp-content/plugins/.

Create wp-config.php

Delete wordpress/wp-config-sample.php and create a new file wordpress/wp-config.php:

wp-config.php Download Copy
<?php
 
// AWS configuration for WP Offload S3.
define('DBI_AWS_ACCESS_KEY_ID',     $_SERVER['AWS_ACCESS_KEY_ID']);
define('DBI_AWS_SECRET_ACCESS_KEY', $_SERVER['AWS_SECRET_ACCESS_KEY']);
 
// MySQL configuration.
define('DB_NAME',     $_SERVER['RDS_DB_NAME']);
define('DB_USER',     $_SERVER['RDS_USERNAME']);
define('DB_PASSWORD', $_SERVER['RDS_PASSWORD']);
define('DB_HOST',     $_SERVER['RDS_HOSTNAME'] . ':' . $_SERVER['RDS_PORT']);
define('DB_CHARSET',  'utf8');
define('DB_COLLATE',  '');
 
// Authentication keys and salts.
define('AUTH_KEY',         $_SERVER['WP_AUTH_KEY']);
define('SECURE_AUTH_KEY',  $_SERVER['WP_SECURE_AUTH_KEY']);
define('LOGGED_IN_KEY',    $_SERVER['WP_LOGGED_IN_KEY']);
define('NONCE_KEY',        $_SERVER['WP_NONCE_KEY']);
define('AUTH_SALT',        $_SERVER['WP_AUTH_SALT']);
define('SECURE_AUTH_SALT', $_SERVER['WP_SECURE_AUTH_SALT']);
define('LOGGED_IN_SALT',   $_SERVER['WP_LOGGED_IN_SALT']);
define('NONCE_SALT',       $_SERVER['WP_NONCE_SALT']);
 
// Other WordPress defaults.
$table_prefix = 'wp_';
define('WP_DEBUG', false);
if (!defined('ABSPATH'))
define('ABSPATH', dirname(__FILE__) . '/');
require_once(ABSPATH . 'wp-settings.php');

The configuration file references several properties of $_SERVER that we’ll define in an Elastic Beanstalk configuration file in the next step.

Create Elastic Beanstalk configuration files

Create a new folder wordpress/.ebextensions. Elastic Beanstalk looks for configuration files in this directory when deploying an application. Create a new file wordpress/.ebextensions/env.config:

env.config Download Copy
option_settings:
  aws:elasticbeanstalk:application:environment:
    AWS_ACCESS_KEY_ID: 'placeholder'
    AWS_SECRET_ACCESS_KEY: 'placeholder'
    WP_AUTH_KEY: 'placeholder'
    WP_SECURE_AUTH_KEY: 'placeholder'
    WP_LOGGED_IN_KEY: 'placeholder'
    WP_NONCE_KEY: 'placeholder'
    WP_AUTH_SALT: 'placeholder'
    WP_SECURE_AUTH_SALT: 'placeholder'
    WP_LOGGED_IN_SALT: 'placeholder'
    WP_NONCE_SALT: 'placeholder'
    RDS_DB_NAME: 'placeholder'
    RDS_HOSTNAME: 'placeholder'
    RDS_PORT: '3306'
    RDS_USERNAME: 'placeholder'
    RDS_PASSWORD: 'placeholder'

You’ll have to replace all the ‘placeholder’ values with your own values.

  • Lines 3-4 Fill with the values generated when creating the IAM user for S3 above.
  • Lines 6-13 These are keys and salts used by WordPress for security. You can use this website to generate keys and salts. Note that backticks (`) in the values will cause Elastic Beanstalk to fail. Once you generate the keys and salts, replace any backtick marks with other characters.
  • Lines 15-19 These are related to the RDS instance you created earlier. RDS_DB_NAME is the name you chose for the database. RDS_USERNAME and RDS_PASSWORD are the values you entered for your credentials. RDS_HOSTNAME is the URL for the database. You can find this by going to the RDS dashboard, selecting your instance, and scrolling down to the “Connect” panel where you’ll see the endpoint.

Verify your source files

Your source directory wordpress should now look roughly like the following. New files and directories are highlighted:

.ebextensions
env.config
index.php
license.txt
readme.html
wp-activate.php
wp-admin
wp-blog-header.php
wp-comments-post.php
wp-config.php
wp-content
index.php
plugins
amazon-s3-and-cloudfront
amazon-web-services
index.php
themes
wp-cron.php
wp-includes
wp-links-opml.php
wp-load.php
wp-login.php
wp-mail.php
wp-settings.php
wp-signup.php
wp-trackback.php
xmlrpc.php

Create zipped bundle

To deploy the application to Elastic Beanstalk we zip all the members of the wordpress directory into a bundle. Note that we zip all the files in the directory, not the directory itself. In the console, navigate to inside the wordpress directory and enter the following command:

zip -rq artifact.zip .

This should create a file wordpress/artifact.zip.

Create Elastic Beanstalk application

Go to the Elastic Beanstalk dashboard and click “Create New Application” in the upper right . You will be guided through the following pages:

Application Information

Application name Enter something descriptive, such as “wordpress”. Click “Next” button.

New Environment

Click Create web server.

Environment Type

Predefined configuration Choose PHP.
Environment type Choose Load balancing, auto scaling.
Click “Next” button.

Application Version

Source Choose Upload your own and select the wordpress/artifact.zip file you created earlier.
Click “Next” button.

Environment Information

Environment name Enter a name for your environment. Can be anything.
Environment URL Can be anything unique to AWS.
Click “Next” button.

Additional Resources

Don’t select any additional resources for the environment. Click the “Next” button.

Configuration Details

Instance type Choose t1.micro. As with the RDS configuration, you can choose a different tier depending on your use case. This selection is just to get an environment up and running.
EC2 key pair You don’t have to select a key pair but it’s a good idea when in production so you can check in on your EC2 instances and tunnel into your RDS instance. Check out this link from AWS for more information on key pairs.
Leave the rest of the default values and click the “Next” button.

Environment Tags

You don’t need to add any tags. Click the “Next” button.

Permissions

Choose to let AWS create new roles for the instance profile and service role. Click the “Next” button.

Review

Review your selections and click the “Launch” button. It will take a few minutes for the application to launch. You can continue to the next section while you’re waiting.

Next steps

Check out the post Automating WordPress Deployment to Elastic Beanstalk to learn how to automate the build and deployment process. This will let you make changes to your local WordPress development environment and deploy a new application with a single command.

Hopefully all of the above worked and you’re off and running, but if not feel free to post questions in the comments section below.

Comments Leave a comment

  • Arthur
    Also, I have read others on this topic suggesting that EFS (managed file service) should be used as the file storage solution for all the wordpress files (including core wordpress files, themes, plugins, etc). Even Amazon recommends this as best practice: https://aws.amazon.com/blogs/architecture/wordpress-best-practices-on-aws/. According to this, one common EFS deviceMore would contain the common wordpress files accessed by the auto-scaling group of ec2 instances. I guess changes to these files would just transferred via FTP to the EFS device, instead of via EB CLI as a zip file. Can you please provide your opinion on this?
    • EssyCodeModerator
      Ooh, this is new since I made this post. I'll have to check it out but, at the risk of making my own post irrelevant I'm inclined to say go with whatever they say are best practices if reasonable. AWS probably has a few more resources committed to this thanMore essycode.com :) Thanks for finding this, I may be updating this post in near future.
  • Arthur
    Great work! One question is how to deploy database changes. Sometimes, a plugin installation or update will modify the structure of the database, or add new entries to some tables. If these modifications are made to database in the dev or local environment, how should they be deployed to theMore production? I know you recommend a RDS database separate from the Elastic Beanstalk application. But the problem still remains. How do we keep the databases in sync?
    • EssyCodeModerator

      Hi Arthur -

      Thanks for the comment. Unfortunately I don't have a good answer for your question about keeping databases in sync -- in practice, any time I make a change via the admin pages that affects the database I have to make the same change both in my test or local environment and again in production. For plugins where you're just changing settings this isn't that big a deal and manageable. In other cases, however, such as with WooCommerce where you're changing products and recording transactions, I'll periodically clone the production database to my dev environment. In past I've set up scheduled (daily) tasks to automate the process. So in short, it depends on your use case but I don't have a good answer. Would love to hear from anyone else though!

  • Nomi
    Thanks for the excellent guide, I'm in the process of moving my company's website to AWS EB. The tutorial pretty much covers everything the only thing I'm confused about is my plugins and theme files. Should I upload them to S3 as well? Do note I will be constantly makingMore changes to theme files and plugins will need to be updated. We run woocommerce so that is a consideration as well. What do you recommend in this case?
    • EssyCodeModerator

      Hi Nomi - Glad the post was helpful. I don't use S3 for plugins and themes but instead include them in a single source bundle that is deployed to Elastic Beanstalk. I think this is preferable to using S3 since you can have a single deployment and don't have to worry about S3 caching preventing changes from propagating.

      You can actually see the build script for this site: https://github.com/essy2017/essy-code-build. So to deploy the site I run deploy.sh, which in turn calls build.sh, which bundles WordPress, my plugins, and theme into a single zip file that is deployed to Elastic Beanstalk. The build script does load a file config.txt that is not committed to source (since it includes information about my local filesystem). It defines a variable "theme_src" that points to my local theme directory. eg, theme_src=/../../wp-content/themes/mytheme. The plugins are included in the source (see /assets) but could also be handled in a similar fashion to the theme, ie, copied from somewhere in your local environment. Hopefully this helps but let me know if otherwise.

  • Russell
    Great tutorial you've put together here. Unfortunately, it doesn't seem to work. I've deployed other EB apps and it has worked. The database is running, no errors in the log, but I just get a blank page when I go to the address.
  • XtMaze

    Hi, very nice post with clear explanation..While everything seems to make sense, i still got some errors...

    Don't know if it's because of what you mention above==>>Note that backticks (`) in the values will cause Elastic Beanstalk to fail. Once you generate the keys and salts, replace any backtick marks with other characters.

    This should be replaced by what exactly? Any character, wouldn't that make my the actual generated "Key" invalid??

    • EssyCodeModerator
      Hi, glad you liked the post. Hopefully it is the backticks that are the problem. You can replace them with any non-backtick character, e.g., "R", "r", "1", etc. There's nothing special about the key itself except for the length (64 characters) and the fact that it's a secret and hardMore to guess, so it will still be valid if you replace the backticks. Let me know if that doesn't solve the problem, I'm happy to help further.

Leave a comment