Setup HTTPS (letsencrypt) for Koa.JS

This tutorial shows you how to setup https for a Koa.JS web server.

Steps

Prerequisites

  • You have already registered a domain. It’s not possible for letsencrypt to obtain a certificate for just an IP-Address.
  • Shell script access to your server running with a Linux distribution.
  • Make sure that the domain is pointing to your server (correct nameserver entries configured at the domain provider and dns entries correctly configured at your server provider). Check out here, how it works for Google Cloud.
  • You have node installed on your server.

Note: I had Ubuntu 16.04 installed on my server for the following instructions.

Create your Letsencrypt SSL certificate

First of all you need to generate your SSL certificate using Certbot. If you use a different Linux distribution other than me, have a look at the custom install instructions for your Linux distribution.

Run the following commands on your server:

sudo apt-get update

sudo apt-get install software-properties-common
sudo add-apt-repository ppa:certbot/certbot

sudo apt-get update

sudo apt-get install certbot

sudo certbot certonly

—> Choose Option 1
—> Enter your email renewal notification (in my case the certificate generated was only valid 3 for months).
—> A (agree) to the terms of service
—> N (No) if you don’t want to receive the newsletter
—> Enter your domains comma separated (e.g. example.com,www.example.com)

Then the certificate should be successfully generated and available in the path /etc/letsencrypt/live/example.com/

Automatic certificate renewal

To renew automatically your certificate, create a shell script in the project folder (e.g. in /home/user/code/project/update-letsencrypt-certificates.sh)

#!/bin/bash

sudo certbot renew

# copy new certificates to project destination

CERTSDIR='etc/letsencrypt/live/example.org/'

sudo rsync —-copy-links $CERTSDIR/fullchain.pem $CERTSDIR/privkey.pem /home/user/code/project/certs

# Set read permissions

sudo chmod -R ugo+r /home/user/code/project/certs

# Kills all running node programs; risky if other node programs are running

sudo killall node

# Restart server with new files in the background

nohup node /home/user/code/project/index.js &

Make the script executable.

chmod 774 /home/user/code/project/update-letsencrypt-certificates.sh

To add a cronjob type in

sudo crontab -e

and enter the following in the text editor.

0 0 1,15 * * /home/user/code/project/update-letsencrypt-certifiactes.sh 2>&1 | /usr/bin/logger -t update_letsencrypt_renewal

This means that on the first and 15th day of the month at 0:00 a.m. all certificates will be renewed if they expire in less than 30 days. The second part of the command will redirect the output of the script to the syslog. Alternatively you can receive an email notification if your cronjob succeeded, but therefore a MTA (email service like postfix) has to be installed.

Initialize Node.JS project

Next create a new project folder (or use an existing one).

mkdir -p “${HOME}/code/project”

cd “${HOME}/code/project”

# We need that directory later to store the certificates in it.

mkdir certs

npm init

Setup HTTPS for your web server

Now we will add a sample implementation for Koa.js.

Go to file package.json and add following lines into the object.

"dependencies" : {

"koa": "2.x",

"koa-router": "7.x"

}

Now you need to lock those dependencies with

npm install

Then create the index.js file.

// index.js

'use strict';

const fs = require('fs');

const path = require('path');

const https = require('https');

const Koa = require('koa');

const server = new Koa();

// add main routes

// the following routes are for the authorisation challenges

// ... we'll come back to this shortly

const router = require('./router.js');

server

.use(router.routes())

.use(router.allowedMethods());

const config = {

domain: 'example.com', // your domain

https: {

port: 5555, // any port that is open and not already used on your server

options: {

key: fs.readFileSync(path.resolve(process.cwd(), 'certs/privkey.pem'), 'utf8').toString(),

cert: fs.readFileSync(path.resolve(process.cwd(), 'certs/fullchain.pem'), 'utf8').toString(),

},

},

};

const serverCallback = server.callback();

try {

const httpsServer = https.createServer(config.https.options, serverCallback);

httpsServer

.listen(config.https.port, function(err) {

if (!!err) {

console.error('HTTPS server FAIL: ', err, (err && err.stack));

}

else {

console.log(`HTTPS server OK: https://${config.domain}:${config.https.port}`);

}

});

}

catch (ex) {

console.error('Failed to start HTTPS server\n', ex, (ex && ex.stack));

}

And create file router.js

// router.js

'use strict';

const router = require('koa-router')();

router.get('/', (ctx, next) => {

  ctx.body = 'Hello World!';

});

module.exports = router;

Last but not least just copy the project to your server and run 

node index.js

Finally

Go to your browser and use type in https://example.org:5555 and you should get back “Hello World!”

Special thanks to Brendan Graetz who posted the original code which I adapted.  

2 Comments. Leave new

  • Michael C Bennett
    25. August 2020 17:12

    Thanks for the tutorial! A few typos I found while following it:

    1. Missing dash in front of the “copy-links” option – should be “rsync –copy-links”, not “rsync -copy-links”
    2. Missing space after the day-of-the-week asterisk in the crontab line; should be “0 0 1,15 * * /home/user . . .”, not “0 0 1,15 * */home/user . . .”

    Thanks again, I was dreading trying to do letsencrypt and this tutorial made it a breeze!

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.