Categories
Technology Web

Moving to HTTPS: First, you upgrade everything

I was one of the lucky folks who received an email from Google warning me that it was going to start marking input fields in my sites as unsafe. “Time to move to HTTPS”, it smugly informed me.

It irks me that we’ve given a company such power over us that it can force us into using technology before we’re ready. However, I knew it was a matter of time before I’d have to go to HTTPS, so decided to just bite the bullet and get it done.

But if I move to HTTPS, I’m making the task a component of an overall site upgrade.  That was my original intent all along…incorporating HTTPS into a total site makeover. Except my plan was to finish by year-end, rather than October. Best laid plans…

To prepare for HTTPS, I

  • Cleaned up my site, removing statically generated HTML pages
  • Upgraded from Ubuntu 14.04 to Ubuntu 16.04
  • Upgraded Apache 2.2 to Apache 2.4
  • Severely restricted port access via the firewall
  • Moved my DNS Zone files to my name registrar
  • Installed SSL digital certificates for all domains
  • Corrected mixed content errors and incorporated HTTPS into my content management system (WordPress)
  • Made the decision to go all the way to HSTS

Prior to the HTTPS Move: Mixed Content Concerns

HTTPS is a secure transport protocol that encrypts traffic to and from the website. It is more secure for the users, but it adds a level of complexity to managing a website—especially if you’ve had websites for years, with an accumulation of statically generated HTML pages and other eclectic resources.

The big problem is a concern called mixed content. If you have a web page that includes links to JavaScript or CSS files using absolute URLs, such as http://mysite.com/style.css, and you access the page using HTTPS, folks are going to get a warning that the page is accessing insecure content. This is actually a lot scarier to folks then accessing a page that’s completely insecure.

Since I didn’t want to attempt to programmatically alter statically generated HTML pages from various content management systems, I have been manually copying the content I want to keep from older pages into my newest WordPress site. However, the going was slow, and Google was demanding.

So, I download all of the static web pages to my PC, and over time, I’ll add them to my new system. Unfortunately, I now get, on average, 700+ 404 errors a day. Also unfortunately, I’ll lose commentary attached to the old pages. My solution is to link to the Wayback Machine archive page for the content whenever possible, so people can see the page as it existed in all its original glory.

(Needless to say, I donate to the Internet Archive annually.)

Upgrading the Server, moving DNS records

The static HTML web pages gone, next up is upgrading the server’s operating system. I wrote about this effort in a separate post. Thanks to my VPS hosting company, the effort went smoothly. Some hiccups in moving from Apache 2.2 to Apache 2.4, but nothing that couldn’t be fixed.

As part of the move, since I’m updating the DNS records with a new server IP address anyway, I moved my DNS management from my Linode server to my Namecheap name registrar. Unlike some other registrars that require you to host with them if you want this capability, Namecheap provides DNR management to anyone, even those folks who aren’t its customers.

Namecheap also provides email forwarding based on the domains. Using this functionality, I’m able to eliminate the need for an email server (Postfix) on my server. This eliminates most of the new server installation hassles, as well as most of the traffic problems to my site.

OK, now that I’ve all but burned sage over my server to purify it. Time to go HTTPs.

Getting to HTTPS…finally

To serve your pages using HTTPS you have to install a digital certificate. Prior to 2016, doing so was both cumbersome and expensive. Since the advent of Let’s Encrypt, though, the process is much more manageable.

Let’s Encrypt is, as they note in bold letters on the front page, a free, open, and automated certificate authority. In other words, it doesn’t cost you a thing, and they provide an application,  certbot, that simplifies the installation of the digital certificate.

After installing certbot, for each domain I used the standard Apache certificate installation procedure, specifying the domain name:

sudo certbot --apache -d burningbird.net

The application asks for an email (the first time, only), and then whether I want to allow both HTTP and HTTPS, or to force https. I decided not to force https until I could see what happened with my WordPress installation.

When the application finished, the certificate is installed in /etc/letsencrypt/archive, the key in /etc/letsencrypt/keys, and the symlinks for the latest version in /etc/letsencrypt/live. In addition, the application creates a new Apache VHOST configuration file. Shelley’s Toy Box configuration file is:

