Otreva currently supports Internet Explorer 9 and higher. You should consider upgrading to get all intended functionality. ×
otreva.com
how to reploy wordpress to amazon web services AWS elasticbeanstalk

Deploying WordPress to Amazon Web Services AWS EC2 and RDS via ElasticBeanstalk

in Blog

A common question we get asked is how do I ensure my WordPress application can scale with an influx of demand? What can I do do ensure high uptimes and great performance?

As a member of the AWS Partner Network, our typical response is to build an auto-scaling, self healing cloud application using AWS ElasticBeanstalk. AWS Elastic Beanstalk is an even easier way for you to quickly deploy and manage applications in the AWS cloud. You simply upload your application via GIT, and Elastic Beanstalk automatically handles the deployment details of capacity provisioning, load balancing, auto-scaling, and application health monitoring. But at the same time, you retain full control over the AWS resources powering your application and can access the underlying resources at any time via ElasticBeanstalk.

Sounds great right? We think so too.

The one consideration is that users have to understand the need for their application to be stateless. This means you can no longer upload photos to the server itself, you can’t install plugins on the server, and you don’t want anything to change on the server without it first being changed locally via your GIT repository. Luckily, there are a few plugins to help ease this pain, and they allow you to still use the default WordPress media uploader and browser yet instead of storing media on the server, you can configure an AWS S3 (Simple Storage Service) bucket to retain all the images off the server.

So why is stateless so important?

Auto-scaling, self-healing applications rely on this single understanding of stateless design. The reason an application must be stateless is because if it needs to scale up (add more servers behind it), it cannot be inconsistent between server instances. The application code on server instance A must be exactly the same as server instance B. This is why your repository should only contain your base PHP files, theme files, plugins and basic WordPress application files. Media like images, videos and PDFs should NEVER be kept in your GIT repository unless they are needed for your theme. So for example if you have a background image that is used throughout the site, that may be an exception that can live in your theme’s image folder inside the GIT repository. However images that go in blog posts, pages, etc should be hosted on a storage service like AWS S3. Once we upload the images to S3, we get a URL back that can live in the database which would be shared by all instances that are deployed. There are many more considerations to stateless application design which are outside the scope of this post.

Prerequisites:

  1. An AWS Account with Billing Setup
  2. GIT – Version Control System
  3. MySQL WorkBench (if migrating database – Not needed for fresh install)
  4. WordPress Install on Local Web Server
  5. WordPress wp-config.php file
  6. AWS ElasticBeanstalk command line tool

Step 1: Setup Local Web Server

This tutorial assumes you know how to install WordPress locally on your machine via a local web server like XAMPP, MAMP, LAMP or other apache based server. So once you have a folder setup and your files ready to be accessed by your local web server (localhost) you will be ready to proceed from here.

Copy all of the WordPress files into your local folder so they’ll be ready to be accessed by your local web server. Don’t setup a local database. At the time of this writing, we’re install WordPress 3.6.1. If you’ve done everything correctly so far, you should be able to access your files and see a screen like this:

Wordpress create a configuration file

Step 2: Configure AWS ElasticBeanstalk and WordPress for the Cloud

If you made it here, great. The next few steps will be slightly different from the typical WordPress install so try not to deviate.

Config AWS ElasticBeanstalk

  1. Login to your AWS Account and go to ElasticBeanstalk and click Create Application which should bring you to a screen similar to below. Name your application here:
    aws-beanstalk-step1
  2. Next, select PHP as your platform and leave the environment type as Load Balancing, Autoscaling.
    aws-beanstalk-step2
  3. Leave sample application selected for now:
    aws-beanstalk-step3
  4. Give your environment a different name if you want and change the subdomain if you want and check the availability. We will later be creating a CNAME in your DNS for the Environment URL so it isn’t a huge deal for what you name it. It won’t be a public URL.
    aws-beanstalk-step4
  5. Ensure you check create an RDS DB instance.
    aws-beanstalk-step5
  6. The default settings on this page are probably fine for most installs and they can all be updated later so we won’t go into detail about them for now.
    aws-beanstalk-step6jpg
  7. Next we’ll need to configure our MySQL database here. Again most of the default values are OK to start and you can always update them later. Most WordPress sites we see need a database well below the 5GB minimum but it is a minimum for AWS RDS so use 5GB unless you have a larger database. Also pick a very secure username and password here and save them for the later steps. You can also pick multiple availability zones if this is an enterprise application that needs to ensure 100% uptime but be aware costs will tip $50 a month for DB usage only.
    aws-beanstalk-step7
  8. Lastly, review everything and create the app. You should see a screen like below. Wait until the environment health is green to proceed to the next steps.
    aws-beanstalk-step8
  9. Next, in the AWS console, go to Services > RDS. Since this is likely your first AWS RDS DB, you should be able to click security group on the left and see only one security group that looks something like “awseb-e-xxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxx”. Edit that security group. You should see a best estimate of your IP Address that Amazon gives you in the small text in the yellow box. Enter that or your correct IP Address with subnet mask. This allows our local WordPress app to access our AWS RDS Cloud Database. We will be sharing one database between our local and AWS EC2 Cloud Environment for this tutorial.* Note: VPC Users Setup Security Differently

    aws-beanstalk-step9

  10. Now while still in the RDS console, switch back to instances and copy the Endpoint field WITHOUT :3306. We’ll want this endpoint URL as well as the username and password we created above for the WordPress install. Also note the Database Name which is normally ebdb.
    aws-beanstalk-step10

