HTTPS server in five minutes with Node.js

Getting started

First you'll need to install Node.js for your operating system. Follow the instructions on the Node.js website to do this - on Windows you can download an installer, on Ubuntu it should be as simple as opening a terminal and running sudo apt update && sudo apt install nodejs npm.

You'll also need OpenSSL to generate some certificates. Ubuntu/Linux users should already have this, Windows users download and install the curl for Windows package.

For this tutorial, you may want to create a new directory on your machine and saving all files / running all terminal commands from that directory.

Writing our first HTTPS server in Node

Fire up your favourite IDE or text editor (yes, really, you don't need anything more than a text editor, you can do this in Notepad if you like).

Enter the following code and save the file as server.js.

const https = require('https');
const fs = require('fs');

    cert: fs.readFileSync('./localhost.crt'),
    key: fs.readFileSync('./localhost.key')
}, (req, res) => {
    res.end('Hello from Node!\n');
console.log("Server listening on https://localhost:4430/");

These few lines of code are all we need to fire up a fully-functional HTTPS server. But don't try to run this yet! We don't have our certificates.

Generate a self-signed CA and server certificate

Open up a command prompt or terminal and run the following commands:

openssl genrsa -des3 -out ca.key 2048
# when prompted, enter a passphrase of your choosing

openssl req -x509 -new -nodes -key ca.key -sha256 -days 365 -out ca.crt
# when prompted, enter the passphrase from step 1
# Then enter whatever you like for the other prompts or leave as blank/defaults

openssl genrsa -out localhost.key 2048
openssl req -new -key localhost.key -out localhost.csr -addext "subjectAltName = DNS:localhost"
# Again when prompted, enter some sensible values or just leave blank

At this point, four new files have been created in your directory; ca.crt, ca.key, localhost.csr and localhost.key. What we've done here is create a private key and certificate which will act as our root certificate authority, as well as a private key and certificate signing request for our HTTPS server (localhost). The key will be used to sign the certificate for our server which is to run on https://localhost (the hostname of your local computer).

Go back to your IDE / text editor and create a new file, saving it as localhost.ext.

keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

DNS.1 = localhost

Now go back to the terminal or command prompt and run the following:

openssl x509 -req -in localhost.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out localhost.crt -days 365 -sha256 -extfile localhost.ext
# When prompted, enter your passphrase from step 1

You now have a new file localhost.crt. If you go back to your server.js file, you'll notice we now have both the files localhost.key and localhost.crt we specified in our call to createServer.

Run the Node server

On your command line, run node server.js:

dave@localhost$  node server.js
Server listening on https://localhost:4430/

and navigate to https://localhost:4430/ in your browser.

Trusting the certificate authority

You may notice your browser popped up a warning about not trusting the address we just entered. You can safely ignore it; it's because your browser doesn't recognise the self-signed certificate authority we just created with OpenSSL. You can add this root certificate to your computer's local trust chain, but I won't go in to that in this article, since it's not really important for our purposes. Just ignore the browser warning and proceed. You should see Hello from Node! displayed in your browser.

Further steps

You've just seen how easy it is to fire up a working HTTPS server with Node.js and OpenSSL. There's much more we can do from here - we can add Express, a web framework for Node, to our app and make it really easy to flesh out a secure API or website.

We can add mutual authentication, so instead of just presenting our SSL certificate to the browser / end user, we can require they present us with a certificate signed by our certificate authority too. This is a great way of securely authenticating authorized users on a public-facing API and rejecting all unauthorized access attempts.

We can write some automated tests for our service.

I'll explore these topics in future blog posts 😀️


Add a comment

All comments are pre-moderated and will not be published until approval.

You can write in _italics_ or **bold** like this.

Recent posts

Monday 19 September 2022, 20:36

Learn how to make use of Doctrine lifecycle events to build a searchable audit log for your application which records an entry whenever an entity's data is changed.


Saturday 10 September 2022, 21:40

Learn all about OAuth2, OIDC, plus build an AWS Cognito style single sign on app.

php coding


Buy this advertising space. Your product, your logo, your promotional text, your call to action, visible on every page. Space available for 3, 6 or 12 months.

Get in touch

Thursday 18 August 2022, 19:40

What's a unit, anyway?

php musings

Tuesday 31 May 2022, 22:00

...and how not to handle customer service


Tuesday 12 April 2022, 21:40

Ever wondered the best way to do encryption in PHP? This tutorial shows you how!