<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerAdmin shelley.just@gmail.com
ServerName shelleystoybox.com
ServerAlias www.shelleystoybox.com
DocumentRoot /****/public_html/

<Directory /****/public_html>
   Options FollowSymLinks
   AllowOverride All
   Require all granted
   DirectoryIndex index.html index.php
</Directory>
ErrorLog /home/bigmama/logs/error.log
CustomLog /home/bigmama/logs/access.log combined
SSLCertificateFile /etc/letsencrypt/live/shelleystoybox.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/shelleystoybox.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>

Note the port number change, from 80 to 443. Port 443 is the standard port for HTTPS. Also note the certificate location references.

Once Apache was reloaded, I was ready to go. Since Let’s Encrypt certificates expire in 90 days, I added a cron job that runs daily and issues the certbot renew command. The application will run with root permissions as long as we edit root’s crontab:

01 01 * * * certbot renew

I repeated the same action for all domains. You can also do the same with subdomains, and I explain how you can add subdomains later in this writing.

One last step to HTTPS Nirvana: making HTTPS work with my content management system.

Supporting HTTPS in WordPress

We can manually make the modifications to serve pages as HTTPS in WordPress, but I didn’t want to see what would happen with content that’s several years old, as well as multisite. I splurged on the Really Simple SSL pro multisite plugin.

Really Simple SSL is a popular free plugin that modifies the .htaccess file to enforce HTTPS, as well as fixing mixed-content issues. The multisite plugin is an add-on for the free version, adding additional functionality, such as per-site HTTPS management.

Unfortunately, the first time I turned on HTTPS, I was kicked out to log back in again, but the login page kept failing. I suspect it was the order in which I implemented the plugins.

I used the force-deactivate.txt file that the company provides, after first renaming the extension to .php. Once I opened it in a web page, Really Simple SSL was deactivated. I could then log back into the site. After returning the file to its .txt extension, I was able to, first, enable the Really Simple SSL plugin, then the multisite plugin.

What’s nice about the multisite plugin is I can fine tune the HTTPS settings for each domain, rather than using just one blanket setting for all. There is virtually no documentation for the plugin, but most of the options are intuitive.

I used Really Simple SSL’s options to force HTTPS, fix the mixed content errors using the WordPress backend, as well as automatically fix mixed content errors. I also turned on  HTTP Strict Transport Security (HSTS) support, but at the time, this wasn’t working. The plugin has since been updated to fix the headers necessary for HSTS. But HSTS is more than changing headers—it’s a major site commitment.

Moving to HTTP Strict Transport Security (HSTS)

HSTS is the next big ‘push’ from the tech companies. A header is generated for the content letting the browser know to redirect all HTTP requests to HTTPS. This increases the security for the user, but it comes with a cost.

For instance, all subdomains have to be served as HTTPS, even if you don’t need to have them served as HTTPS. This includes the ‘www’ subdomain. And once you’re listed as HSTS, it’s a bugger to clear this state if, for some reason, you won’t be serving pages as HTTPS.

Really Simple SSL actually didn’t serve the header, as the option implies. (This has since been fixed.) However, another WordPress plugin, Security Headers, does. But serving the header is only one small component of the entire process. In particular, the subdomain requirement was almost a non-starter for me for the burningbird.net domain, since I use some subdomains for development, and the protocol I use can impact on application behavior.

Once you make the HSTS decision, you’re committed. You can get your domain removed from the HSTS lists, but it’s very difficult and will take time.

In the end, I decided if I was going to go through all the hassle to get HTTPS to work, I was going to finish the process and go all the way to HSTS.

First, I needed to turn on SSL and connect a certificate for all the subdomains I support with burningbird.net. Let’s Encrypt will be supporting wildcard digital certificates in January, where you can use one certificate for all subdomains, but for now, I have to issue one for all the subdomains individually.

To get this to work, I needed to use certbot to expand my digital certificate.  What this does is allow me to package the subdomains with the top-level domain:

sudo certbot --expand -d burningbird.net,www.burningbird.net,docs.burningbird.net

When I asked this time whether to force HTTPS directly in the vhost file, I answered yes. Certbot modified my port 80 vhost file for burningbird.net, adding the following:

