how to reploy wordpress to amazon web services AWS elasticbeanstalk

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

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.


  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:
  2. Next, select PHP as your platform and leave the environment type as Load Balancing, Autoscaling.
  3. Leave sample application selected for now:
  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.
  5. Ensure you check create an RDS DB instance.
  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.
  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.
  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.
  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 Differentlyaws-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 otreva-production.

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 otreva-production, 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_.
  3. Now click install and you should be up and running! Finish the install just as any other WordPress Install
  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’, ‘otreva-production’); 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
    #ElasticBeanstalk Configs we won't need in the repo
    #These are to ignore media files which we again DON'T want in our GIT Repo.

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


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

  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


    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?



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

  • Israel


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

    Thanks for the tutorial.


    • 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?

    • 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?

    • 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

    2. SecurityGroup for ElasticBeanstalk env

    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

    2. SecurityGroup for ElasticBeanstalk env

    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.

    • Hello. Your question is a bit beyond the scope of this article. I’d suggest reading up on Amazon’s firewalls in general.

      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?

        • 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….

          • 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:

            Sorry I didn’t understand the question.

          • Linda

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

          • 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:

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

          • Ameet Mehta

            Thx Mike, great post. Seems like any new user of RDS will automatically get the EC-VPC setup and are forced to go the VPC security group route. After readying the doc you posted, I’m still not clear as where I would add my local ip (like in that yellow box for estimated ip). Basically seems like I would either edit the VPC SG or create a new one for the RDS server. It is confusing to say the least, and I get pointed to:

            Any insight would be highly appreciated, because any new person coming to this post could get stuck here as well. Just want to get past step 9 and get my local wp to sharing the same RDS like your walkthrough. thx!

          • @ameetmehta:disqus VPC shouldn’t change how security groups work although the screenshots are likely different. You still need a security group on the databases that has an inbound rule allowing port 3306 / MySQL for your local IP. Same idea.

          • Ameet Mehta

            Thx for the quick response, after getting lost in Amazon docs and some trial/error I got it to connect through the vpc, though not as secure since i ended up using instead of my ip, which I’ll lock down once I get this off the ground. thx again for the excellent tutorial.

  • 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

    • 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

    • 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, 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

        • 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.

  • Tominatrix

    You’d be crazy to set up a site following these instructions to the letter. At the very least you should change the RDS retention setting to “snapshot”, otherwise if something goes wrong with your Elastic Beanstalk environment (and trust me, it will) your database will be deleted along with your instances. Ideally I’d be creating the RDS instance externally and just using EB for the web servers.

  • Collinssolutions

    not sure if you are still monitoring this but i went through this tutorial and had some questions. One is on storage. with this setup are user uploads stored on the instances or in block storage that all have access to. Also will this work for a multisite wordpress setup running pro sites

    • Hi @Collinssolutions:disqus. I’m not sure about pro sites as I’m unfamiliar with that.

      However, yes for storage you want to move that off the beanstalk instance. Beanstalk will automatically kill and replace instances when they have issues so you can’t store anything there you don’t want to disappear on a refresh. If it isn’t in your git repo, it shouldn’t be on the instance. Check out the last paragraph in the article for the plugins that help with that.

  • Collinssolutions

    sorry another post. I got it working and published to aws but even though the localhost-config.php file isnt there the site is still running of the localhost name. all the css is still pulling that as the path and not my elastic domain name

    • Sounds like your site URL in the DB is wrong. This is a WordPress setup thing.

      An easy solution is to add these two params in the else block of wp-config.php where the DB connection info is:


      of course replacing with the URL you want. Then you don’t have to edit the DB. Then you can add the same two lines in your local-config.php file to handle the difference when working locally.

  • Ameet Mehta

    Hi, I’ve successfully gotten through setting up ELB, with a t2.small EC2, and a local wordpress install connecting directly to RDS, as well as pushing wordpress up with git and AWSdevtools. I am able to SSH into the EC2 instance, but UNABLE to actually ping or hit my ip via the browser, as it just hangs and never resolves. I assumed it was about the Security Groups, but I have made everything wide open (to test) and set the SG on the the EC2 instance, inbound HTTP, HTTPS, SSH, RDP all to but still to no avail. I’ve read elsewhere but not covered here about associating an Elastic IP to my EC2 instance, which i tried and still no go. The only main difference that my set up has is the VPC which is what AWS gives you now when you set up Elastic Beanstalk. Definitely been on the mad hunt to figure this out as I just want to resolve the site in browser, any insight would be much appreciated. thx!

  • epok

    Hi Mike, Thank you for your help in this process. I don’t know if you are going to be able to help me. I created a wordpress in local (mamp). I wanted to export it online with AWS. I followed this tutorial to create the base of my importation:

    I have exported also my database but I don’t know how to link it with my wordpress now copied on AWS. Can you help me ? Thank you very much in advance 😉

  • Fred Zilz

    Thank you so much for the time you put into your tutorial / blog.

    I am curious about he .gitignore and the git add *.*
    If I follow your instructions I get a message that indicates local-config.php is on the .gitignore list and no files get added. I got around this my using git add –all but I wanted to know if maybe I missed something that would allow git add *.* to work, because I see in some of your other blog posts you use git add *.* and so this must work for you.

    • @fredzilz:disqus checkout to learn a little more about GIT. There are also some free git clients out there like SourceTree which remove the manual command line and may help you some.

  • Hi! awesome post, thanks so much for sharing.

    You mentioned here in the comments that you cache pretty heavily your production sites. Exactly how do you do it?

  • Luke Janicke

    I also couldn’t get past Step 9 without adding an inbound MySQL rule for That is very insecure. But I had no choice.

    My Application is in the Asia Pacific (Singapore) region and therefore I must use VPC Security Groups, according to the message that comes up when I open RDS Security Groups in AWS. So, in VPC Security Groups, where I have four security groups, I guessed the one I needed to edit was:



    awsebrdsdbsecuritygroup = AWS ED RDS Security Group

    Plus, that Security Group already had an inbound MySQL (3306) rule for the AWS EB Security Group.

    However, when I tried to add an inbound MySQL (3306) rule with my CIDR, I got an error message:

    The source must be a valid CIDR (e.g. or the ID of another security group.

    For my CIDR, I got my IP address from and assumed the suffix was /16 since System Preferences told me my Subnet Mask was and told me /16 is what you use for Also, in System Preferences I could see that my Network IPv4 Address started with 172, which puts it in the Class B (/16) group.

    I work in a number of different locations on different home, work and public networks. So, I would have to login to AWS regularly and edit the CIDR in this Security Group rule. That wouldn’t be a problem.

    However, AWS didn’t accept my CIDR. I tried with/without the VPN, checking my IP each time and System Preferences for the Subnet Mask.

    In the end, I had to add an inbound MySQL rule with source That means anyone anywhere could try to connect. Of course, they won’t know the database username or password, but they could try a brute force attack.

    Until I can figure out why AWS isn’t accepting my actual CIDR, I’m stuck with this insecure workaround.

    • @luke_janicke:disqus definitely a networking issue. I suggest reading up on CIDR (Classless Inter-Domain Routing) as this really isn’t related to AWS. Once you can get the exact IP address your router is reporting to the world, you’ll want /32 so if my router/firewall is reporting to the world, I need as the CIRD. Isn’t their a dropdown in the AWS security groups for “My IP”? I think AWS will do all the hard work for you.

    • Luke Janicke

      /32 worked. Thanks!

      However, in the “Edit inbound rules” form the only dropdown was a grey popup that offered my other security groups. See attached. But never mind, I can use IP/32 or now.

  • whoisstan

    Great start! A big issue I am seeing is storing the DB credentials in a file that is committed. Its much better, to use environment variables for this in my opinion. Like this:

  • Muskan Lamba

    Everything was oK, but when i issued ‘git aws.push’ after copying the content of ‘AWS-ElasticBeanstalk-CLI-2.6.4/AWSDevTools/Linux’ into root directory of WordPress it fires an error “git: ‘aws.push’ is not a git command.”

  • Rajkumar D

    Hi Mike,
    I have moved the word-press file to AWS in beanstalk,

    My questions are :
    1. Where that uploaded files are stored.
    2. How to access deployed files through FTP.
    3. Why beanstalk accept the file name not in(index.html,etc)

    Can you explain me clearly.
    Because i am trying to move word-press using duplicator plugin.
    Help me!

  • Muhammad Azaz Qadir

    Installing WordPress on AWS EC2 is time consuming and difficult for those who do not have experience in sys admin. However, this won’t be an issue if you are using a managed platform when you install WordPress on AWS in one click.

  • steven law

    Hi Michael, I create a RDS/VPC in AWS from Malaysia. Using mYSQL Workbench there was no issues. However, even with adding the internal ID in Singapore, I cannot access from Singapore.
    All settings are public and I get Google internal IP from both places.
    Inbound set to anywhere and
    running out of ideas.. it seems to be localised to Singapore only.

  • Hi Mike, i like your posting of this article. I followed your steps, I found that you are using PHP as the AWS EB Pre Configuration and RDS for MySQL. As AWS EB support for Docker so I’m using it with Multiple Container. As Both of WP and MySQL are available in Docker as an Image, I’m looking for the way to instal WordPress and MySQL in those Multiple Container. Please advise if it is possible. Thanks.

  • fail at step 3. Error establishing a database connection. How to fix this? I am using MAMP

  • Santhosh Raj

    HI Mike,
    I already have an existing server (a running website) on Elastic beanstalk.
    I have to configure the WordPress with this website.
    How can I achieve this?

Otreva is a custom software product development company focusing on user experience, responsive web development, & mobile application development.

Interested in seeing what it costs to build an app?

Start Quote See Stats
224 Wyoming Ave. #100
Scranton, PA 18503

You've found the secret footer!

Tweets about @Otreva

Or check us out on:

Shopify Experts