If you’re a regular visitor to my website, have you noticed what’s changed?
I’ll forgive you if you don’t see it right away. You need to take a look in the URL bar, usually found at the top of your browser. You’ll see a green lock and, if you’re using the Google Chrome browser, a ‘Secure’ indicator.
Yup. I did it. I migrated the website from http to https.
Making this switch sounds simple enough, but it can get a bit complicated. I self-host my own WordPress website on an Amazon EC2 instance. I also use the Cloudflare CDN service to front my traffic to make the website a touch faster and to provide a thin layer of security.
While I am aware of straight forward methods to secure a website using Cloudflare, I wanted to use the Let’s Encrypt certificate service. I’ve heard a lot about it and figured what better way to learn how it works than to use it for my own website. For those not familiar with Let’s Encrypt, according to their words it’s a ” free, automated, and open certificate authority (CA), run for the public’s benefit. It is a service provided by the Internet Security Research Group (ISRG).”
I took on the challenge for the following reasons:
- I wanted to do my part to be a good citizen of the internet. Everyone who has a website should be using HTTPS/SSL to encrypt their traffic and protect the privacy of their users. I wanted to stop being one of “them.”
- I wanted to establish a more secure connection between my website and the Cloudflare CDN. Using their Full SSL implementation would have worked and been good enough. However, I wanted to go all in and use the most secure option available – Full (strict).
- While I could have used one of the Cloudflare SSL services and certificates, I wanted to learn about and support the Let’s Encrypt service. Plus, it gives me the option to move away from CloudFlare in the future without losing SSL.
- And last, but certainly not least, one of the reasons for self-hosting my website was to learn about running a server. What better project than upgrading a website from HTTP to HTTPS, especially a WordPress instance. It’s a perfect project to use as a learning vehicle.
Enough blabbering, let’s get started.
Background and references
Before I start a server project, I do my homework so I know the depth of the water before I jump. I did plenty of Google searches to learn about the experience of those before me. Here’s a list of the most useful articles I found. You’ll notice that there a few Amazon articles. They do a great job with their documentation. Their tutorials are very useful, and sure enough, they had a step-by-step on how to use Let’s Encrypt SSL certificates on an EC2 instance.
- Creating an Amazon EBS Snapshot – AWS Tutorial
Making a backup of your EC2 instance. Always best to be safe than sorry. - Deploying Let’s Encrypt on an Amazon Linux AMI EC2 Instance – Gifford Nowland
Of all my research, this was my “go-to” article that I kept coming back to over and over. - Let’s Encrypt on EC2 – Ivo Petkov
Referenced from Nowland’s article and serves as an excellent cross-reference. - Appendix: Let’s Encrypt with Certbot on Amazon Linux – AWS Tutorial
Just as important as Nowland’s article, if not more so since it is from “the source.” - How to Validate a Let’s Encrypt Certificate on a Site Already Active on Cloudflare – Cloudflare Support
Once you have the Let’s Encrypt certificate installed, it’s important that you make sure it stays up to date since the certs expire every 90 days. When using Cloudflare, there are a couple of items you need to address to make sure the certificates update automatically. - Migrating your WordPress website from HTTP to HTTPS – Bramus Van Damme
Once the server is secure, you need to update your WordPress settings. The post also has some nifty resource for addressing insecure content warnings, which we’ll get to in a bit. - Step 3: Test and Harden the Security Configuration – AWS Tutorial
Once everything has been secured, it’s good to verify that the outside world thinks so too.
For informational purposes, this project took me the better part of a day (~6 hours). I would say the majority of this time was spent on research. Once I was comfortable and had my plan mapped out, creating the certificates, installing them, changing Cloudflare settings, and so on, only took a couple of hours.
The good news is that the server wasn’t down or offline during this time. The transition happens rather seamlessly to the site visitors.
Here’s the outline of my plan:
- Check prerequisites
- Generate and install Let’s Encrypt certificates
- Upgrade WordPress and Cloudflare settings
- Setup Auto-renewal
- Address mixed content warnings
- Update Google Analytics and Search Console settings
- Validate the SSL installation
Disclaimer: The remainder of this article requires an intermediate level of server operation and knowledge. I’ve documented the steps well enough for my own purposes so I can update and/or recreate the SSL configuration on other websites I manage.
Prerequisites
Before getting too far along, check to make sure that port 443 is open on the server and that the Apache SSL modules are installed and active.
- Login in to your Amazon EC2 console and make sure that port 443 is enabled for traffic in your security groups. Amazon has plenty of documentation on how to set it up.
- Install the Apache SSL module, if necessary. I’m using the Amazon AMI version of Linux, which uses the yum package manager. Run the following command:
$ sudo yum install mod24_ssl
- Restart the Apache server to load the SSL module.
Generate and Install Let’s Encrypt SSL certificates
Step One: Create a backup snapshot of your Amazon EC2 instance, just in case.
I’m not going to detail the steps, just follow the Amazon tutorial: Creating an Amazon EBS Snapshot
Step Two: Check that Python is installed.
Run the following command:
$ yum list installed | grep python
If you don’t see any results for Python, such as ‘python27.x86_64’, then install Python as follows:
$ sudo yum install python27-devel git
Step Three: Check if Extra Packages for Enterprise Linux (EPEL) is enabled.
Run the following command:
$ yum repolist all
Look for ‘epel/x86_64’ in the resulting list. You will see ‘enabled’ to the right of it. If not enable it as follows:
$ sudo yum-config-manager --enable epel
Reference: AWS – Adding Repositories
Step Four: Download the latest release of Certbot from EFF and make it executable.
$ wget https://dl.eff.org/certbot-auto
$ chmod 755 certbot-auto
After downloading Certbot, you might want to put in a directory other than where it was downloaded. Just remember where you put it because you will need the location to setup the automation later.
Step Five: Run Certbot to generate the SSL certificates
Since the site is running on Cloudflare, you will need to run a couple of special options. Specifically, you need to run it with the ‘certonly’ option, and you need to verify site ownership using the ‘webroot’ flag. Unfortunately, you can’t use the interactive method. You’ll need to move and edit a few files later.
$ sudo ./certbot-auto certonly --debug --webroot -w <path_to_website_root> -d example.com -d www.example.com --agree-tos
Step Six: Update virtual host entries and restart Apache
The good news, you have the certificates. Now you need to update your virtual host entries to point to the newly minted certificates. I’m not going to list the steps here since they are different depending on your configuration. I’d recommend using Nowland’s or Petkov’s articles that I referenced above.
Once the virtual hosts are updated to point to the certificates, restart Apache. Take a deep breath and relax. You’re almost there.
Step Seven: Update CloudFlare settings
The site is ready to accept secure connections from Cloudflare. Go into the Cloudflare settings for your website. Find the icon labeled ‘Crypto’ and click on it. The first settings entry is ‘SSL.’ Select ‘Full (strict).’ You can do this because you have a valid certificate that Cloudflare will honor. Cloudflare will serve your website using their SSL certificate, but all requests for content that are made to your website will be over an SSL connection.
Update WordPress and Cloudflare settings
For these steps, I relied heavily on the article by Bramus that I listed in the reference list.
Step One: Change default domain name
In the WordPress General setting tab, change the ‘WordPress Address (URL)’ and ‘Site Address (URL)’ to an https prefix.
Step Two: Force SSL for admin
This step involves making an edit to your wp-config.php file. It’s not mandatory, but since you’ve went through the work to enable HTTPS, why not? Just add the following line to the file:
define('FORCE_SSL_ADMIN', true);
Step Three: Redirect all requests to HTTPS
This is step #5 in the Bramus article. It involves making a change to the .htaccess file such that all requests into your website are forced to use the https domain. Here are the directives to add to the file:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
Step Four: Enable HSTS (in .htaccess)
This step isn’t absolutely necessary either, but you might as well since you’ve come this far. It’s just good practice to do it. By the way, this is step #6 in the Bramus article.
# Enable HSTS
Header set Strict-Transport-Security "max-age=31536000; includeSubDomains" env=HTTPS
Step Five: Enable HSTS in CloudFlare
Since we’ve went through the trouble of adding HSTS to our website, let’s go ahead and enable it in Cloudflare. Go back to the ‘Crypto’ settings for your website in Cloudflare, head about halfway down the page and locate the setting ‘HTTP Strict Transport Security (HSTS).’ Chose ‘Change HSTS Settings’, acknowledge the terms, select ‘Next’, and then enable it on the final screen. I just used the recommended defaults.
Automate certificate renewal
Let’s Encrypt SSL certificates expire after 90 days. Thankfully, you can setup certbot to check for your certificates daily and renew them automatically. It involves creating a cronjob on the server. Both Amazon and Cloudflare have support articles on how to do it. Here are the steps that I followed.
Step One: Open crontab
Open up crontab to add the renewal job. It’s easy, just open the file /etc/crontab in a text editor on the server.
Step Two: Create the cronjob
In my case, the crontab had easy to follow instructions for setting up a cron job. Some places suggest checking twice a day for updates, but I figured once was enough. It’s also a good idea to restart the server if and when the certificates are updated using the ‘deploy-hook’ option in certbot. Here is the line I added to my cronjob:
3 4 * * * root /usr/bin/certbot-auto renew --deploy-hook "service httpd graceful"
Step Three: Restart crond service
Restart the crond service, and your automation is ready to go.
$ sudo service crond restart
Fix mixed-content warnings
Now that you have everything running, let’s reload the website. It’s possible that you see an ‘i’ (info icon) instead of the green padlock. This means you have mixed-content warnings. In other words, not all of the content on the page has an https prefix. It’s usually due to old links that are in the WordPress database.
The Bramus article has scripts that you can run on your database to update all of the links in your database. I had prepared myself to take this step, which had me feeling very uneasy (editing the WordPress database directly always gives me the heebie-jeebies). Thankfully, the power of Cloudflare saved my bacon.
If you go to the ‘Crypto’ settings for your website in Cloudflare, there is a setting halfway down the page called ‘Always use HTTPS.’ Turning this to the ‘on’ position will cause all of the links on your page to magically go from ‘http’ to https. Of course, if you want to be complete, you can run the database scripts. In my case, after flipping the switch, all was good. I decided to leverage the Cloudflare setting and leave my database as is. My motto: The less mucking with the WordPress database, the better.
I can always revisit this later if the Cloudflare settings change, or if I decide to stop using the Cloudflare CDN service.
Inform Google you’ve went secure
Now that we’ve completed all of the work to enable HTTPS, let get credit for it from Google. Google has been telling us that it will favor HTTPS websites, so we should take advantage.
Step One: Change the domain in Google Analytics from http to https
I’m going to assume that you’re using Google Analytics and have it enabled on your site. If so, login to your Analytics account and change the default URL to ‘https’ in both the Property and View settings.
Step Two: In Google Search Console, add the https version of the website
Google Search console is a hidden secret that you need to be taking advantage of, if you’re not already. Head over to the Search Console (click here). Click the red ‘Add a Property’ button and follow the instructions. Just be sure to use https in front of URL. Now you can get statistics from Google regarding how it sees your website. It also helps alert Google that you’ve gone secure.
Step Three: Add a sitemap.xml if you have a sitemap for your WordPress instance
Now that Google knows about the https version of your website in Search Console, submit a sitemap. This will tell Google what the structure of your website looks like and how to index it. It’s under the ‘Crawl’ menu in Search Console. Find the sub-menu ‘Sitemaps’, click on it, and then follow the on-screen instructions to test and submit a sitemap. There are great WordPress plug-ins to generate one, including the popular Yoast SEO plug-in.
Validate SSL settings
The final recommended step is to check with a couple of third party website to make sure they agree with your HTTPS setup.
Step One: Enter your domain at the Qualsys website (click here)
If you run into any problems, errors, or warnings, the website should give you suggestions and recommendations on how to fix them.
Step Two: Check with SSL Shopper (click here)
This isn’t entirely necessary. I figured it would be good to see the results from more than one source just to make certain that independent parties agree that my website is secure.
Congratulations! If you made it this far, you did it. You’re website is now HTTPS secure. You’ve done your part in being a good citizen and steward of the internet.
Disclaimer #2: I documented these instructions for my own personal use in case I need to reference them later to remember and recreate what I did. You are more than welcome to reference my experience, but keep in mind that they may or may not work for you depending on the specifics of your setup. What I’m trying to say, in not so many words, is that I’m happy to entertain questions and will do may best to offer assistance, but I cannot guarantee timely and accurate responses.