How to secure your site in an afternoon

About a week ago, I set up HTTPS on my personal website, and started redirecting all traffic to the HTTPS equivelent. Apart from the geeky coolness factor of serving my content via HTTPS, I also think it’s something everyone should be doing. Sending any data via regular HTTP is just not secure, and after reading Jeremy Keith’s article about Security for all I realised that this tutorial needed writing. Read on to find out how I switch to HTTPS.

If like me you’re adding HTTPS to a website on a single subdomain, you can actually get HTTPS certificates for free. I visited StartSSL who provide basic certificates for free.

Signing up for an account with StartSSL

Creating an account with StartSSL is a laborious process. Here’s how to get one:

  1. Visit StartSSL and click “Control Panel”
  2. Click “Sign-up” (unless you already have an account)
  3. Fill in all the fields
  4. Check your email and enter in the verification code. Click “Continue”
  5. Choose “2048 High Grade” from the dropdown
  6. Click “Install”, this will install a certificate into your browser. It might seem strange, but StartSSL use this method to authenticate you instead of a username and password
  7. Click “Finish”

Validating your domain

Great, you’ve got an account! Before you can generate the certificate for your website, we first need to validate your domain.

  1. Click “Validations Wizard”
  2. Choose “Domain Name Validation”
  3. Enter your domain name, e.g. “”
  4. At this point you’ll find out it needs to send an email to an email address at that domain. My website uses Google Apps for email, so I had to create an alias for “[email protected]”. If you use Google Apps, then the article Add or remove an address for a user will show you how to do this. Otherwise, you may need to add a forwarding rule for this email address.
  5. So once you’re sure that you can receive emails at one of those addresses, click “Continue”
  6. Enter the verification code you receive via email and click “Continue” then “Finish”

Generating your certificate

Now that we’ve verified that we are the owner of this domain, we can finally generate the certificate.

  • Click “Certificates Wizard”
  • Choose “Web Server SSL/TLS Certificate”

Instead of using the inbuilt tool, I chose to use the command line to generate a private key. Whilst their tool generates a private key with a password, some services like Amazon CloudFront (which my website uses) do not support password protected private keys. It’s also more secure to generate the private key yourself, as StartSSL will never know what it is this way.

  1. Click “Skip” so we can enter our own private key
  2. In a command line, navigate to a folder where you wish to store your certificate files and type:

    openssl genrsa 2048 > ssl.key
    openssl req -new -key ssl.key -out csr.pem

    You can write anything you like for each question you will be asked. The only important one is “common name” which must be your domain name (the one you validated earlier).

    Once you’ve completed this, in your folder you will have a private key file called ssl.key, and another file called csr.pem which is a “Certificate Request” file.

  3. Open the file csr.pem in a text editor

  4. Copy every line of the file to your clipboard
  5. Back on StartSSL, paste the contents of your clipboard into the textarea and click “Continue”
  6. Click “Continue” again
  7. Select the domain you validated from the dropdown list
  8. Enter the one subdomain you would like this certificate to work on in addition to the root domain. I chose “www” for my site.
  9. Double check the details are correct and click “Continue”
  10. Copy the contents of the textarea into a text editor, and save this file to your certificates folder (the one containing your private key) and call it ssl.crt. That’s your certificate!
  11. You’ll also need two other certificates, the intermediate and root certificates. Download those too and save them to your folder. They provide a chain of accountability, showing just who has validated your certificate.

Using your certificate on CloudFront

My website is distributed by Amazon’s CDN service, CloudFront. Here are the steps I took to get everything set up.

Amazon requires a single file for intermediate certificates. Run the following command to combine the two files we downloaded earlier.

cat ca.pem > ca-bundle.pem

Now you’ll need to install the AWS Command Line Interface in order to upload these files.

  1. Install homebrew if you don’t already have it
  2. Install the AWS CLI by typing brew install awscli into the command line.
  3. Type aws configure to enter your access key and secret. You’ll need to generate these on the Amazon IAM control panel.

Now that you’re all set up, you can enter the following command to upload your files. Annoyingly, the command only seems to work if you give absolute paths starting with file:///, so you’ll need to replace the paths in the command below with absolute paths to your files. You’ll also want to change the --server-certificate-name and the last directory in the --path to something memorable.

aws iam upload-server-certificate --server-certificate-name example --certificate-body file:///path/to/certificates/ssl.crt --private-key file:///path/to/certificates/ssl.key --certificate-chain file:///path/to/certificates/ca-bundle.pem --path /cloudfront/example/

Now you’ll need to configure your CloudFront distribution to use these certificates.

  1. Log into the AWS console and navigate to your CloudFront distribution
  2. Under “General”, select “Edit” and choose “Custom SSL Certificate (stored in AWS IAM)”, selecting your certificate from the dropdown.
  3. You’ll also need to select “Only Clients that Support Server Name Indication (SNI)”, which means that SSL will be provided for free, but won’t work on IE<7
  4. Click “Yes, Edit”
  5. Go to “Behaviours”, choose the behaviour you would like to serve via HTTPS and click “Edit”
  6. If you want to redirect users to use HTTPS, choose “Redirect HTTP to HTTPS”, otherwise you probably want “HTTP and HTTPS”. Bear in mind that without redirection, most users will use the insecure version of your website.
  7. Click “Yes, Edit”
  8. Put the kettle on. This will take a while, and let’s face it, you’ve earned a break.
  9. Once CloudFront has had time to propagate the changes, check your website, and you should see a nice green padlock (if you’re using Chrome) or some other indication that the page you’re viewing is secure.

If you’re interested, click on the padlock to see all the details your visitors can see as evidence that the website is trusted. On Chrome, clicking “Connection” and then “Certificate Information” will show you all the SSL certificates that have authenticated the connection. Note that the certificate is valid for one year. Make sure you put something in your calendar to remind you to update the certificate before it expires!

Using your certificate with other providers

Depending on your host, or how your website is distributed, your milage may vary, but those files you’ve downloaded will be all that’s needed.

Eric Mill has an excellent tutorial (which helped me out enormously) Switch to HTTPS Now, For Free. In it he not only walks through the steps I’ve detailed, but also shows you how to get setup on various different hosts.

If that article didn’t help and you can’t find any documention, you should try contacting your host. Not all hosts provide support for SSL certificates, and some may charge you for the priviledge. But most good hosts will allow you to use your own certificate for free.

Good luck! It’s a pretty epic undertaking, but still if you’re well prepared shouldn’t take more than an afternoon to complete.

Notice: Array to string conversion in /var/www/ on line 22

Fatal error: Uncaught Error: Function name must be a string in /var/www/ Stack trace: #0 /var/www/ tags(Object(page)) #1 /var/www/ require('/var/www/joshem...') #2 /var/www/ tpl::loadFile('/var/www/joshem...', Array, true) #3 /var/www/ tpl::load('post', Array, true) #4 /var/www/ site->load() #5 /var/www/ require_once('/var/www/joshem...') #6 {main} thrown in /var/www/ on line 22