How to SSL encrypt your Django & Heroku projects for free, with Let’s Encrypt.
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:
- Adding Let’s Encrypt support to Django
- Installing & running Certbot
- Proving site ownership with the ACME challenge
- Generating the security certificate with Certbot
- 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
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
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!
Your site should be encrypted now. Give yourself a pat on the back and have a beer!