How to SSL encrypt your Django & Heroku projects for free, with Let’s Encrypt.

Picture of me

Written by Peter Curet

Published on March 08th, 2017

It's 2017 people! Let’s protect our user's data and get every site encrypted. Soon Chrome will be marking HTTP as non-secure, so follow these steps if you’d rather not scare your users with non-secure screens popping up.

Let’s get started.

We will be encrypting our site using a Certificate Authority called Let’s Encrypt, an open and free initiative aiming to make online encryption ubiquitous. The encryption process can get a little complicated, so I've divided it into 5 steps:

  1. Adding Let’s Encrypt support to Django
  2. Installing & running Certbot
  3. Proving site ownership with the ACME challenge
  4. Generating the security certificate with Certbot
  5. Adding the security certificate to Heroku

1. Adding Let’s Encrypt support to Django

First off, it's important to understand how Let's Encrypt works. When requesting a security certificate, you will need to prove that you really are the owner of the site. This is called an ACME challenge

The ACME challenge entails that a challenge key url on your site returns a challenge key response. Both the key and the response are unique, and are provided by Let's Encrypt. 

We'll be adding ACME challenge support to our application using the django-letsencrypt library by Urda.

The library is fairly straightforward, and allows you to add the key and response pairs through the Django admin environment. This will expose the url necessary to prove your ownership.

Using pip, run the following commands to update your python environment and requirements:

pip install django-letsencrypt
pip freeze > requirements.txt

In your settings.py, add letsencrypt to your installed apps:

INSTALLED_APPS = [
    ... ,
    'letsencrypt',
    ... ,
]

Finally, expose the challenge key urls by updating your urls.py with the following routing:

urlpatterns = [
    ...,
    url(r'^\.well-known/', include('letsencrypt.urls')),
    ...,
]

Now, deploy your project to Heroku and make sure you update the database tables by running the migrate command.

2. Installing & running Certbot

Next we install Certbot, the client that fetches the certificate from Let's Encrypt. For other installation methods, follow these instructions.

I'm using homebrew, which makes installing it is super easy. Open up a terminal and run: 

brew install certbot

In your terminal run the following command, and follow the instructions.

sudo certbot certonly --manual

CertBot will ask some of your information, including your email and domain name.

Finally it will output a bunch of text, most of it not relevant to our situation. Most importantly, it will output something along these lines:

Make sure your web server displays the following content at 
http://your-domain.com/.well-known/acme-challenge/CHALLENGE-KEY 
before continuing: 

CHALLENGE-KEY-RESPONSE

For readability sake, I've replaced the key and response pair hashes with CHALLENGE-KEY and CHALLENGE-KEY-RESPONSE. In practice these will be complicated hashes, which you will add to your backend.

3. Proving ownership with the ACME challenge

In your Django admin, go to the new Let's Encrypt section, and add a new ACME challenge.

Paste your CHALLENGE-KEY and CHALLENGE-KEY-RESPONSE in their corresponding fields, and save the entry. The challenge url should now be exposed.

4. Generating the security certificate with Certbot

Switch back to the terminal, and continue by pressing enter. CertBot will now try to access the challenge url. If successful, it will output the following:

Generating key (2048 bits): /etc/letsencrypt/keys/0000_key-certbot.pem
Creating CSR: /etc/letsencrypt/csr/0000_csr-certbot.pem

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
  /etc/letsencrypt/live/your-domain.com/fullchain.pem. Your
   cert will expire on 2017-06-20. To obtain a new or tweaked version
   of this certificate in the future, simply run certbot again. To
   non-interactively renew *all* of your certificates, run "certbot
   renew"
 - If you like Certbot, please consider supporting our work by:

  Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
  Donating to EFF:                    https://eff.org/donate-le

5. Adding the security certificate to Heroku

Almost there! They certificate has been saved locally, but needs to be stored on Heroku. Run the following to add the certificate to Heroku. Make sure to replace the 0000_key-certbot.pem with the filename given in the terminal output from the previous step:

sudo heroku certs:add /etc/letsencrypt/live/your-domain.com/fullchain.pem /etc/letsencrypt/keys/0000_key-certbot.pem --app your-app

If you already had a certificate in place, and just want to update, run the following:

sudo heroku certs:update /etc/letsencrypt/live/your-domain.com/fullchain.pem /etc/letsencrypt/keys/0000_key-certbot.pem --app your-app

Certificate Renewal

Let's Encrypt issues certificates that are valid for 90 days, and will e-mail you when they are about to expire. Since you have everything set up, it's easy (but not ideal) to do manually.

I'd like to automate this, but so far I haven't gotten the chance to get into this. If you have some ideas, I'd love hear them so give me a shout!

Congrats!

Your site should be encrypted now. Give yourself a pat on the back and have a beer!

Get the latest updates

Stay tuned, I’ll be sharing exciting stuff soon!