Setting up free HTTPS with Heroku SSL and Let’s Encrypt

August 2016

I was tempted to just switch over to google compute engine where I can get a(maybe two) VM and set up SSL/TLS with seemingly hassle-free configuration given that the configuration of initialising a VM being very straight-forward (with vast images available). And I could even set one up hosting my Neo4j database. Hmmmmm. Cost is a problem, whilst it is not that much of a big deal on GCP but still, while you are developing hobby project I would prefer some more straight-forward methods with minimal cost (so that I can see the value and pay in the future)
  1. Cost of a SSL/TLS Certificate
    In fact you can easily buy a SSL/TLS with providers such as godaddydigicert etc. The price differs by the different type of certs — an Extended validation (EV) Certificates on digicert would cost $470 (so you get the Green Box showing the company name, pretty awesome)
  2. Cost of installing the certificate to the server
    With Paas like Heroku, the flexibility of configuration is much less (which is also the greatness of these services). So you can get add-ons in order to allow protocols. It wasn’t long ago that you needed to pay $20 a month to get SSL-endpoint enabled. hmmmmmmmmmmmmmmm. :/ With Iaas, you can do whatever you want, as the cost was  getting a well-geared(suited) VM.
I don’t want to leave heroku (for now), but I must get the Layer on. So, here comes Heroku SSL (beta)! Yes, it is for free. (Only if you’re with a paid dyno). It sounds contradicting but yeh. Heroku offers a hobby plan with $7/month per dyno. Not bad! :D
Heroku SSL is still on beta, so use it with your own risk. I am experimenting on a hobby dyno so I am incredibly happy to try. To use it, there are three simple steps:
  1. Acquire an SSL certificate from your SSL provider
  2. Upload the certificate to Heroku
  3. Update your DNS settings to reference the new SSL endpoint
I generated the SSL certificate with Let’s Encrypt:
Let’s Encrypt is a freeautomated, and open certificate authority (CA), run for the public’s benefit. Let’s Encrypt is a service provided by the Internet Security Research Group (ISRG).- objective of Let’s Encrypt and the ACME protocol is to make it possible to set up an HTTPS server and have it automatically obtain a browser-trusted certificate, without any human intervention. This is accomplished by running a certificate management agent on the web server.-
To get a free certificate from Let’s Encrypt, you’ll need to install certbot, which an automatic client that fetches and deploys SSL/TLS certificates to webserver. In this case with heroku, certbot will only be used to generate the certificate as we have no access to ssh for our heroku ‘server’. To install certbot, simply by
brew install certbot
Once install, it is time to get the certificate
sudo certbot certonly --manual
So it begins. For my case, I am getting the certificate for, there’ll be this prompt asking you to put in the domain name(s), just click ‘OK’ afterwards
The terminal will give you this lot:
Make sure your web server displays the following content at before continuing:xxxxxxxxxxxx-yyyy.zzzzzzzzzzzzzzzzzzzIf you don’t have HTTP server configured, you can run the following command on the target server (as root):mkdir -p /tmp/certbot/public_html/.well-known/acme-challenge cd /tmp/certbot/public_html printf “%s” Gm35kFLiXnNtKT9OAOG_KPZvqMmYYAZU6DN-QRoGclg.s2I4ZV9Ne2CNtczlqXV9uw1ZdB5OSypG_cIdiuT7BwI > .well-known/acme-challenge/Gm35kFLiXnNtKT9OAOG_KPZvqMmYYAZU6DN-QRoGclg # run only once per server: $(command -v python2 || command -v python2.7 || command -v python2.6) -c \ “import BaseHTTPServer, SimpleHTTPServer; \ s = BaseHTTPServer.HTTPServer((‘’, 80), SimpleHTTPServer.SimpleHTTPRequestHandler); \ s.serve_forever()” Press ENTER to continue
It is to make sure that the certificate is created for the domain name specified earlier. So certbot will try to access to this and expect to read this string ‘xxxxxxxxxxxx-yyyy.zzzzzzzzzzzzzzzzzzz’ from the endpoint. To do so, on node server, just add something like
app.get('/.well-known/acme-challenge/:content', function(req, res) { res.send('xxxxxxxxxxxx-yyyy.zzzzzzzzzzzzzzzzzzz') })
Once done so (add/commit/deploy to heroku), go back to the terminal and press ENTER to continue (as it said so)
If successful, it will show you a congratulation message and tell you the location of the certificate. Yeh then it is time to upload the certificate to heroku!
As this SSL free service on Heroku is still on beta, you will need to enable the lab mode for the app through CLI.
heroku labs:enable http-sni -a your-app heroku plugins:install heroku-certs
Then add the certificate by
heroku _certs:add /etc/letsencrypt/live/ /etc/letsencrypt/live/
Before this, you can access to with no problem with the certificate that comes with heroku, but accessing (given this is your custom domain) will give you an error of ‘Your connection is not private’ as the certificate on is with domain name * so it is not a match!
To map that, check the DNS target, it will probably show you something like this:
$ heroku domains === your-app Heroku Domain your-app Custom Domains Domain Name DNS Target ─────────────── ─────────────────────────────
For my situation, I have had forwarding domain to so I simply changed the CNAME record with host www and targeting
This is the most exciting part. Check if the cert works!
curl -vI
IT WORKS!!!!!!!!!!!
Browse to and click on the green https to check out the certificate! It is no longer the certificate with *.herokuapp but the Let’s Encrypt one.

:D Yayyyyyy. Good Bye to ‘Your connection is not private’

Built with Gatsby ^5.3 + Notion Email 📥 Twitter 💬 Github 👩‍💻 LinkedIn