Switching a WordPress server to HTTPS and HTTP/2

Having migrated my server to a more modern server configuration, I was in a position to make two changes to the way it serves its websites – switching to secure HTTP and enabling support for HTTP/2.

What and Why

What’s HTTPS?

Web traffic has traditionally been sent between the server and your web browser using HTTP, the Hypertext Transfer Protocol. With HTTP, the content being sent – both the web pages you’re viewing and any data you’re sending (e.g., form submissions) isn’t encrypted. If someone was to intercept those packets of data as they’re being sent across the internet, they could view the contents. They might even be able to modify or replace them.

Secure HTTP, which might be referred to by various relevant abbreviations including HTTPS and SSL/TLS, encrypts all of the data that is communicated between server and client. Everyday internet users have been aware of HTTPS for years, especially in terms of financial transactions. Browsers have shown a padlock icon to let the user know that their connection is secure.

Why switch to it?

As general awareness of privacy and security risks has grown in recent years, there has been a growing movement for all sites to enable HTTPS and to redirect anyone connecting via HTTP so they receive an encrypted connection instead. Here’s some general reading about the arguments for encrypting the web from the Electronic Frontiers Foundation and Mozilla Developer Network.

In short, switching to HTTPS is the responsible thing for website hosts to do. And what’s more, it’s now easy and cheap, thanks in large part to Let’s Encrypt, which allows you to get a free security certificate for your site(s).

And if you’re not convinced that there are enough carrots to justify the switch, there’s a big stick looming. While Google has already been rewarding sites that serve encrypted content in their search algorithms, they’re now beginning to flag sites served over HTTP as ‘Not Secure’ in Chrome.

And what’s HTTP/2?

It’s the recent major update to the HTTP protocol, which had seen limited changes and improvements since the early development of the World Wide Web during the 1990s. Without attempting to dig too deep into technical details, it changes the way web clients/browsers and servers communicate to remove some shortcomings and performance limitations, and to allow things like allowing servers to push content to the client/browser without needing it to be requested. If you want to get into the details, you could start with Rachel Andrew’s “Getting Ready for HTTP/2”.

Why switch to it?

Because it offers improved performance for clients/browsers that support connecting with it, and the server will fall back to serving via earlier HTTP versions to clients/browsers that don’t support it. It’s a win-win.

The Process

To avoid breaking anything that would have required me to wipe out my work and restore the original server configuration, I worked through the upgrade in stages. It allowed the sites to remain live through the whole process, and while there were a few wrinkles along the way it all went pretty smoothly and didn’t take long at all.

One important thing to be aware of is that although an encryption requirement wasn’t included in the HTTP/2 standard, some of the most widely-used web browsers will only use HTTP/2 over secure connections. This means the migration to HTTPS needed to come first, then HTTP/2 after the server was delivering encrypted communications.

My server hosts multiple separate WordPress sites, so I migrated one site at a time. Once I had a site fully set up to be delivered via HTTPS and HTTP/2, I repeated the process on the next one.

The general sequence for each site was:

  1. Enable HTTPS, then configure and test the WordPress site with HTTPS enabled.
  2. Enable redirection of HTTP traffic to HTTPS, then test and fix any issues with the WordPress site until all pages display correctly and the browser’s address bar indicates a secure connection.
  3. Enable HTTP/2, then test that the site is being delivered by HTTP/2 where possible.

Enable HTTPS, configure and test in WordPress

The first thing you need is an SSL/TLS certificate for your site via Let’s Encrypt. The recommended tool for this is Certbot, and the commands to install it are in the Certbot instructions for nginx on Ubuntu 16.04.

Once Certbot is installed, the key command to start generating your certificate and/or updating your server configuration is sudo certbot --nginx, which initiates a pretty straightforward Q&A process.