<VirtualHost *:80>
ServerAdmin shelley.just@gmail.com
ServerName burningbird.net
ServerAlias www.burningbird.net
DocumentRoot /****/public_html/

<Directory />
....
RewriteEngine on

RewriteCond %{SERVER_NAME} =burningbird.net [OR]
RewriteCond %{SERVER_NAME} =www.burningbird.net
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

Once I expanded all of my domains to include the www subdomain, and all the vhost files were modified, I could remove the forced HTTPS redirect in the .htaccess file.

Next, I tested the pages at burningbird.net, since it had probable mixed-content issues. I used the Qualys SSL Server Test, which does a deep dive into the site. It came back on both IPv4 and IPv6 with a grade of A+.

Now I was ready to add the HSTS header. The Security Header plugin allows you to not only specify the HSTS header, but also disable content sniffing, enable chrome XSS protection, and other features. I turned on these two options, and set the HSTS time to live value to 31536000.

Normally, when you’re going HSTS, you set the time to live to a tiny amount, and then gradually build up to the minimum max age of 18 weeks. Most of my domains are new with new content, and I’ve already stripped all my static HTML pages. I’ve tested my burningbird.net domain, all my subdomains, and everything is working. And I wanted to be done.

So I set the time to live to 31536000, which is a year. Google recommends two years, but I’m using one year as a tiny act of defiance. My site, my time to live.

Once the HSTS header is properly implemented, my last act that truly commits me to HSTS is to add my sites to the HSTS Preload lists. The lists page accepts a domain, checks for the header, checks all subdomains, and if everything is OK, asks if you own the domain and want to be listed. Checking OK for both and I’m off and running.

Eventually, all the major browsers will know that when they get to my domains, to never use anything but HTTPS for the domain and any subdomains. This eliminates any accidental or deliberate attempts to send a domain page to HTTP, including preventing man-in-the-middle attacks.

The requirements for subdomains for HSTS did lead to one more challenge in WordPress.

Back to WordPress for a subdomain fix

Incorporating support for HSTS requires all subdomains to be served as HTTPS. I have had several odds and ends subdomains in the past, and I thought about just dropping their DNS records.

I decided, instead, to leave the DNS records, and expand my certificates even further by listing out all of the subdomains I have had, but redirect them all to my primary burningbird.net domain. This worked quite well, but it ran into issues with my WordPress multisite installation.

Every time a person would type in one of the subdomains, such as realtech.burningbird.net, it would redirect to burningbird.net, but the multisite installation would then push me to the registration page to register the subdomain as a proper website. The page would display “Greetings Site Administrator! You are currently allowing “none” registrations. To change or disable registration go to your Options page.” to me, as Administrator, but “Registration is closed” to everyone else. Not especially helpful.

The addition of the following in the wp-config.php file solved this problem:

define('NOBLOGREDIRECT', 'https://burningbird.net');

Now, the subdomain just redirects back to the burningbird.net front page, and all is finally well.

The “I don’t know about you all but I’m tired” summary

With the addition of Wordfence for WordPress security, my firewall, and now HTTPS, my site is as safe as I can possibly make it.

If you go out to the Google webmaster forum and express your unhappiness at the email I referenced at the beginning of this writing, you’ll be assured that moving to HTTPS is a piece of cake…ten minutes at most.

Well, that’s just naive balderdash.

Even if an individual has the cleanest site in the world (most of us don’t), and no static HTML pages (unlikely for people who have had a website for years), they’ll either have to have SSH access to their site, or be hosted with a company that isn’t going to profit off them being forced to install a digital certificate.

Then there’s the extra complexity of getting a digital certificate for every single subdomain one has. This shouldn’t be a problem in the future with Let’s Encrypt, as it will be supporting a ‘wildcard’ certificate starting in January that can cover all subdomains for a domain.  Even then we’ll be ‘encouraged’ to go HSTS, and then the question is do we want every single subdomain to be served as HTTPS?

Still, when you accessed this page, you accessed it as HTTPS not HTTP. You can be assured from that little lock in the corner that yes, the site is secure. Well, unless my server gets hacked by someone smarter than my firewall and Wordfence, and malware gets embedded into the page that will end all life as we know it.

But that’s a challenge for another day.