Switching to https

A step-by-step guide to enabling TLS on Apache.

As promised at Indie Web Camp, here are the steps I took to make my site https:// only.

Now, here’s the thing with any of these walkthroughs; they’re all very specific to host/server combo in question. My particular combination is:

  1. Hosting on a Digital Ocean virtual machine running Ubuntu 14.04 (typing lsb_release -a on the server will tell you which version of Ubuntu you’re running).
  2. Running Apache 2.4.7 (typing apache2 -v will tell you which version of Apache is running).

If you’re using another flavour of Linux, or running Nginx, this walkthrough will probably not help you. You’ll also need admin access to the server. If you’re on shared hosting, you may well be screwed from the get-go.

To start with, you need to get your magic certificates from a Certificate Authority. So the first question is: who is a good Certificate Authority?

Choose a Certificate Authority

There is no such thing as a good Certificate Authority.

It’s a racket.

The best you can hope for is to deal with a Certificate Authority that doesn’t charge too much and doesn’t make the process as painful as applying a power drill to your teeth.

My pain was mitigated by my DNS provider, DNSimple. They have a one-clickish process for applying for a certificate. They charge $20 a year for a single hostname, which is not too bad. If that’s still too rich for your blood, you can look into navigating the interface at StartSSL. Good luck with that.

Until last week, DNSimple were using RapidSSL to issue those single-hostname certificates. RapidSSL still issues SHA-1 certificates by default, which is not good. But after a little prompting, DNSimple switched to Comodo for their single-hostname certificates, which means you can get yummy SHA256 encryption.

Make a private key and CSR

DNSimple can even take care of generating a private key and a Certificate Signing Request (the two chunks of encrypted gibberish you need to send to the Certificate Authority to get your certificate). Otherwise you’ll need to generate those for yourself. To do that, ssh into your server and run this, swapping out yourdomain_com for, you guessed it, your domain:

openssl req -new -newkey rsa:2048 -nodes -keyout /etc/ssl/private/yourdomain_com.key -out /etc/ssl/certs/yourdomain_com.csr

..and answer the probing questions that your nosy server will ask of you. You’ll then have two files:


You can then copy and paste the contents of those files when you’re applying for a certificate from your CA of choice. I can’t walk you through that process because, like I said, I managed to skip over it completely by having DNSimple do all the work.

I still had to put the private key on my server so I created the file:

nano /etc/ssl/private/yourdomain_com.key

And then I pasted the private key in there, hit ctrl o and then hit enter to write out the file, followed by ctrl x to close it.

(If some of these command line things don’t work for you, try prefixing them with sudo, try again, and enter your password when prompted.)

See how this is getting more and more specific to my particular combination? Now I’m talking about installing a Comodo certificate (acquired through DNSimple) on Apache 2.4 on Ubuntu 14. If you’re using a Certificate Authority other than Comodo, the next step won’t mean much to you.

Install your certificate on your server

There’s some documentation on the Comodo site for this step. At this point, you should have received a zip file from Comodo with four files:

  1. AddTrustExternalCARoot.crt
  2. COMODORSAAddTrustCA.crt
  3. COMODORSADomainValidationSecureServerCA.crt
  4. yourdomain_com.crt

Open a text editor on your computer and create a new file by copying and pasting the contents of these files in this order:

  1. COMODORSADomainValidationSecureServerCA.crt followed by
  2. COMODORSAAddTrustCA.crt follwed by
  3. AddTrustExternalCARoot.crt

On your server, create a new file by typing:

nano /etc/ssl/certs/yourdomain_com.ca-bundle

Paste in the combined contents of the text file from your computer. Hit ctrl o (followed by enter) to write out the file and ctrl x to close it.

That leaves one file, which is your actual certificate, yourdomain_com.crt

On your server, type:

nano /etc/ssl/certs/yourdomain_com.crt

Copy and paste the contents from the certificate file (yourdomain_com.crt) in there. Hit ctrl o to write out the file and ctrl x to close it.

Set up https on Apache

Remember, this is for Apache 2.4. Things will be subtly different on previous versions. For instance, on Apache 2.4, all the files in /etc/apache2/sites-available must end with .conf; that wasn’t the case with previous versions.

First things first. You need to enable the ssl module for Apache. On your server, type:

a2enmod ssl