As mentioned above, I migrated one site at a time, so when I ran Certbot I had it generate a certificate for just that site’s domain name (e.g., davidmallard.id.au) and the www-prefixed version (www.davidmallard.id.au). Importantly, at this stage I told Certbot not to redirect HTTP traffic. I then visited the site by typing the HTTPS address into my browser’s address bar to test that the basics were working. I then manually typed the site address (with https:// as the protocol prefix) to test whether the basics were working.

This all went fine for me, but if there are any issues you might need to:

  1. Restart nginx (sudo systemctl restart nginx).
  2. Look at the changes Certbot made to your server configuration file by viewing and/or editing the relevant file in /etc/nginx/sites-available.

WordPress itself then needs some extra configuration. For most sites, this meant going into the Dashboard, to Settings -> General, and updating the WordPress Address (URL) and Site Address (URL) fields to replace http with https. But one of my sites is a WordPress Multisite (Network) installation, and this required manual editing of the database instead – if you have to go through that process, back up your database first and then you can draw on the “Changing the URL directly in the database” instructions.

Enable HTTP redirection and test

Once I was as comfortable as possible that forcing HTTPS wouldn’t break the site, I ran the Certbot command again, telling it to use the existing certificate (which had been generated in the previous step) and this time telling to to enable redirection.

Once that was done, I visited the site with http:// prefix and checked that the site loaded and the address in the browser’s address bar had switched to https:// (ideally with the green padlock indicating a secure connection. Again, this worked fine for me but if redirection failed I’d look at restarting the server and checking whether Certbot didn’t get something right in modifying the server configuration file.

Once I established that the redirection was fundamentally working, I navigated around the site to test whether everything was being served securely, including things like:

  1. If the homepage has a link to another page with a hard-coded address http://, follow it and check that you end up with a page served over HTTPS.
  2. If a page is displaying an HTTPS address in the address bar but doesn’t have a clear indication that the site is secure (e.g., green padlock) then there might be some mixed-content issues. I had to do some extra work with some sites, and found that opening the site in Chrome, then opening DevTools (Command-Option-I) and viewing the Security tab (you might want to reload the page with the tab open) would let me find the issues. In some cases it was HTTP URLs that had been entered into the theme settings that I fixed via the Customizer. In one case a parent them I was using had hard-coded loading of Google Fonts via HTTP and I had no choice but to manually edit the theme file to replace those addresses.

WordPress also has a FORCE_SSL_ADMIN directive that can be defined in the wp-config.php file. Once the web server itself is redirecting all traffic I don’t know that it’s necessary, but once redirection was working I enabled it anyway.

After all of this configuration and some tinkering to deal with problematic theme settings/code, everything should be being served over HTTPS!

You can get a security analysis of the site by visiting https://www.ssllabs.com/ssltest/ (if all has been configured correctly, you should expect to get an A).

Certbot should have automatically set things up to renew the 90-day Let’s Encrypt certificate before it expires. You should run sudo certbot renew --dry-run and check that it doesn’t alert you to any problems. You can also check out the file /etc/cron.d/certbot to see the cron task that will run to check the certificates.

Enable HTTP/2 and test

Once all of the HTTPS configuration is in place, enabling HTTP/2 doesn’t take much more:

  1. Edit the relevant server configuration file, eg sudo nano /etc/nginx/sites-available/davidmallard.id.au, find the line(s) that have listen 443 ssl; and change to listen 443 ssl http2;.
  2. Restart the server with sudo systemctl restart nginx.
  3. Test the site address at https://tools.keycdn.com/http2-test

What’s next?

That’s it for turning a somewhat-neglected server into one that’s running on modern web protocols that deliver benefits for security, performance and search engine optimisation.

My next steps are to overhaul my personal site. Jen Simmons has been promoting a great initiative with the hashtag #newwwyear and I’ve set my goals to get a lot more done in the next couple of weeks:


Next up will be a mix of refreshing site content, wiping out the current theme and starting with a fresh redesign (so expect that things might begin to look a bit weird for a little while), and adding IndieWeb functionality to the site. I also still have some server configuration to do, especially in terms of enabling caching for the sites.