This tutorial shows you how to setup https for a Koa.JS web server.
Steps
- Create your Letsencrypt SSL certificate
- Automatic certificate renewal
- Initialize Node.JS project
- Setup HTTPS for your webserver
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
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!
Thanks for your feedback 🙂
I implemented it right away.