(Again, if that doesn’t work straight away, try prefixing it with sudo.)

Now restart Apache:

service apache2 restart

Your Apache server is now capable of serving over https, but you still need to give it more details.

Go into the sites-available directory by typing:

cd /etc/apache2/sites-available

You can see all the files in this folder by typing ls. I’m going to assume that you’ve got the server serving up just one site and that the details of that site are in the 000-default.conf file which serves up your site over port 80. You’ll want to copy any details you have set up in 000-default.conf over to default-ssl, but with the difference that the port number is 443. The top of your default-ssl file should look something like this:

<IfModule mod_ssl.c>
    <VirtualHost *:443>
            ServerAdmin you@yourdomain.com
            ServerName yourdomain.com
            ServerAlias www.yourdomain.com
            DocumentRoot /var/www

It might be that your DocumentRoot is /var/www/html. That’s fine (as long as that’s where your website’s files are actually sitting).

Oh, I should have mentioned: the way that you can examine (and edit) that default-ssl.conf is by typing:

nano /etc/apache2/sites-available/default-ssl.conf

Comment out these two lines by placing a # at the start of each line:

#SSLCertificateFile     /etc/ssl/certs/ssl-cert-snakeoil.pem
#SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key

Right under those lines, add these:

SSLCertificateFile    /etc/ssl/certs/yourdomain_com.crt
SSLCertificateKeyFile /etc/ssl/private/yourdomain_com.key

Now you’re pointing at your hard-earned certificate and your private key. You still need to point to that bundle file you created earlier.

Comment out this line by putting # at the start of it:

#SSLCertificateChainFile /etc/apache2/ssl.crt/server-ca.crt

Right underneath it type:

SSLCertificateChainFile /etc/ssl/certs/yourdomain_com.ca-bundle

Now page down to near the end of the file by hitting ctrl v. Right before the closing /VirtualHost tag, add these lines:

SSLProtocol All -SSLv2 -SSLv3
SSLHonorCipherOrder On
SSLCompression off

That line beginning with SSLCipherSuite needs to be all one line so watch out for line breaks if you’re copying and pasting. It’s quite an impressive bit of unintelligible gibberish, isn’t it?

Write out the default-ssl.conf file by hitting ctrl o, followed by enter, and exit this hellish text editor by hitting ctrl x.

Type this (you might need to sudo it):

a2ensite default-ssl.conf

Do the Apache restart dance by typing:

service apache2 reload

You might see a message like “Could not reliably determine the server’s fully qualified domain name…” Don’t worry about it. If, on the other hand, you see an error message that Apache can’t restart, worry about it.

Open your website in a browser; http://yourdomain.com — you should see no difference whatsoever. But now type https://yourdomain.com (but, y’know, swapping out yourdomain.com for your domain). Again, everything should look exactly the same but with one crucial difference: a shiny green lock in the corner of the URL bar indicating that the site is secure.

Redirect http to https

Once you’re happy with the way the https version of your site is working, you can make it the default.

Before doing this, it’s worth making sure that you haven’t hardcoded any images, scripts, or other external files with http:// URLs. If you’re pointing to third-party resources, most of them should also be available over https. Don’t forget that you can use protocol-relative URLS: //fontdeck.com/etc instead of http://fontdeck.com/etc or https://fontdeck.com/etc.

To switch http requests for your site over to https, you’ll need to edit the file that has your port 80 details. That’s probably 000-default.conf in /etc/apache2/sites-available.

Open up that file:

nano /etc/apache2/sites-available/000-default.conf

The top of the file should look something like this:

<VirtualHost *:80>
    ServerAdmin you@yourdomain.com
    ServerName yourdomain.com
    ServerAlias www.yourdomain.com
    DocumentRoot /var/www

Again, the details might be slightly different for you: your DocumentRoot might by /var/www/html. Either way, add this line right after that DocumentRoot line:

Redirect / https://yourdomain.com/

(Swapping out yourdomain.com for your domain.)

Do the keyboard shortcut mambo: ctrl o, enter, ctrl x.

Do the Apache restart shuffle:

service apache2 restart

Now try visiting http://yourdomain.com in a browser. You should be automatically redirected to https://yourdomain.com …I really hope it works for you.

Enable HSTS

