Free TLS with LetsEncrypt and Heroku in 5 Minutes
Our team at 201 Created recently built a proof-of-concept web app that showcases the extraordinary capabilities of the modern web. It is quickly converging on (and in some cases, surpassing) the feature set of native apps. We will be releasing the web app soon, along with more blog posts about our process; to stay tuned, follow @bantic (me) or 201 Created.
Update July 27 2018: A few readers have pointed out that this approach no longer works for apps on the free tier at Heroku. The bad news is that there is no longer a zero-cost way to deploy a Heroku app with TLS. The good news is that it is even easier, provided you upgrade to a (paid) hobby dyno or greater, to use Heroku’s Automated Certificate Management system to turn on TLS for your app.
Our web app accepts payments via Apple Pay (pay with your fingerprint!) and Android Pay, and in order to do so we must serve the app securely with TLS (aka https and, erroneously, SSL). In the past this would entail buying an TLS Certificate from one of the providers online and jumping through a few hoops to get it assigned.
These days, however, there’s a new CA (Certificate Authority) on the block: LetsEncrypt. They are a non-profit that launched in April, 2016, and are dedicated to allowing everyone to secure their website with TLS. LetsEncrypt now supports more than 20 million active certificates and is rapidly growing.
If you host your website on Heroku with a custom domain and haven’t yet secured your site with TLS, now is the time. The process takes less than 5 minutes and is completely free if you have a Heroku account that uses paid dynos (Hobby and up). See more details about Heroku’s free SSL here.
Step 1: Install certbot
The first step is to install the command-line tool certbot. If you are on Mac and use homebrew, installation is simple:
brew install certbot
For other OSes, see the certbot installation docs.
(Note: this post was tested with certbot version 0.9.3. If your version is significantly different you may need to adjust some commands below.)
After certbot is installed, generate a cert manually:
sudo certbot certonly --manual
After you hit ok you may be notified that your IP is logged. If so, hit ok again. At this point certbot will display the ACME challenge information: A URL and its required text content. It looks like this:
Make sure your web server displays the following content at
http://www.my-site.com/.well-known/acme-challenge/<long-string>:<long-string>.<other-long-string>
Step 2: Upload static file
Before you continue, you must configure your server at heroku such that it returns the given string for the given URL. If you are using rails you can put a file in the public
directory and it will be served statically:
$ mkdir -p public/.well-known/acme-challenge/$ echo "<long-string>.<other-long-string>" > public/.well-known/acme-challenge/<long-string>
The same principle applies for other types of serving software. Put that file in your public
or similar directory (or configure a route in your application to serve this file). After you’ve put the static file in place, commit the changes and push them to heroku.
This step also requires that you have your custom domain (in the example above we are using www.my-site.com) set up at heroku. If you haven’t done this yet, you’ll need to do so before you can continue. This involves telling Heroku about the custom domain and setting a DNS CNAME record. See Heroku’s docs on custom domains for more details.
At this point you should be able to visit the url that certbot displays (e.g.: http://www.my-site.com/.well-known/acme-challenge/<long-string>
) in your browser and see the correct string of text. When that is the case, hit enter and let certbot verify that you control this domain.
If all goes well you will see:
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/www.my-site.com/fullchain.pem. Your
cert will expire on 2017-04-12.
Step 3: Upload cert to heroku
Now, upload the certificate and private key to heroku. The heroku command-line tool will do this for you. Copy and paste the following command, replacing the domain name for the one you are using.
The command requires two arguments: the path to your certificate and the path to your key:
heroku certs:add path/to/cert path/to/key
Certbot will have placed both files in /etc/letsencrypt/live
, so copy and paste the command below, replacing the bold text for the domain name you are using (same name, including ending “.com” or other tld, that you entered in the first step of generating the cert):
sudo heroku certs:add /etc/letsencrypt/live/domain/fullchain.pem /etc/letsencrypt/live/domain/privkey.pem
After heroku accepts the uploaded cert, you are all set! Visit https://yourdomain.com and bask in the glory of the green lock icon.
Before you go, remember to take note of the certificate expiration date and add a reminder so that you don’t forget to renew it. The command to renew your cert is:
sudo certbot renew --manual
Links
Some other links worth reading:
- LetsEncrypt 2016 Year In Review — look at that hockey stick!
- Heroku SSL Docs
- Heroku Custom Domain Docs
- LetsEncrypt: How it works
- ACME Challenge spec — For the very curious. Note that HTTP challenge (which we used here) is only one of several types that the spec supports. Another common one is the DNS challenge, which involves adding a specific DNS record for your domain.
Did these steps work for you? Are you now running your site over https? Please let me know in the comments. If you’d like to see our follow-up blog posts about the web app we are building, follow me or 201 Created.