Secure your nodejs server with letsencrypt for free

HTTPS is the basic security setting for all websites. To enable HTTPS and avoid the annoying “certificate not trusted error” on browsers, you need to get a certificate from a trusted issuer and install it on your server.

Let’s Encrypt is a free, automated, and open Certificate Authority. With letsencrypt, you can secure your server with HTTPS for free.

In this post, I will introduce how to secure your nodejs server with letsencrypt-express (now renamed to greenlock-express). Although there is an express in the name, you can still use it in your non-express nodejs server.

First, let’s create a test server:

const http = require('http');
function handler(req, res) {
res.end('Hello World!');
}
http.createServer(handler).listen(80);

It listens on port 80 and response ‘Hello World!’ to any request.

Next, you need to enable HTTPS by starting an https server:

const http = require('http');
const https = require('https');
function handler(req, res) {
res.end('Hello World!');
}
http.createServer(handler).listen(80);
https.createServer(handler).listen(443)

The https server does not work now, as you haven’t specify any certificate for it yet.

Now use letsencrypt-express (greenlock-express) to create a handler wrapper: (2018–05–20: the following code has been updated to support Let’s Encrypt v2)

const PROD = false;
const lex = require('greenlock-express').create({
version: 'draft-11',
  server: PROD ? 'https://acme-v02.api.letsencrypt.org/directory' : 'https://acme-staging-v02.api.letsencrypt.org/directory',
  approveDomains: (opts, certs, cb) => {
if (certs) {
// change domain list here
opts.domains = ['example.com', 'yourdomain.com']
} else {
// change default email to accept agreement
opts.email = 'youremail@here.com';
opts.agreeTos = true;
}
cb(null, { options: opts, certs: certs });
}
  // optional: see "Note 3" at the end of the page
// communityMember: true
});
const middlewareWrapper = lex.middleware;

You need to change the domain list and default email in approveDomains function according to your own needs.

The returned object middlewareWrapper is a function, which takes any handler with the following form, and returns a middleware with the same form:

function(req, res, next)

This is good, because it can be used in different web frameworks. Now wrap your https request handler with it:

https.createServer(
lex.httpsOptions,
middlewareWrapper(handler)
).listen(433);

That’s it! Test your server with HTTPS, if every thing is ok, set PROD to true, restart, and your server is well protected by HTTPS.

Optional:

You can redirect all HTTP request to HTTPS by applying the following code to your HTTP server:

const redirectHttps = require('redirect-https');
http.createServer(lex.middleware(redirectHttps())).listen(80);

The certificate of Letencrypt will expire in 90 days, but you don’t need to worry about it at all, letencrypt-express will renew the certificate every 80 days in background. Zero down time!

Note 1: be sure to test your server with staging server (PROD = false) first, and turn PROD to true when test is done. Otherwise, it is possible that you will be blocked by hitting rate limits with bad requests.
Note 2: When testing your server in staging mode (PROD = false), the browser will complain that the certificate is not trusted. It is totally normal, accept the certificate, and see if your site is accessible and works fine. If ok, move to PROD.
Note 3: According to the maintainer of Greenlock AJ ONeal, you can add an additional option “communityMember: true” when you create the handler wrapper. It will let you receive important updates on greenlock as well as related tools