Step 3: Install WordPress

  1. Switch back to your browser and go to your configuration. We are now ready to create a configuration file.
    Wordpress create a configuration file
  2. Fill in the database name as found in the RDS console, which is normally ebdb, the endpoint from above as Database Host (remember without :3306) as well as the username and password you created. You can leave the prefix as wp_.
    create-a-config2
  3. Now click install and you should be up and running! Finish the install just as any other WordPress Install
    create-a-config3
  4. But wait, we’re only halfway done!

Step 4: Local WP Conifg and GIT Repository setup

  1. Create a new file: local-config.php and put it in the root folder where wp-config.php is. Make sure to change to whatever your local hostname is below where you can access your install.
    
    <!--?php define('WP_HOME','http://localhost/elasticbeanstalk'); define('WP_SITEURL','http://localhost/elasticbeanstalk'); ?-->
    
  2. Open wp-config.php to edit. Add the following code just before define(‘DB_NAME’, ‘ebdb’); This allows us to browse our local code under our local hostname while still using a remote database. This step is very important.
    if ( file_exists( dirname( __FILE__ ) . '/local-config.php' ) ) {
        include( dirname( __FILE__ ) . '/local-config.php' );
    }
    
  3. Create another file called .gitignore in the same location (root). This file will allow us to ignore files from our GIT repository that we need locally but that we don’t want in the repo.
    #################
    ## WordPress
    #################
    .git-rewrite/
    local-config.php
    .elasticbeanstalk/
    *.local.*
    *.remote.*
    *.base.*
    *.backup.*
    *.orig*
    
    #ElasticBeanstalk Configs we won't need in the repo
    AWSDevTools/
    AWSDevTools-OneTimeSetup.bat
    AWSDevTools-RepositorySetup.bat
    scripts/
    AWSDevTools-RepositorySetup.sh
    
    #These are to ignore media files which we again DON'T want in our GIT Repo.
    wp-content/uploads/
    wp-content/cache/
    

Step 5: Initialize your GIT repo

This assumes you already have GIT setup on your local machine.

  1. From the command line, CD to your local folder where all the website files are and make sure you are in the root where the wp-admin, wp-content, wp-includes folders are.
    git init
  2. Add all the local WP Files to a GIT Repository. Note git will automatically ignore the files we put in our .gitignore file above.
    git add *.*
  3. Finally commit them to the GIT Repository.
    git commit -m "Committing my initial WordPress site into this repo"

Step 6: Push this site up to AWS Beanstalk

Now we finally have our local site in our local GIT Repository and we’re ready to push it up to ElasticBeanstalk to make the site live. You should probably read this first to get a better understanding of what we’re about to do. We’re going to use a slightly slimmed down version of the above to help you get going.

  1. Create a folder in the root of our site called .elasticbeanstalk. Inside that folder we’ll make two files.
    1. config
      [global]
      ApplicationName=YourApplicationNameFromAWSConsole
      AwsCredentialFile=.elasticbeanstalk/aws_credentials
      DevToolsEndpoint=git.elasticbeanstalk.us-east-1.amazonaws.com
      EnvironmentName=EnvironmentNameFromAWSConsole
      Region=us-east-1
      

      aws-beanstalk-step11

    2. aws_credentials
      These come from your AWS Console Account. Create a new user under IAM Console to get these:

      [global]
      AWSAccessKeyId=AKIAxxxxxxxxxxxxxxxxxxxxx
      AWSSecretKey=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
      
  2. Go and download the AWS command line tools. Then copy the content inside the Windows folder of that download to your root folder where WP lives. If on Linux or OSX, use that folder instead.
  3. Add and commit everything we just did to the GIT Repository.
    git add *.*
    git commit -m "Adding AWS Configs"
  4. Finally let’s push the Repo up to Beanstalk.
    git aws.push
  5. If all went well, you should be able to see the environment updating inside the AWS Console.