If you’ve made it this far and everything is working, well done! You have patience and fortitude in equal measure.

Go to ssllabs.com/ssltest and paste in your site’s domain name to see how well your site is doing in the security stakes. You’ll be given a grade, which will bring back all sorts of horrible memories of school tests.

If you’ve been given an A grade, there’s a way to level up to A+. You can enable HTTP Strict Transport Security. No, I don’t understand what it means either.

Go back to the command line on your server. You need to enable the headers module for Apache. Again, you may need to sudo this one:

a2enmod headers

Restart Apache:

service apache2 restart

Now dive back into that default-ssl.conf file:

nano /etc/apache2/sites-available/default-ssl.conf

Hit ctrl v to page down to right before that closing /VirtualHost tag. Add this line right after the gobbledygook you added previously:

Header always set Strict-Transport-Security "max-age=63072000"

You know the drill: ctrl o, enter, ctrl x.

Command Apache to restart before Zod!

service apache2 restart

On ssllabs.com/ssltest hit “clear cache” to test your site again. You should be rewarded with a higher grade and a feeling of smug self-satisfaction. Here’s adactio and here’s Huffduffer.


I hope that this walkthrough will be of some use to you. But the chances are that unless you are also using Comodo as your Certificate Authority and you’re running Apache 2.4 on Ubuntu 14, there will be some sort of difference between your setup and mine that could render all of this null and void.

If you run into problems, I probably can’t help you. I’m a complete n00b at this stuff, and if it hadn’t been for Tim’s hand-holding, I doubt I ever would’ve managed.

The https page on the Indie Web Camp is a handy resource that links off to other tutorials.

If you’re serving your site on Cloudfront, Josh’s walkthrough should be very helpful.

If you do make the switch from http to https, please, please, please document each step along the way, and then publish it. There are plenty of articles and blog posts telling us why we need to switch on TLS, but not nearly enough articles and blog posts telling us how.

Saying “You should enable TLS—it’s easy!” can be damaging on two counts:

  1. The first part is redundant: we all know that we should be doing this.
  2. The second part just makes us feel bad. It’s like telling someone “You should play guitar—it’s easy!” Yeah, it’s easy if you already know how to play guitar.

If you’re a l33t server wizard and you care about this https stuff—which you almost certainly do—I urge you to divert the time and energy you might consider putting into advocacy and instead put that time and effort into helping n00bs like me. If you can gather willing web developers in the same physical space—like Tim did at Indie Web Camp—I think you can achieve maximum knowledge dispersement. (Perhaps Google/Mozilla/Opera/Microsoft dev rels could sponsor TLS days in various cities and towns?)

The issue with https is not that web developers don’t care or understand the importance of security. We care! We understand!

The issue with https is that it’s really bloody hard.

But it’s worth persevering with it.


Aaron Gustafson

I’ve been complaining about “man in the middle” attacks brought on by internet service providers a bunch over the last year. The only way to keep uninvited third parties from injecting JavaScript and more—potentially screwing up your page—is to move to HTTPS. So, as much as it pains me to abandon good old fashioned HTTP, I’ve decided to lock things down a bit.

I was using Github to host my site as a Github page. It worked really well given this is a static site, but you can’t run Github-hosted sites under HTTPS unless you go with their *.github.io domain name (they have a wildcard certificate for that domain). There’s been a ton of interest in Github allowing custom cert installation, but no movement yet, so… onward!1

I opted to move to DigitalOcean since my consultancy recently relocated all of its sites there in a mass exodus from MediaTemple. Migrating the site was as simple as setting up the DigitalOcean server as a new “live” remote on my local git install and pushing it up there. Since it’s a static site, I didn’t have to worry too much about the server config. Apache is really great at hosting static files.

With the contents in place, I went through the rather convoluted process of getting SSL set up following the instructions from DigitalOcean. I opted for the free StartSSL certificate to begin with (a rather convoluted process, but we got there in the end) and then flipped the DNS records to point to the new box. Given that the StartSSL certificate needs to be renewed every 30 days, I may opt for a paid certificate in the not too distant future.

Once the DNS propagated, I had to go back and button up a few scripts that were requesting non-HTTPS content. I also had to tweak my Jekyll plugins and Rake tasks to include the legacy “http://” URLs when querying for webmentions and the like (since I didn’t want to lose those references). I also updated the Apache’s VirtualHost configuration for the non-secure site to make all traffic redirect:

