Running WordPress on HTTPS in AWS Elastic Beanstalk

After my recent move to AWS, I decided to put my blog into Elastic Beanstalk as a way for me to learn more about the offering. Overall the process was pretty straightforward, and I’m enjoying having the control that comes with a self-hosted WordPress blog too. I did want to make one change though, which was to move the site to run on HTTPS instead of standard HTTP. My logic on this comes from the fact that Google uses HTTPS as a ranking signal, and who doesn’t want their site rated higher in searches? I’ll take you through the steps it took for me to set it all up in this post.

Step One: Get an SSL certificate

The first step was to get my hands on an appropriate SSL certificate for the site. AWS Certificate Manager is my new best friend here. First of all, it’s free! You pay to run your application in Elastic Beanstalk, but that’s it, you don’t pay an additional charge for the certificate, which is excellent news. There are some other bonuses too, such as automatic renewal and management of keys as well. These features and the price made choosing where to get a certificate from a no-brainer.

The process of requesting a certificate is straightforward. Open the Certificate Manager in the AWS console and select “request a certificate”. You’ll then be asked to perform either a DNS or email validation to ensure you control the domain in question. Once that’s complete you will be issued a certificate that can integrate directly in many AWS services.

Step Two: Configure Elastic Beanstalk environment

Now that we have a certificate we can configure it in the EB environment. To do this, head into your EB environment in the console and select “Configuration”. Scroll down to the “Network Tier” settings, and you’ll see a section to do with the load balancer. Here you will see settings about the “Secure Listener Port” as well as an option to select one of your managed certificates for use here.

Once you configure this, the environment will start listening on port 443, but your site likely won’t work under HTTPS yet. There are a few other steps to complete. At this point, I saw a lot of my pages load, but images and CSS were missing because we need to tell WordPress to run with HTTPS next.

Step Three: Use HTTPS for admin pages

An essential part of WordPress to protect with SSL is the admin pages. It’s also a good idea to start with this when implementing your HTTPS setup since if it goes wrong, you’re only impacting the admins of your site and not end users. WordPress makes it easy to force HTTPS for admin pages through a change in the wp-config.php file.

define('FORCE_SSL_ADMIN', true);

WordPress will use this setting to force anything under the /wp-admin directory to require HTTPS. Now you’ll notice that if you put this line in your admin pages will be inaccessible – your browser will catch you with a “Too many redirects” error. Let me explain why this is – when we configured the load balancer in Elastic Beanstalk it does what is called “SSL Offloading” or “SSL Termination”. Under SSL offloading the SSL handshake will terminate at the load balancer, and the request from there to the actual web server instances executes as standard HTTP.

There are plenty of good reasons to do this (including only needing to manage certificates at the load balancer, and improving performance on the web servers as they don’t need to handle the SSL handshake individually) but it causes an infinite loop here. Because the request hits the site as HTTP, which based on our setting above will send a redirect response to the SSL URL. The redirected request will arrive at the load balancer again, and again will transition back to HTTP and repeat the process.

Fortunately, we can get around this by leveraging an HTTP header that load balancers that offload SSL traffic put on requests called “HTTP-X-FORWARDED-PROTO”. This header indicates what protocol the original request arrived in, so we can determine if the user requested the site under HTTPS or not. Here is a code sample that you can include in wp-config.php to do this.

if (strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false) {
	$_SERVER['HTTPS']='on';
}

This code inspects the HTTP header, and if it includes “https” we set the HTTPS flag on the server, so it treats it as if the request was made via HTTPS even though it came from the load balancer as HTTP. Once you put this in and deploy, you will now be able to access your admin site as HTTPS with no issues at all!

Step Four: Handling mixed content warnings

If you look at the rest of your site under the HTTPS URL now, you’ll see that it works. However, you might find yourself seeing a “mixed content” warning because some of your images and content that existed before configuring SSL have HTTP links instead of HTTPS. There are a couple of problems to solve here, how we ensure new pictures and content use HTTPS, and then what to do with the existing content.

For me solving the problem of new content was an easy one. I’m using the “WP Offload S3 Lite” plugin which lets me store all of my images and content in an S3 bucket (which I then use AWS CloudFront as a CDN for). The plugin has an option which lets you force all links to HTTPS, so this was straightforward.

For the existing content, I found a great post at css-tricks.com which talks about moving WordPress to SSL as well and includes some samples of scripts to run on your database to convert all the links for you. Have a look at those scripts, and be sure to take a backup of your database before you make manual changes like this! It worked a treat for me though, so was very happy with this approach.

Step Five: Redirecting traffic to HTTPS

Search engines have already crawled my site as HTTP, and people may have bookmarks and other shortcuts. These existing links mean I want to redirect those requests to HTTPS without breaking the experience for users. There are a few places I could inject code to do this, but to ensure that I didn’t modify any files in the original WordPress code I decided to create a plugin for it. The plugin code looks like this:

<?php 
/* 
    Plugin Name: Brian Farnhill HTTPS Rediect
    Plugin URI: https://brianfarnhill.com
    Description: A plugin to redirect to HTTPS
    Version: 1.0
    Author: Brian Farnhill
    Author URI: https://brianfarnhill.com
    License: GPL2
*/

function redirect_if_nossl_loadbalancer() {
    if (strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === false) {
        header('Location: ' . "https://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]", true, 302);
        die();
    }
}
add_action("parse_request", "redirect_if_nossl_loadbalancer");<span style="display: inline-block; width: 0px; overflow: hidden; line-height: 0;" data-mce-type="bookmark" class="mce_SELRES_start"></span>

The plugin uses the same SSL detection we put in the wp-config.php file earlier, but now we are adding an HTTP header for the redirect to the same URL but under HTTPS.

Wrapping up

That’s all there is to it – do a lot of testing and check as many pages as you can for issues, but that should get you running with HTTPS. If you need to roll things back you can remove those changes to the config file and the plugin – and don’t forget to restore your database backup as well!
 

 

 

 

One Reply to “Running WordPress on HTTPS in AWS Elastic Beanstalk”

  1. Thanks for this article. I messed this all up bad last week – your explanation of the redirect loop I was experiencing made it all click.

    Thanks for helping me out!

Leave a Reply