Free SSL with Let's Encrypt and Node.js
November 8, 2016
If you use Heroku for web app hosting, then you can use letsencrypt to generate a free SSL certificate for your web app.
While DNS service providers like GoDaddy offer SSL certs, they cost about $60 to generate. This may be convenient, but libraries like letsencrypt have made it possible to generate the same thing for free.
Heroku has updated its platform to support SSL for any apps that use paid dynos. While Heroku previously boasted free SSL, users still had to pay $20/month to integrate with separate DNS providers (via the Heroku SSL Endpoint add-on).
Now Heroku uses Server Name Indication (SNI) to provide 'free' SSL for apps using paid dynos. This means you still have to pay $7/month, however it’s significantly cheaper than using the addon.
This tutorial assumes you have the Heroku CLI installed and are working with Node.js. It is also assumed that you have a Node.js app already deployed to a paid Heroku dyno (Hobby or better). This app uses Godaddy as it's example DNS service provider, however it is not required that you have your domain purchased through GoDaddy to follow this tutorial. The steps are described as follows:
- 1. Configure Heroku
- 2. Configure your DNS
- 3. Generate free SSL certificate
- 4. Configuring your Node.js app
- 5. Upload certificate to Heroku
1. Configure Heroku
You will need to add your custom domain to your Heroku app. Remember to include CNAME's for both your naked domain (yourappname.com) and the www extended version (www.yourappname.com)
heroku domains:add yourappname.com
heroku domains:add www.yourappname.com
If everything has gone according to plan, run
heroku domains --app yourappname
And you should see something like...
=== yourapp Heroku Domain
=== yourapp Custom Domains
Domain Name DNS Target
2. Configure your DNS provider
In your DNS management console, point the CNAME alias for www to the DNS target specified in the step above. For example, we would set our CNAM www alias to www.yourapp.com.herokudns.com in this instance.
You also want to make sure you enable domain forwarding to point to your secure domain (in this case, https://www.yourapp.com). This will ensure that users are always taken to your domain, regardless of whether they enter a naked domain or with the www prefix.
3. Generate free SSL certificate
brew install certbot
This will install the certbot ACME client. Once installed, run the following:
sudo certbot certonly --manual
Follow the steps to generate the certificate. You should first enter your email address, and then it will ask you for the custom domain(s). Once complete, you should see something like this:
Make sure your web server displays the following content at
http://your.domain/.well-known/acme-challenge/some-random-characters before continuing:
Notice the part in red. This character string is important, as it is the unique string that your app will use for SSL certification. Copy this character string as it will be used again in the following step. DO NOT HIT ENTER. Please make sure you complete step 2 before continuing with the certbot client.
4. Configure your Node.js app
This example is built using Express, but the whole idea is to create a REST endpoint that can receive the SSL token
var id = req.params.cert
var finalString = id + Key from step 3
As you can see, a GET route is defined that accepts the SSL token as a parameter (:cert). Be sure to deploy this code before you start testing your SSL connection.
It is also recommended that you force https via the express-force-https module.
npm install express-force-https
Once the module is installed, configure your Node.js environment to use the module.:
var secure = require('express-force-https');app.use(secure);
5. Upload certificate to Heroku
Now jump back to the certbot client. If all went well in Step 2, you shouldn’t receive any errors and the appropriate .pem files are generated. The file should be stored at /etc/letsencrypt/live/
heroku _certs:add /etc/letsencrypt/live/
If all goes according to plan, you should now have a valid SSL certificate for your custom domain.