Free SSL with Let's Encrypt and Node.js

If you use Heroku for web app hosting, then you can use letsencrypt to generate a free SSL certificate for your web app.

Why?

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.

Steps

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.herokuapp.com

=== yourapp Custom Domains
Domain Name DNS Target
──────────────── ──────────────────────────────
yourapp.com yourapp.com.herokudns.com
www.yourapp.com www.yourapp.com.herokudns.com

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

Using Homebrew and certbot makes issuing valid SSL certificates pretty easy. Make sure you have Homebrew installed, and then run

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:

some-random-characters.-more-random-characters

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

app.get('/.well-known/acme-challenge/:cert', function(req,res){
var id = req.params.cert
var finalString = id + Key from step 3
res.setHeader('content-type', 'text/plain');
res.send(finalString)
})

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//. To upload the newly generated certificate to Heroku, simply:

heroku _certs:add /etc/letsencrypt/live//fullchain.pem
/etc/letsencrypt/live//privkey.pem — app

Conclusion

If all goes according to plan, you should now have a valid SSL certificate for your custom domain.

Your thoughts?