I have a Node Express app running on Heroku that I want to encrypt with a free-of-charge SSL cert from LetsEncrypt. However, the methods I've seen require opening up ports 443 and 80 to allow the ACME process to work.
Heroku only gives you one port, and doesn't let you choose which port. So how can I use LetsEncrypt?
I spent a bunch of time figuring this out yesterday. First time in a long time there were no answers on StackOverflow for something I was trying to do!
You can also validate your domain ownership to Let's Encrypt with DNS instead of HTTP.
With
certbot
, specify DNS as your preferred challenge:After a couple of prompts, certbot will tell you to deply a DNS TXT record to validate your domain:
Your domain registrar probably has its own docs for deploying a TXT record. Do that, and go back to
certbot
and press ENTER - Let's Encrypt will check the TXT record, sign the cert, andcertbot
will save it for you to upload to heroku.See my detailed blog post for more.
Update:
Heroku now supports LetsEncrypt natively! So this workaround is no longer needed.
Instructions here:
https://devcenter.heroku.com/articles/automated-certificate-management
For new apps, you don't have to do anything, it's turned on by default. For apps created before March 21 2017, you can turn it on with this Heroku cli command:
heroku certs:auto:enable
Thanks @Spain Train
Background
Ideally, LetsEncrypt allows for an automated certificate renewal process. That's harder to do on Heroku, so this answer describes how to use a manual process. Using a Heroku environment var, you'll be able to update your certs manually fairly easily going forward - no code changes.
Credit for this answer goes largely to two nice blog posts: https://medium.com/@franxyzxyz/setting-up-free-https-with-heroku-ssl-and-lets-encrypt-80cf6eac108e#.67pjxutaw
and
https://medium.com/should-designers-code/how-to-set-up-ssl-with-lets-encrypt-on-heroku-for-free-266c185630db#.ldr9wrg2j
There's a GitHub project which apparently supports automated certs updates on Heroku. I'll update this answer when I've tried it out:
https://github.com/dmathieu/sabayon
Using LetsEncrypt on Heroku with a Node Express app
Get the Express server ready:
Add this middleware to your Express app. Be sure to add it BEFORE any middleware that redirects http to https, because this endpoint must be http.
Create the certificate files using certbot:
sudo certbot certonly --manual
Enter the site url when prompted (www.example.com)
certbot will display a Challenge Response string in the format
xxxxxxxxxxxxxxxxxxx.yyyyyyyyyyyyyyyyyy
LEAVE CERTBOT WAITING IN THIS STATE. Do not press enter yet or exit.
https://dashboard.heroku.com/apps/your-heroku-app-name/settings
Under Config Variables, click 'Reveal Config Vars'
Edit the CERTBOT_RESPONSE var's value to match the Challenge Response from step a.
NOTE THE HTTP, NOT HTTPS
It should display the Challenge Response string. If this happens, go on to the next step. If not, do whatever it takes to get that URL to return the CR string before proceeding, or you will need to repeat this entire process.
If all goes as planned, certbot will tell you everything worked and display the location of the created certs. You'll use this location in the next step. Note that you might not be able to inspect the contents of the folder due to os permissions. If in doubt,
sudo ls /etc/letsencrypt/live/www.example.com
to see if the files exist.Update the Heroku instance to use the new certs:
Run
heroku certs:add
if your site doesn't have a cert. If updating, runheroku certs:update
.sudo heroku certs:update --app your-heroku-app-name /etc/letsencrypt/live/www.example.com/fullchain.pem /etc/letsencrypt/live/www.example.com/privkey.pem