WordPress with AWS ELB and SSL

Learn how to secure and scale your WordPress site with an AWS Elastic Load Balancer configured for SSL encryption. This detailed step-by-step how-to guide will get you up and running quickly and painlessly.

Summary

In recent past AWS introduced new serverless load-balancing models that are designed to sit in front of your web app architecture and importantly, these new ELB models are both highly-reliable and free.  If you use an AWS EC2 instance to host your WordPress environment then there are many advantages to adding an AWS Elastic Load Balancer (ELB) to your infrastructure architecture.

  • Horizontally scale your WordPress site.
  • Add an automatically-renewing SSL certificate to your site for free.
  • Improved site response times
  • Perform maintenance to your server without having to take your site offline

Unfortunately, getting an ELB with an SSL certificate to work with WordPress is tricky. Namely, WordPress can get stuck in an infinite loop of URL redirections whenever you try to redirect traffic to HTTPS. After a long afternoon of banging my head against the keyboard I finally got HTTPS working. This article will hopefully help you to get your own ELB and SSL certificate up and running quickly and painlessly. Let’s get started!

Theory

This wasn’t immediately obvious to me, but, HTTPS and SSL are only necessary for traffic between your site’s visitors and the ELB. The upstream traffic between your ELB and your EC2 instance(s) resides inside your Virtual Private Cloud (VPC) and can therefore communicate safely using HTTP. This means that you only need to add an SSL certificate to your ELB, and you can (mostly) continue to use HTTP on your EC2 instance.

AWS Architecture

This is not only easier to manage but also provides better page hosting performance. The tricky part is configuring WordPress so that is doesn’t get confused or otherwise behave in a way that would undermine our aim of providing site visitors with a secure browsing experience.

Implementation

First, this article assumes that your WordPress environment is hosted on a single AWS EC2 instance, largely based on AWS’ Tutorial: Install a LAMP Web Server with the Amazon Linux AMI and Hosting a WordPress Blog with Amazon Linux.

1. Get an SSL certificate thru AWS Certificate Manager.

I highly recommend using AWS Certificate Manager to create your SSL certificate. This is an especially good choice if you’re new to SSL because the certificate application process is well-documented and intuitive. Take a look at my how-to article for requesting a SSL certificate from AWS.

2. Create an ELB

You’ll find the link to the Elastic Load Balancer console on the left sidebar of the EC2 console.

ELB Step 1
ELB Step 2
ELB Step 3

3. Add The Certificate To Our New ELB

Add Certificate Step 1

In Step 3 (Configure Security Groups) you should select the same security group that your EC2 instance currently uses. Note however, that your security group must include HTTPS (port 443) in its inbound rules.

Add Certificate Step 2
Add Certificate Step 3

In Step 4 you will configure routing of your inbound web traffic. That is, as site traffic arrives to your application ELB, you need to provides instructions on where the ELB should send this traffic. You’ll be able to edit this information later, just fyi.

Now then, to get the ELB to work at all I had to get creative with a couple of things. One of my more vexing problems regarded Health Checks. The theory behind this is simple: AWS ELB’s will regularly try to ping a certain file. For any EC2 instance included in your Target Pool, if the success code returned matches up with the value in the routing configuration (the, “Success Code”) then the EC2 instance is considered healthy. Mind you, there are additional details which hopefully are self explanatory. Ok, so, in my case i host multiple virtual servers from the same Apache server, and this, along with the fact that all web sites are WordPress sites, caused problems with the default health check, which is to ping index.php. To workaround these problem I created an empty file in the root of each of my WordPress sites named health.aws. Additionally, Apache didn’t necessarily return a 200 status code; even if the file could be pinged. After some investigating I learned that — sometimes, depending on particulars of your server state — Apache might send a redirection code like say, 301, instead of a success code like 200. To work around this I added 301 as a possible valid response code, and voilá, the ELB can correctly determine the health (or lack thereof) of my EC2 instances.