Redirect permanent / https://www.aaron-gustafson.com/

All in all, it was a relatively painless migration. Admittedly, the initial re-build of the site (after updating the Rake tasks) did re-submit all of the webmentions I’d previously sent in order to provide the new address. If I referenced you a bunch in the past, I apologize for the flood of traffic, but it had to be done.

Anyway, so now this site is running under HTTPS. If you encounter any issues, please let me know. And if you want to read a really good account of migrating a site to HTTPS, you should definitely read Jeremy Keith’s step-by-step guide.

  1. It’s worth noting that the source of the site (and even a back-up build) will remain on Github for the forseeable future.


Remy posted a screenshot to Twitter last week.

That “Add To Home Screen” dialogue is not something that Remy explicitly requested (though, of course, you can—and should—choose to add adactio.com to your home screen). That prompt appears in Chrome on Android as the result of a fairly simple algorithm based on a few factors:

  1. The website is served over HTTPS. My site is.
  2. The website has a manifest file. Here’s my JSON manifest file.
  3. The website has a Service Worker. Here’s my site’s Service Worker script (although a little birdie told me that the Service Worker script can be as basic as a blank file).
  4. The user visits the website a few times over the course of a few days.

I think that’s a reasonable set of circumstances. I particularly like that there is no way of forcing the prompt to appear.

There are some carrots in there: Want to have the user prompted to add your site to their home screen? Well, then you need to be serving on a secure connection, and you’d better get on board that Service Worker train.

Speaking of which, after I published a walkthrough of my first Service Worker, I got an email bemoaning the lack of browser support:

I was very much interested myself in this topic, until I checked on the “Can I use…” site the availability of this technology. In one word “limited”. Neither Safari nor IOS Safari support it, at least now, so I cannot use it for implementing mobile applications.

I don’t think this is the right way to think about Service Workers. You don’t build your site on top of a Service Worker—you add a Service Worker on top of your existing site. It has been explicitly designed that way: you can’t make it the bedrock of your site’s functionality; you can only add it as an enhancement.

I think that’s really, really smart. It means that you can start implementing Service Workers today and as more and more browsers add support, your site will appear to get better and better. My site worked fine for fifteen years before I added a Service Worker, and on the day I added that Service Worker, it had no ill effect on non-supporting browsers.

Oh, and according to the Webkit five year plan, Service Worker support is on its way. This doesn’t surprise me. I can’t imagine that Apple would let Google upstage them for too long with that nice “add to home screen” flow.

Alas, Mobile Safari’s glacial update cycle means that the earliest we’ll see improvements like Service Workers will probably be September or October of next year. In the age of evergreen browsers, Apple’s feast-or-famine approach to releasing updates is practically indistinguishable from stagnation.

Still, slowly but surely, game-changing technologies are landing in browsers. At the same time, the long-term problems with betting on native apps are starting to become clearer. Native apps are still ahead of what can be accomplished on the web, but it was ever thus:

The web will always be lagging behind some other technology. I’m okay with that. If anything, I see these other technologies as the research and development arm of the web. CD-ROMs, Flash, and now native apps show us what authors want to be able to do on the web. Slowly but surely, those abilities start becoming available in web browsers.

The pace of this standardisation can seem infuriatingly slow. Sometimes it is too slow. But it’s important that we get it right—the web should hold itself to a higher standard. And so the web plays the tortoise while other technologies race ahead as the hare.

It’s interesting to see how the web could take the desirable features of native—offline support, smooth animations, an icon on the home screen—without sacrificing the strengths of the web—linking, responsiveness, the lack of App Store gatekeepers. That kind of future is what Alex is calling progressive apps:

Critically, these apps can deliver an even better user experience than traditional web apps. Because it’s also possible to build this performance in as progressive enhancement, the tangible improvements make it worth building this way regardless of “appy” intent.

Flipkart recently launched something along those lines, although it’s somewhat lacking in the “enhancement” department; the core content is delivered via JavaScript—a fragile approach.

What excites me is the prospect of building services that work just fine on low-powered devices with basic browsers, but that also take advantage of all the great possibilities offered by the latest browsers running on the newest devices. Backwards compatible and future friendly.

