Setting up HTTPS site encryption for a client's WordPress site

Written by on in Graz, Austria.

Thanks to Google’s public endorsement of HTTPS as a ranking-factor last year, convincing even non-technical people of using site encryption has become a lot easier. Of course, for geeks, it’s still about privacy and future-compatibility but leaving motives aside, HTTPS has finally arrived at the mainstream of website owners and developers.

Local testing

The client’s site includes a WooCommerce store and every minute the site is offline or defunct results in a potential loss of money. Therefore I staged all the changes locally. Since I had the whole site already set up locally from previous projects, there was little to do except generating a certificate, including that into the web server and crossing fingers.

I have described how I generally set up my local development environment in the How I work article.
Thanks to the VVV wiki article the task was a matter of minutes:

1. Generate a key and certificate file for the development domain.

openssl genrsa -out asb-hd.dev.key 2048

openssl req -new -x509 -key asb-hd.dev.key -out asb-hd.dev.cert -days 3650 -subj and/CN=asb-hd.dev

2. Edit the site specfic nginx config file to load the generated files and restart the server.

server {
    # Determines the port number that nginx will listen to for this
    # server configuration. 80 is the default http port.
    listen       80;

    # Listen for HTTPS requests as well
    listen       443 ssl;

    # Tells nginx what domain name should trigger this configuration. If
    # you would like multiple domains or subdomains, they can be space
    # delimited here. See http://nginx.org/en/docs/http/server_names.html
    server_name  asb-hd.dev;

    # Tells nginx which directory the files for this domain are located
    root         {vvv_path_to_folder}/htdocs;

    # Includes a basic WordPress configuration to help with the common
    # rules needed by a web server to deal with WordPress properly.
    include /etc/nginx/nginx-wp-common.conf;

    ssl    on;
    ssl_certificate    {vvv_path_to_folder}/ssl/asb-hd-dev.cert;
    ssl_certificate_key    {vvv_path_to_folder}/ssl/asb-hd.dev.key;
}

3. Tell OS X to always accept the self-generated certificate.

  1. Open the “Keychain Access” application, in Finder > Applications > Utilities
  2. Drag and drop the cert file into the application window
  3. Select “Always Trust” in the dialog box which appears

To test that the certificate was actually properly set up I started with activating it for the admin area only by adding a constant to wp-config.php:

<?php define('FORCE_SSL_ADMIN', true);

The login page automatically switched to HTTPS and after login worked too, I was happy to see that the certificate was actually working. Next, I tried manually calling the public facing site by entering its URL with the https protocol.

That’s where the first issues became visible: Chrome showed a “broken” padlock next to the site address and reported that the site was requesting unencrypted resources. This essentially renders HTTPS useless and most modern browsers inform the user about certificate problems in a way that must make the launch of a thermo-nuclear missile look comparatively casual. So let’s better get rid of that.

A glance into the console revealed more information about the offending resources:

errors%402x

From the name of the images I could tell that some of them were served directly by WordPress and changing the site’s address to include the HTTPS protocol would automatically take care of them. However some of them were part of user-created content such as text widgets or post content. That means one either had to change them manually for every piece of content in the site or look for a way to automate it.

Incidentally I had used a plugin called Better Search Replace a couple of weeks before, when I switched the site from its development domain to its final production domain. That plugin was still installed so I quickly ran a test query to replace all instances of http:// in the database with https://.

That query returned almost 4000 instances which reassured me that there was no way I was going change all of them manually.

There were however 2 things to consider:

To get around these considerations I first ran a global replacement of http://asb-hd.de to https://asb-hd.de. Next, I changed https://asb-hd.de to //asb-hd.de but excluded the GUID column of the posts table.

Unfortunately that last change also set the site URL to a protocol-relative address which I quickly undid because it left me unable to login to the admin area.

Reloading the browser window showed zero mixed content and a green padlock in all browsers for the local version of the site. Yay!

Applying the changes in production

With the certificate already at hand and set up on the production server by the hosting company, my only job here was taking care of the database changes already mentioned before.

Additionally I enforced HTTPS on the Apache-powered production server via a .htaccess file:

# Force HTTPS
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
outlook

Et voilà, many happy green padlocks everywhere:

firefox
chrome

Which leaves only one awkward question: When will I finally use it for my own site? Given that Let’s Encrypt could actually launch successfully there should be little reason left why not to.