Heroku and Let’s Encrypt

Bertrand Bonnefoy-Claudet
Cryptosense tech blog
3 min readNov 4, 2016

Update (2017-04-12): Since March 2017, you can use Heroku’s Automated Certificate Management for your paid dynos.

Cryptosense hosts some of its applications on Heroku and as many others, we want to use HTTPS. Heroku applications automatically benefit from it because the herokuapp.com domain has a certificate for all the applications under it. However, if you use a custom domain such as www.example.net, you have to get a certificate yourself and upload it to Heroku.

Even basic TLS certificates usually come at a price but since 2016, you can get such certificates for free from the Let’s Encrypt authority. Let’s Encrypt provides certificates through the ACME protocol, which enables nice features such as automatic renewal. This works really well for servers you can administer because everything from domain validation to HTTP server configuration can be handled in one command. Unfortunately, this is not the case with Heroku because you don’t administer the front-end.

Challenge response

To get a certificate for some domain, you must prove that you control the domain. With Let’s Encrypt, you can either use a DNS challenge or an HTTP challenge. If you can do it with your provider, the DNS challenge is probably the easiest option since it bypasses Heroku completely. If you can’t, HTTP is your only option and we’ll see how to do it.

As explained in the How it Works page, you will need to serve some text at a specific path over HTTP on your application. Therefore, you will have to tell your application to serve this response text at the following kind of URL:

http[s]://www.example.net/.well-known/acme-challenge/<challenge>

The challenge and response texts are temporary and can be passed to the application via a database or the environment. If you use Flask, you can use https://github.com/njoyce/flask-letsencrypt to automatically configure routes given a challenge and response. You will only be able provide those later but you should make sure this part works before proceeding to the next step.

You also need your DNS to be configured so that your custom domain points to your Heroku application. The procedure depends on whether you already use TLS for that custom domain. See the documentation on Custom Domain Names for more details.

Get a certificate

We’ll use the Certbot client. It normally does everything at once but as you will manually provide the challenge response to your application, getting the certificate will happen in two steps instead. On a machine with Internet access:

certbot certonly --manual -d www.example.net

If your TLS is not yet properly configured, you’ll probably want the --no-verify-ssl option. This can be needed if your old certificate is self-signed or has expired.

At some point, the program will prompt you to provide the challenge and response to your application. At Cryptosense, we do the following, but you can use your own format or go through a database instead:

heroku config:set ACME_CHALLENGE=<challenge>:<response>

This restarts the application and sets a new environment variable that the application can parse. Whatever the method you chose, when your application is ready, hit ENTER. If all went well, your certificate and private key should be in /etc/letsencrypt/live/www.example.net.

Upload the certificate

Add the certificate and private key to Heroku:

heroku certs:add fullchain.pem privkey.pem

If you already had a certificate set up, use certs:update instead. The certs:info command should confirm the new certificate is OK and your application should be reachable at https://www.example.net.

Cryptosense builds software to detect and fix broken cryptography in complex systems. If you’re interested in working with us, have a look at our careers page.

--

--