In the screen that follows you’ll add one (or more) EC2 server instance(s) to your Target Group. Keep in mind that with AWS ELB it’s possible for you to horizontally scale your WordPress platform. But, also keep in mind that, on the basis of this article alone, you are definitely not ready to manage an ELB with multiple EC2 targets. Thus, the prudent thing for you to do at this point is to add your sole EC2 instance to the list of registered targets, and to leave horizontal scaling experiments for another day.

Add Certificate Step 4

And, that’s a wrap. You’ve configured your first AWS Application ELB! Now that the heavy lifting is behind us we can shift our attention to re-configuring Apache and WordPress on our EC2 instance.

4. Modify Apache Configuration To Redirect HTTP to HTTPS

You will not make any changes to your Apache configuration. If that seems counterintuitive then let me explain why. In AWS’ own support documentation they recommend that you add “X-Forwarded-Proto” headers to redirect your HTTP traffic to HTTPS, and while this is in fact the correct methodology, we cannot do this YET because if we did it would cause an infinite loop. Instead, we’re going to add these headers from within our wp-config.php file in the next section.

A little more explanation: by default Apache is installed to use HTTP (port 80), therefore all configuration for this protocol was taken care of for you when your originally setup your server. Importantly, inbound traffic originating from the ELB also is traveling over HTTP as per the diagram above and thus we a) should continue to listen on port 80, and b) we should continue to use HTTP all the way to our WordPress server. Now then, to provide an end-to-end HTTPS connection for our users we’ll need our WordPress server to return all web pages over HTTPS rather than over HTTP. We do that below. Meanwhile, following is a sample Apache virtual server configuration which contains a snippet of the code that AWS actually recommends. You can uncomment the snippet and add to your own config in order to test/verify my claim:

  ServerName blog.lawrencemcdaniel.com
  ServerAlias blog.lawrencemcdaniel.com

  DocumentRoot /var/www/html/blog.lawrencemcdaniel.com
  ServerAdmin lpm0073@gmail.com
  ErrorLog /var/www/logs/error_log_blog.lawrencemcdaniel

  #I'm leaving you with a copy of the snippet referenced above in case you want to experiment.
  #RewriteEngine On
  #RewriteCond %{HTTP:X-Forwarded-Proto} =http
  #RewriteRule .* https://%{HTTP:Host}%{REQUEST_URI} [L,R=permanent]

Restart Apache
sudo service httpd restart

Here is some additional reading on how and why this configuration works:

5. Update WordPress Configuration

We need to update the WordPress Address URL and the Site Address URL; both of which are visible within the Settings -> General console window. However, you’ll need to update these values using your wp-config.php file located in the root directory of your site.

define('WP_HOME','https://blog.lawrencemcdaniel.com');
define('WP_SITEURL','https://blog.lawrencemcdaniel.com');

// Update 8-April-2018: I moved https redirection from the Apache virtual server config to wp-config.php using this snippet.
if (strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false)
       $_SERVER['HTTPS']='on';

Cached files and cookies in your browser will affect your browser behavior while you’re implementing and testing these changes. Make sure you regularly clear these two elements of your browser cache to avoid confusing and misleading results.

6. Update Webmaster tools

It’s really important to be aware that Google distinguishes between HTTP and HTTPS in terms of recognizing and indexing your site. Make sure that you add your “new” HTTPS site as a new Web Property in Webmaster Tools.

By |2018-07-03T18:33:53-06:00January 25th, 2018|Categories: AWS, Dev Ops, Wordpress|26 Comments

About the Author:

Lawrence is a full stack developer specializing in the Open edX platform, Django, Angular, Ionic, Wordpress and Amazon Web Services. He lives in Puerto Escondido, Oaxaca, Mexico.

