Hosting WordPress Yourself Part 6 – HTTPS and HTTP/2

#

In the previous installment of this series, I demonstrated how to configure cron, outgoing email and automatic backups. In this post I will show you how to configure HTTPS and HTTP/2.

HTTP/2

HTTP/2 is the latest version of the HTTP protocol and can provide a significant improvement to the load time of your sites. I wrote a complete article on the subject, which explains the benefits in more detail. In short, there really is no reason not to enable HTTP/2, the only requirement is that the site must also be served over HTTPS.

HTTPS

HTTPS is a protocol for secure communication between a server (website) and a client (web browser). It ensures that all data sent between the devices is encrypted, and that only the intended recipient can decrypt it. Without HTTPS any data transmitted will be sent in plain text, allowing anyone who is eavesdropping to read the information. HTTPS is especially important on sites which process credit card information, but has gained widespread adoption over the last couple of years. This is partly due to Google announcing it as a ranking signal, but also due to the introduction of Let’s Encrypt, which provides free SSL certificates.

Obtaining and installing SSL certificates used to be an arduous task but Let’s Encrypt and the Certbot client make the process a breeze. Let’s begin…

Obtaining a Certificate

Begin by connecting to your server.

ssh ashley@pluto.ashleyrich.com

Install the Certbot client using apt-get:

sudo apt-get install letsencrypt -y

You can then obtain a certificate for your site using the letsencrypt command:

sudo letsencrypt certonly --webroot -w /home/a5hley/ashleyrich.com/public -d pluto.ashleyrich.com

This uses the webroot plugin to validate that you own the domain. The -w flag should point to your site’s public directory and the -d flag is the domain you’re requesting the certificate for. When you first run the command you should be prompted to enter your email address, which will be used for expiration notices.

On subsequent attempts you should receive the following confirmation, which details where the SSL certificate has been saved and also when it will expire. Let’s Encrypt certificates expire after 3 months:

Installing the Certificate

Open the site’s Nginx configuration file:

sudo nano /etc/nginx/sites-available/ashleyrich.com

Add the following directives within the server block, replacing the file path with the one you received when obtaining the certificate. The ssl_certificate directive should point to your fullchain.pem file and the ssl_certificate_key directive should point to your privkey.pem file:

listen 443 ssl http2;
listen [::]:443 ssl http2;

ssl_certificate /etc/letsencrypt/live/pluto.ashleyrich.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/pluto.ashleyrich.com/privkey.pem;

The http2 value is all that is needed to enable HTTP/2 support. Save and close the file by hitting CTRL X followed by Y. Before reloading the Nginx configuration, ensure there are no syntax errors.

sudo nginx -t

If no errors are shown, reload the configuration.

sudo service nginx reload

Now if you visit your site in the browser using HTTP you should receive an empty response. However, when visiting using HTTPS the site should successfully load and show the green pad lock icon in the address bar. If the site times out, remember to ensure that you have opened port 443 on your server firewall!

The final step is to update the WordPress address and site URL.

SSL - Image 6

Redirect HTTP Traffic to HTTPS

At the moment all HTTP traffic is dropped by the server. Instead you should redirect all HTTP traffic to HTTPS. Open the site’s virtual host file and add a new server block below the existing one:

server {
    listen 80;
    listen [::]:80;
    server_name pluto.ashleyrich.com;

    return 301 https://$server_name$request_uri;
}

Reload Nginx for the changes to take effect, but remember to test the configuration first. Now you should be redirected to HTTPS when visiting the site via HTTP.

Renewing Certificates

Certificates obtained through Let’s Encrypt automatically expire after 90 days, therefore you need to renew them often. Luckily, the Certbot client has a command which will renew all certificates which are due to expire in the next 30 days. To automate the process you can add this command to a cron job. The command will need to be executed with heightened permissions so it should be added to the root user’s crontab:

sudo crontab -e

Add the following command to the end of the file:

0 0,12 * * * letsencrypt renew >/dev/null 2>&1

This will attempt to renew certificates twice daily. Certificates which are not due to expire in the next 30 days will be skipped.

SSL Hardening

Although your site is configured to only handle HTTPS traffic it still allows the client to attempt further HTTP connections. Adding the Strict-Transport-Security header to the server response will ensure all future connections enforce HTTPS. This article by Scott Helme gives a more thorough overview.

Add the following directive to the http block.

add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";

You may be wondering why the 301 redirect is still needed if this header automatically enforces HTTPS traffic: unfortunately the header isn’t supported by IE10 and below.

Check your Nginx config and reload if successful.

sudo nginx -t
sudo service nginx reload

Now if you perform a scan using the Qualys SSL Test tool you should receive a grade A+. Not bad!

SSL - Image 8

SSL Performance

HTTPS connections are a lot more resource hungry than regular HTTP connections. This is due to the additional handshake procedure required when establishing a connection. However, it’s possible to cache the SSL session parameters, which will avoid the SSL handshake altogether for subsequent connections. Just remember that security is the name of the game, so you want clients to reauthenticate often. A happy medium of 10 minutes is usually a good starting point.

Open the main Nginx configuration file.

sudo nano /etc/nginx/nginx.conf

Add the following directives within the http block.

ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;

Test the Nginx configuration and reload if successful.

sudo nginx -t
sudo service nginx reload

The final nginx.conf file can be seen below, which includes everything from this series so far.

Job done! Hopefully this guide has given you a good insight into securing your sites with HTTPS. Let me know in the comments below if there are any other precautions you take.

About the Author

Ashley Rich

Ashley is a PHP and JavaScript developer with a fondness for solving complex problems with simple, elegant solutions. He also has a love affair with WordPress and learning new technologies.