And if that sounds like a naïve hope, then I humbly suggest that Service Workers are a textbook example of exactly that approach.

# Sunday, November 15th, 2015 at 10:56pm


A lot of folks have been very vocally pushing for “HTTPS Everywhere”, and for good reason. The fact that the lack of HTTPS makes you miss out on shiny new things like HTTP/2 and Service Workers adds even more incentive for those a little less inspired by the security arguments.

Unfortunately, moving to HTTPS can be kind of painful as you can see from Jeremy Keith’s excellent post detailing exactly how he got adactio.com onto HTTPS. He pinpoints the major obstacle with HTTPS adoption at the end of his post:

The issue with https is not that web developers don’t care or understand the importance of security. We care! We understand!

The issue with https is that it’s really bloody hard.

Let’s Encrypt—a new certificate authority from the Internet Security Research Group (ISRG)—has been promising to help with this, pledging to be “free, automated and open”.

They just announced public beta today, so I decided to give the beta version of their system a try on wpostats.com. Like Jeremy’s blog, WPO Stats is housed on a Digital Ocean virtual machine running Ubuntu 14.04 and Apache 2.4.7.

Getting Let’s Encrypt installed

The first thing I had to do was get the Let’s Encrypt client installed. To do this, I logged into the WPO Stats server and followed the instructions on the Let’s Encrypt repo.

First I grabbed the repo using git:

git clone https://github.com/letsencrypt/letsencrypt

Once git had done it’s magic and pulled down the Let’s Encrypt client, I needed to actually install it. To do that, I navigated to the newly created letsencrypt directory and then ran the Let’s Encrypt client with the help flag enabled.

cd letsencrypt

./letsencrypt-auto --help

This does that scary-looking thing where it downloads a bunch of different dependencies and gets the environment setup. It went off without a hitch and after a few moments it completed and told me I was ready to begin.

Obtaining and installing a certificate

The install process was smooth, but I was bracing myself for the actual SSL setup to be a bit more painful. As it turns out, I didn’t have to worry.

To run the client and get my certificate, I ran the same command without the help flag:


This popped up a pleasant little GUI (Figure 1) that walks through the rest of the process. The first screen it popped up was a warning.

No names were found in your configuration files. You should specific ServerNames in your config files in order to allow for accurate installation of your certificate. If you do use the default vhost, you may specify the name manually. Would you like to continue?

Figure 1: First screen of the letsencrypt client GUI banner.

In this case, I only use the server for WPO Stats—nothing more. This means that, yes, I use the default vhost. I selected ‘Yes’ and moved along. Where this might be different is if you were hosting multiple domain names on a single server. For example, if I ran this site on the same server, I may have virtual hosts set for both timkadlec.com and wpostats.com and would need to have that specified in my config files.

The next three prompts were straightforward. I had to enter my domain name, my email address, and then accept the terms of service. I’ve always liked easy questions.

After that, I was prompted to choose whether I wanted all requests to be HTTPS, or if I wanted to allow HTTP access as well. I had no reason to use HTTP for anything, so I selected to make everything secure.

Figure 2: GUI screen for choosing to make everything HTTPS or keep HTTP around.

And, well, that was it. The next GUI prompt was informing me I was all set and that I should probably test everything out on SSL Labs.

Figure 3: Final screen of the letsencrypt GUI informing me I was victorious.

I checked the site, and everything was in working order. I ran the SSL Labs test and everything came back a-ok. For once, it really was as simple as advertised.

I felt like trying my luck so I went through the process again for pathtoperf.com and, again, it went through without a hiccup. All told it took me about 10 minutes and $0 to secure both sites. Not bad at all.

Going forward

The improvement between the obnoxiously complicated process Jeremy had to suffer through and the simplified process provided by Let’s Encrypt is absolutely fantastic.

I don’t want to mislead you—there’s work to be done here. I don’t know that every server is setup to be quite as smooth as the Apache process, and without root access to the server you still have to go through some manual steps.

UPDATE: It looks like Dreamhost is going to allow customers to generate and enable Let’s Encrypt certificates from the control panel. Hopefully other hosting providers will follow suit.

But that’s where they’ll need you. Try it out on your own servers and test sites and if you run into difficulties, let them know. I’m really optimistic that with enough feedback and input, Let’s Encrypt can finally make HTTPS everywhere a less painful reality.