26 Comments

  1. Tom June 3, 2019 at 2:30 am - Reply

    What the actual heck??!! If I had not found your post, I would have just given up on this. Thank you so much for figuring this out and taking time to post what you learned.

  2. sam February 26, 2019 at 10:56 am - Reply

    Hi Lawrence,

    Thank you for this blog. I followed the instructions to configure the WordPress multisite with ALB balancer. Everything works fine and sites are loading properly. But when I try to use wp-cli, I am getting the following error.

    PHP Notice: Undefined index: HTTP_X_FORWARDED_PROTO in phar:///usr/local/bin/wp/vendor/wp-cli/wp-cli/php/WP_CLI/Runner.php(1153) : eval()’d code on line 7

    Also, I found a similar log in apache error logs.

    PHP Notice: Undefined index: HTTP_X_FORWARDED_PROTO in /var/www/html/cdpblog/wp-config.php on line 9

    Any suggestions?

  3. Neil January 27, 2019 at 6:29 am - Reply

    Hi Lawrence,
    Thank you for the great tutorial.

    Everything works fine except that if I search my website on a browser it only loads when i type https://my-domain.com.
    if I type just my-domain.com or http://www.my-domain.com it won’t load.
    how to fix this problem?
    I am not a technical guy just followed your instruction.
    Thanks,
    Neil

    • admin January 27, 2019 at 7:56 am - Reply

      hi neil, i’m glad you found the post helpful! your problem is in Step 5: Update WordPress Configuration. but bear in mind that you might have performed this step correctly, and that it’s your browser cache that’s causing this problem. testing your site from any other device, like say, a friend’s mobile phone, will help you determine where your problem lies.

  4. TJ January 23, 2019 at 5:09 pm - Reply

    Thank you for the article. Can you tell me where in the wp-config.php file you put the snippet from 8-April-2018?
    (if (strpos($_SERVER[‘HTTP_X_FORWARDED_PROTO’], ‘https’) !== false)
    $_SERVER[‘HTTPS’]=’on’;)

    I just want to be sure I am not screwing anything up.

    Thank you again for sharing your knowledge.

    • admin January 23, 2019 at 5:15 pm - Reply

      i put it near the top of the file, just below all of my “define()” imperatives. but it’s unlikely that the location matters.

  5. June December 19, 2018 at 2:03 pm - Reply

    HI Lawrence,
    Thank you for this article – I think it explains why I am getting mixed content error on my blog and the infinite redirect when I try to login to wp-admin. Unfortunately for me, my blog resides in a subdirectory of my site and the edits to httpd.conf are necessary for the other portions of my site to display using https. Do you know of any way to edit httpd.conf so that all directories EXCEPT http://www.mysite.com/blog use the rewrite rule and then perhaps I can use the information in this blog to get my WordPress site working properly on my EC2 instance? Any advice would be most appreciated@

  6. Jash October 3, 2018 at 1:35 pm - Reply

    Hi,

    Everytime I try to login to my WordPress Panel, it gives me an error cookies are blocked or not supported on your browser.

    I am pretty sure I have not blocked them on my browser. Can you please suggest what could be the issue

  7. ChiefCook &. BottleWasher September 9, 2018 at 9:37 am - Reply

    Hi Lawrence,

    Thanks for the great documentation. It’s entirely consistent with what I’ve been figuring out, but being without sufficient programming chops, left feeling like the bride at the church steps.

    Anyway, I go through all the steps as per your outline, and get to a 502 Bad Gateway. Suggestions? The good news is that the SSL indicator is green, and I’m not looking at an unrendered html page. The bad is that I’m still 1/2 way up the aisle without the ring!

    Please advise, and I’ll go through one more time to see if I can find my error.

    Excellent presentation… …my only critical offering, I’d suggest making it possible for reader to zoom in on your images. Otherwise clean, professional, and easy to follow.

    Best regards,

    admin@reportrkr.com

    • admin September 9, 2018 at 10:08 am - Reply

      i’m glad you found it helpful. it’s entirely possible that your 502 error will work itself out in the next 45 minutes or so, thus, this might be an opportune moment to take a short break. 502 errors sometimes indicate a temporary state.

      • ChiefCook &. BottleWasher September 10, 2018 at 9:37 am - Reply

        The 502 message has not cleared, and registered target still showing as “unhealthy”… …set up the Health Check to /health.aws, and have that file sitting in EC2 instance root directory. Settings exactly as per your Configure Routing illustration. Is the root ownership and permission setting special?

        Everything else seems to be checking out as I go through the various security groups. Target name in my case entered as “b2b-ioda-org.http” and is resolving properly to the instance ID.

        I’d added in the 08 April update to the wp-config as per below, sitting on two lines:

        // Update 8-April-2018: I moved https redirection from the Apache virtual server config to wp-config.php using this snippet.
        if (strpos($_SERVER[‘HTTP_X_FORWARDED_PROTO’], ‘https’) !== false)
        $_SERVER[‘HTTPS’]=’on’;

        I had not added in the redirect recommended by AWS that you had #’d out.

        Thoughts?

        • admin September 10, 2018 at 10:10 am - Reply

          that helps. the file path to “health.aws” is relative to HTTP rather than you linux file system, thus in my case, i created a folder with the following path: /var/www/html/health.aws, and this folder includes a simple index.html file with the following contents:

          Health Test

          • ChiefCook &. BottleWasher September 10, 2018 at 3:58 pm

            Tried that. No luck, though I remain pretty sure that we’re on the right track.

            In your notes, you set the Document Root in httpd.conf as:
            DocumentRoot /var/www/html/blog.lawrencemcdaniel.com

            Doesn’t that place the http root one directory down?

            In the Health Edit dialogue box, on your notes above, you show it as “/health.aws” …I assume that’s how it should be entered on the AWS Control Panel?

            Also, I can’t seem to find the logs. In your notes, you’d advised updating the httpd.conf in the form of ErrorLog /var/www/logs/error_log_blog.lawrencemcdaniel …:
            – should the location not be “logs” without an s, ie /log/?
            – should the location be enclosed in apostrophe marks?
            – so “ErrorLog /var/www/log/error_log_blog.lawrencemcdaniel”

            Anyway, sorry for all the niggly questions… …but it’s in the nature of the beast.

            Much appreciated

            ChiefCook

            Protocol
            HTTP
            Path
            /health.aws
            Port
            traffic port
            Healthy threshold
            2
            Unhealthy threshold
            2
            Timeout
            5
            Interval
            15
            Success codes
            200-301

          • admin September 11, 2018 at 11:20 am

            this is helpful. you should first focus on getting your ELB report that it’s in good health. keep in mind that the ELB communicates with your EC2 instance using http, and thus, the “root” path is not the same as the root of your linux file system. it seems from your comments that you’re already on the right path. there’s nothing magical about the “/health.aws” file btw — the ELB health test sends a regular http get request to your server, and if the http response headers include a response code that’s in the range of what you specified in your setup (ie, 200-301) then it considers itself to be healthy. thus, you can specify any file that is accessible via http. my rationale for creating an independent file (health.aws) is that i’m assured that it will always exist (since i created it).

  8. Mohamed Nazar August 20, 2018 at 2:46 am - Reply

    Great! I have implemented it but wp-admin page coming without CSS and it not allow me to login with working credentials.

    • admin August 20, 2018 at 4:34 am - Reply

      Hi mohamed, if you’re using Chrome then open the javascript console and tell me what error code you see. meanwhile, try logging with safari or firefox. if these work correctly while chrome does not then i think i know your problem.

  9. Amit Jat July 17, 2018 at 6:00 am - Reply

    I was Googling around for content WordPress with AWS ELB and SSL this morning, when I came across your excellent page.

    Great stuff!!

    I just wanted to say that your page helped me a ton. I would have never found any deep insight article on WordPress with AWS ELB and SSL. I specially like you add flowchart of process,

    It helps to learn WordPress with AWS ELB and SSL

    It’s funny: I recently published top online resources to learn Aws tutorial.

    Here it is in case you’d like to check it out: https://hackr.io/tutorials/learn-amazon-web-services-aws

    Also, my tutorial might make a nice addition for learning Aws tutorial.

    Either way, thanks. And have a great day!

    • admin July 17, 2018 at 9:02 am - Reply

      thanks Amit! i just registered on your site and submitted a couple of my AWS tutorials. hackr.io looks really useful, good luck with next steps! 🙂

  10. Jim July 16, 2018 at 1:13 pm - Reply

    Hi Lawrence,
    I also struggled for an afternoon with setting up a WordPress site with TLS/Loadbalancer. I tried plugins (really…), but got stuck in the loop before I could activate it. But with your steps, it worked immediately. Thanks for posting.

  11. Conor July 15, 2018 at 4:30 pm - Reply

    Hi Lawrence,

    Thank you very much for this information. There is limited resources online regarding this particular set up and any of the blogs/ guides I have followed have left me with a broken site in an infinite loop. I just have one question, I am correct in saying that for step 4 all I have to do is add:

    RewriteEngine On
    RewriteCond %{HTTP:X-Forwarded-Proto} =http
    RewriteRule .* https://%{HTTP:Host}%{REQUEST_URI} [L,R=permanent]

    anywhere in my wp-config.php file and then run the server restart command?

    And then update:

    define(‘WP_HOME’,’https://blog.lawrencemcdaniel.com’);
    define(‘WP_SITEURL’,’https://blog.lawrencemcdaniel.com’);

    and add:

    // Update 8-April-2018: I moved https redirection from the Apache virtual server config to wp-config.php using this snippet.
    if (strpos($_SERVER[‘HTTP_X_FORWARDED_PROTO’], ‘https’) !== false)
    $_SERVER[‘HTTPS’]=’on’;

    to my wp-config.php also?

    Do I run a second server restart after?

    Sorry, I do not have any experience with this kind of thing.

    Thank you,
    Conor

    • admin July 16, 2018 at 6:10 am - Reply

      hi conor, no, you should not edit your apache config. this is why your getting an infinite loop. the alternative commands that you’re placing in wp-config.php are the only modifications that you need. btw, these two sets of edits are duplicative (they do exactly the same thing, but at different stages of creating the http response headers). when using AWS ELB you’ll need to make the modifications ONLY in wp-config.php.

  12. Chuck Boecking July 3, 2018 at 10:52 am - Reply

    Hi Lawrence,

    Worked great – thank you very much!!

    Quick question: the if wp-config.php => (strpos($_SERVER[…. statement works great for redirecting traffic that lands on http://www.YourURL.com however, it does not work if you land on http://www.YourURL.com/SomePage. Any idea why this does not work?

    • admin July 3, 2018 at 6:31 pm - Reply

      hi chuck, that actually sounds more like the effect of a page caching plugin. the line “if (strpos($_SERVER[‘HTTP_X_FORWARDED_PROTO’] … ” evaluates the http header, not the URL path. you might try completely clearing any caches on your wordpress site, and for good measure you might also clear your browser cache in case of any other similar side effects.

  13. Sagi July 1, 2018 at 2:04 am - Reply

    Hi, I’ve tried the approach (without changing my apache conf – only wp-config). While the home page loads over https, I cannot access the dashboard. Once I try to login using my wp admin user, I do not see the dashboard. Instead, I get an error: “Sorry, you are not allowed to access this page.”

    • admin July 1, 2018 at 5:47 am - Reply

      hi Sagi, that’s great. looks like you’re almost done. you need to clear your browser cache AND clear the site cache of any performance plugin that you might be running on your site.

  14. Amit June 25, 2018 at 12:10 pm - Reply

    Hi LAwrence,

    Thanks for this blog. I added step 4 config into /etc/httpd/conf/httpd.conf file,

    RewriteEngine On
    RewriteCond %{HTTP:X-Forwarded-Proto} =http
    RewriteRule .* https://%{HTTP:Host}%{REQUEST_URI} [L,R=permanent]

    and then step 5 in wp-config as well.

    MY target group is displaying target as healthy and i have https configured as inbound rule as SG of My EC2 instance. i
    https still doe snot works. what should i check next ?

Leave A Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.