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');
https.createServer({
cert: fs.readFileSync('./localhost.crt'),
key: fs.readFileSync('./localhost.key')
}, (req, res) => {
res.writeHead(200);
res.end('Hello from Node!\n');
}).listen(4430);
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
.
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[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 😀️
Comments
All comments are pre-moderated and will not be published until approval.
Moderation policy: no abuse, no spam, no problem.
Recent posts
The difference between failure and success isn't whether you make mistakes, it's whether you learn from them.
musings coding
Recalling the time I turned down a job offer because the company's interview technique sucked.
musings
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.
Recalling the time I was rejected on the basis of a tech test...for the strangest reason!
musings
Why type hinting an array as a parameter or return type is an anti-pattern and should be avoided.
php
Leveraging the power of JSON and RDBMS for a combined SQL/NoSQL approach.
php