How to Obtain and Automatically Renew SSL Certs with Let's Encrypt on Node.js

Thanks to Let's Encrypt, everyone can enjoy the security of an SSL-protected domain.

To be fair, there are still a few places where their automated system won't work, like if you're running your web server on an irregular port, like 8443, or perhaps running in a load balanced environment.

I used to run Node with SSL under an irregular port as a backend service, and had to manually install new certificates. Not too terrible, but automatic renewal and saving the time and money is very nice.

Obtaining your initial certificate

In May 2016, the EFF announced the release of Certbot, the Let's Encrypt client. Certbot makes it easy to get your certificate.

EFF CertBot

So I had these socket.io (running on Node) servers on irregular ports, and the only reason they were on irregular ports was because they shared servers with another web server (they were a backend service). I noticed my boxes were just doing too much, so configuration and having everything play well together was getting more cumbersome. I like servers that have one job. Getting multiple servers running on one box is great, and saves money, however it stinks when you want to scale. Servers are cheap, so I sometimes make them unitaskers. Docker is big on this philosophy, but having multiple containers on one host still means services contend for ports.

I was Googling around and reading people's trouble's with Node on Express, since it's not an age-old web server like Apache or NGINX. I was determined to figure this out, and it turns out it was easy.

  1. Stop the web server running under Node.js. (I'm using upstart).

  2. Install certbot to your home directory and make it executable:

wget https://dl.eff.org/certbot-auto  
chmod a+x certbot-auto  

Run certbot to do its handshake and generate certificates:

./certbot-auto certonly --standalone -d yourdomain.example.com

The first time you run it, you have to provide your email. They will send you renewal reminders:

Let's Encrypt email

Next, agree to the terms of service:

Let's Encrypt terms of service

After a couple of seconds, you'll get a confirmation of success:

Let's Encrypt success

As the message says, your certificate, key, and chain are all saved in the directory: /etc/letsencrypt/live/yourdomain.example.com/

Adding the certs to your Node.js server

It's as easy as adding the paths to these files in your server's JavaScript file:

this.express = require('express');  
this.app = this.express();

var http = require('https');  
var fs = require('fs');

var sslPath = '/etc/letsencrypt/live/yourdomain.example.com/';

var options = {  
    key: fs.readFileSync(sslPath + 'privkey.pem'),
    cert: fs.readFileSync(sslPath + 'fullchain.pem')
};

this.server = http.createServer(options, this.app);  
this.io = require('socket.io').listen(this.server);  
this.server.listen(443);  

Then restart your server. That's it!

How does this work?

For a few seconds, Certbot takes control of your web server ports and sends a secret token to itself through the web -> to your domain's DNS -> to your domain, and then does some key signing in the whole handshake with itself to ensure the domain is yours.

How lets encrypt works to authorize your domain

Automatic renewals

Renewals are super simple. You just havr to know the right incantation of certbot. Put this in your crontab:

# Auto-renew SSL certificates with LetsEncrypt
@monthly   /path/to/certbot-auto renew --standalone --pre-hook "stop yourWebService" --post-hook "start yourWebService"

Replace the path to certbot-auto with the path on your server. And change the stop and start portions with how you stop and start your web service.

What this does once a month:

  1. Stops your web server.
  2. Checks the age of your certificate,
  3. If needed, runs the renewal by doing the same handshake as before (but because ih has already obtained a certificate before, it remembers your settings from a conf file it made then, so it already knows your domain, email etc).
  4. Makes new certificate, key, etc, and places them in the same directory as before.
  5. Starts your web server, using new certificate.

If you don't want extra junk in /var/log/crontab, use the --quiet flag.

If you're behind a load balancer in AWS

If you're running in a load-balanced environment in AWS, you can just SSL-terminate at the load balancer (when using ELB - Elastic Load Balancer) and get free certificates for your load balanced services using Amazon Certificate Manager. If you aren't using this, you can save a good deal of money, wildcard your domain all you want, and ACM will auto-renew your certificates for free.

comments powered by Disqus