Done! Well with the deploy process.

Now your basic WordPress application is up on AWS but keeping it stateless means you must always install plugins locally, make changes locally to theme files, and otherwise change the sources code in the repo locally and then add, commit and push to AWS. However it allows us to use the power of AWS cloud infrastructure to create self-healing, auto-scaling apps. Although out of the context of this article, you can easily use plugins like Amazon S3 and CloudFront along with Amazon Web Services to send your media files to S3 and keep your codebase free of media. Upload the later plugin first.

Good luck and feel free to leave comments below with questions. If you’ve never installed WordPress on a basic shared server or local server, you may not want to attempt this until you have done that.

  • Pingback: Deploying WordPress to Amazon Web Services AWS EC2 and RDS via ElasticBeanstalk | Web Tech News

  • Israel

    Michael,

    Thanks for this you saved me a lot of time. I got one small problem when I click on login it logs me to the remote site no to my local installation. Do you know why that is?

    Thanks,

    Israel

    • http://www.otreva.com Otreva

      Related to WP_SITEURL as you mentioned. I edited in step 4.

  • Israel

    Michael,

    On Step 4, point 1 you have WP_HOME twice. I changed the second to WP_SITEURL and everything worked.

    Thanks for the tutorial.

    Israel

    • Michael Averto

      Great catch Israel, I’ve updated. Thanks for the comment.

  • mc3

    Whats the best way to have a separate databases for staging and production?

  • Arnaud Levy

    a “c” is missing in .gitignore, no?
    .elastibeanstalk/

    • http://www.otreva.com Otreva

      Yep, nice catch. Fixed.

  • Morgan Buck

    Do you ever run into issues with a wordpress or plugin update where your local files and remote db have both been updated by a change but your production server has not yet had the file changes pushed to it to support the updates? Or are database changes of this sort uncommon enough in wordpress these days that this is safe?

    • http://www.otreva.com Otreva

      Hi Morgan,
      I’ve never had an issue. You could always solve this by running a local and production DB if you think it’ll be an issue. We cache pretty heavily on our production sites so if we update plugins locally, we immediately push those changes to production. So that being said, I’ve never had an issue with the half dozen or so WordPress sites we have setup via ElasticBeanstalk but every scenario is different. We also try to keep plugins to a minimum so if you have more than a handful installed, I imagine it could be more of an issue for you.

  • Guest

    Hi Michael, do you notice if the menu have changed? I don’t seem to be able to find the settings you mention in step 9 or at least I’m bit confused with the appearance of:

    1. RDS Security Group
    rds-awseb-e-8hfmde2u9b-stack-awsebrdsdbsecuritygroup-….

    2. SecurityGroup for ElasticBeanstalk env
    awseb-e-8hfmde2u9b-stack-AWSEBSecurityGroup-….

    I don’t seem to be able to find “the best estimate of your IP Address that Amazon gives you in the small text in the yellow box.” you mention…

    Have a missed something? Attached a screenshot for your reference.

  • gordontam

    Hi Michael, do you notice if the menu have changed? I don’t seem to be able to find the settings you mention in step 9 or at least I’m bit confused with the appearance of:

    1. RDS Security Group
    rds-awseb-e-8hfmde2u9b-stack-awsebrdsdbsecuritygroup-….

    2. SecurityGroup for ElasticBeanstalk env
    awseb-e-8hfmde2u9b-stack-AWSEBSecurityGroup-….

    I don’t seem to be able to find “the best estimate of your IP Address that Amazon gives you in the small text in the yellow box.” you mention…

    Have I missed something? Attached a screenshot for your reference.

    • http://www.otreva.com Otreva

      Hello. Your question is a bit beyond the scope of this article. I’d suggest reading up on Amazon’s firewalls in general. http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/authorizing-access-to-an-instance.html

      The short answer is you need to click the Inbound tab but explaining firewall configurations is a whole topic on its own.

      • Linda

        I think the question gordontam asked was valid. Following the steps outlined above the on Step 9 there is no possiblity to set Security Groups. I have the same difficulty as Gordontam and your answer does not address the question. Has the Amazon interface changed since this article was written? And if so how do you complete step 9 in the absence of a security group tab from the RDS Dashboard?

        • http://www.otreva.com Otreva

          Hi Linda, I guess I didn’t understand his question. To answer what you are saying, when you go into RDS > Security Groups there will definitely be a group called “default” at a minimum. If you click on the icon to edit (a magnifying glass) you get to the screenshot in step 9. I guess maybe you were both confused by the icon being a magnifying glass?

          I hope that makes sense and I understand the question correctly.

          • Linda

            Thanks so much for getting back to me. The problem is that in mine and I guess gordontam’s case we do not have a security groups option. My dashboard skips straight from Snapshots to Parameter Groups. Perhaps we missed something in previous steps which means we don’t have a security groups option available? Thanks again though. I might try research a little about VPC – maybe that is the answer to working around this discrepancy….

          • http://www.otreva.com Otreva

            Ahh ok. Yes there wouldn’t be a security group within RDS or EC2 within a VPC now that I re-read both comments as that is the intention of the VPC. The security would be on the VPC level than instead of the individual services like EC2 or RDS. A quick google for “aws security groups vpc” turned up: http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_SecurityGroups.html

            Sorry I didn’t understand the question.

          • Linda

            Thanks you’ve been a great help – learned a lot.

          • http://www.otreva.com Otreva

            No problem, glad I could help.

            Sorry for the confusion. I thought typical readers deploying WordPress sites wouldn’t be using a VPC when I wrote this but you proved me wrong. Basically Step 9 needs to happen on the VPC level which this explains: http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_SecurityGroups.html

            Everything else should be the same. I’ll also add a note to this post to accounts for VPC users.

  • Mandy McKay

    Hi Mike, thanks for this it is a great solution. I used Xampp lite on a thumb drive for my local version. I have one problem though, the elasticbeanstalk version is dependant on local host being active. If I turn the Xampp server off and click on any links on the elasticbeanstalk version, I get a page error because local host cannot be found. I’m not sure what I have done wrong – any suggestions would be great. Many thanks

    • http://www.otreva.com/ Mike Averto

      Hi Mandy,

      Sounds like your problem is a basic WordPress, DNS, and GIT issue. Your problem stems from step 4, part 1. That step includes a local config file which forces WordPress to be local. However that local file is NOT supposed to be included in your GIT repo (sounds like it is), so beanstalk is forcing you local. I hope that helps.

      • Mandy McKay

        Thanks Mike, a few days of creating and deleting eb environments and I finally have it working.

  • Vitalij Kudresov

    Great post, one thing I would do differently is create RDS. Say you decide to terminate your app and rebuild it, because you wan’t to migrate to different server or for whatever reason. In this situation Elastic Beanstalk would delete you RDS. Instead you could create RDS separately and just add from WordPress config

    • http://www.otreva.com/ Mike Averto

      Vitalij, I agree. We typically do it that why ourselves on most projects for that reason. But for simplification of this article we wrote so that AWS handled all the setup.

      Also I think by default RDS has a daily snapshot so even in your scenario typically data wouldn’t be lost.

  • Jacob Walton

    Was going so well until the very end, step 6.2 “Lastly go into the ZIP you downloaded in the beginning” – What ZIP I downloaded in the beginning!? Can’t find any other reference to this. :/

  • Pingback: Starting a Dev Blog | Kudresov's Tech Blog

  • Gustavo

    Hey Mike, tks for the tutorial.. I followed your steps and successfully deployed a WP in beanstalk…

    The only issue that I am having is with permlinks… When I set them to custom it generates a .htaccess file… Even if I deploy it to beanstalk the links do not work they return 500 error…

    Can you pls let me know how to work around it? I really wanted to use beaultiful urls in my blog.. I am pretty sure there is a way but I tried everything I could and coundt find any solution in google as well..

    tks vm
    Gustavo

    • http://www.otreva.com/ Mike Averto

      Gustavo, this is related to WP. This is all you should need in your .htaccess for pretty permalinks. I’d try to put this and ONLY this in your .htaccess and repush to beanstalk via GIT.


      # BEGIN WordPress

      RewriteEngine On
      RewriteBase /
      RewriteRule ^index.php$ - [L]
      RewriteCond %{REQUEST_FILENAME} !-f
      RewriteCond %{REQUEST_FILENAME} !-d
      RewriteRule . /index.php [L]

      # END WordPress

      • Gustavo

        tks.. the way it worked for me was to put .htaccess in gitignore and in beanstalk wp change the permalink settings.. then it worked..

        my question is, does that mean my design isnt stateless anymore?

        there are other plugins that can only be configured in beanstalk wp… for example caching etc…

        btw any tips on how to configure that and what plugins to use to keep the design stateless?

        tks again

        • http://www.otreva.com/ Mike Averto

          Sorry @disqus_VHjm34EClk:disqus not enough info here, sorry. A .htaccess should have nothing to do with being stateless. Things like sessions, media, etc make your design NOT stateless, not web server configs.

  • Michael

    Hi Michael, is there a way that I can import my local database to the RDS instance? I don’t want to use the RDS database for my local development. I’d rather do a migration to the production.