# Thursday, December 3rd, 2015 at 1:58pm


# Shared by James Bell on Friday, September 12th, 2014 at 12:11pm

# Shared by Liam McMurray on Friday, September 12th, 2014 at 12:39pm

# Shared by Ryan Santschi on Friday, September 12th, 2014 at 3:25pm

# Shared by Kirsten Cassidy on Friday, September 12th, 2014 at 10:27pm

# Shared by John Allsopp on Friday, March 6th, 2015 at 8:12am

# Shared by Rafael Yepes on Tuesday, November 10th, 2015 at 11:36am


# Liked by Andrew Jones on Friday, September 12th, 2014 at 12:35pm

# Liked by Chris Shiflett on Friday, September 12th, 2014 at 12:35pm

# Liked by Robert Deniszczyc on Friday, September 12th, 2014 at 12:36pm

# Liked by Joschi Kuphal 吉 on Friday, September 12th, 2014 at 12:37pm

# Liked by a boy cat on Friday, September 12th, 2014 at 12:38pm

# Liked by Channy Yun(윤석찬) on Friday, September 12th, 2014 at 12:47pm

# Liked by It's Dom on Friday, September 12th, 2014 at 12:47pm

# Liked by studlyspam on Friday, September 12th, 2014 at 12:48pm

# Liked by Orionesque on Friday, September 12th, 2014 at 12:49pm

# Liked by Nicholas Fletcher on Friday, September 12th, 2014 at 12:58pm

# Liked by L A Watts on Friday, September 12th, 2014 at 12:58pm

# Liked by Bespoke Media on Friday, September 12th, 2014 at 12:59pm

# Liked by Bradley Taylor on Friday, September 12th, 2014 at 1:00pm

# Liked by James King on Friday, September 12th, 2014 at 1:22pm

# Liked by Sam Richard on Friday, September 12th, 2014 at 1:24pm

# Liked by Josh Habdas on Friday, September 12th, 2014 at 1:33pm

# Liked by Chris Greufe on Friday, September 12th, 2014 at 1:45pm

# Liked by D Pitchford on Friday, September 12th, 2014 at 1:58pm

# Liked by Niall Thompson on Friday, September 12th, 2014 at 2:17pm

# Liked by Scott Gruber on Friday, September 12th, 2014 at 2:57pm

# Liked by John F Croston III on Friday, September 12th, 2014 at 2:57pm

# Liked by Patrik Ragnarsson on Friday, September 12th, 2014 at 3:41pm

# Liked by Elaine Nelson on Friday, September 12th, 2014 at 4:15pm

# Liked by Dan Brown on Friday, September 12th, 2014 at 9:59pm

# Liked by vollepeer on Saturday, September 13th, 2014 at 5:31pm

# Liked by Ian Silvester on Monday, September 15th, 2014 at 9:01am

# Liked by delete yourself on Friday, March 6th, 2015 at 8:25am

# Liked by Ethan Marcotte on Friday, March 6th, 2015 at 10:47am

# Liked by Jared Marcotte on Friday, March 6th, 2015 at 11:22am

# Liked by Ricky Onsman on Friday, March 6th, 2015 at 11:44am

# Liked by ge ricci on Friday, March 6th, 2015 at 12:15pm

# Liked by Michael Hastrich on Friday, March 6th, 2015 at 12:26pm

# Liked by Elizabeth Sarobhasa on Saturday, March 7th, 2015 at 7:07am

# Liked by Matt Gaunt on Tuesday, November 10th, 2015 at 10:00am

# Liked by Rem on Tuesday, November 10th, 2015 at 10:00am

# Liked by raul penaranda on Tuesday, November 10th, 2015 at 10:42am

# Liked by Jake Archibald on Tuesday, November 10th, 2015 at 11:12am

# Liked by Tom Leadbetter on Tuesday, November 10th, 2015 at 11:12am

# Liked by Miles Tincknell on Tuesday, November 10th, 2015 at 11:25am

# Liked by Rafael Yepes on Tuesday, November 10th, 2015 at 11:48am

# Liked by Raphaël BECK on Tuesday, November 10th, 2015 at 11:48am

# Liked by harry on Wednesday, November 11th, 2015 at 4:41pm

Have you published a response to this? :