Exploring Methods of Creating SLL HTTPS for Localhost in Node.JS

Pieces 🌟 - Dec 9 '22 - - Dev Community

Node.js backends that are run in development environments are usually served via HTTP by default. However, you may need your backend to be served via HTTPS if you are integrating services, using external libraries, or testing strong content security policies, among other scenarios. It’s usually vital that these situations are tested in a development environment before being deployed to production. This article will explain an array of ways to configure Secure Sockets Layer (SSL) HTTPS on a local development Node.js Express backend.

Goals:

This article aims to educate developers, particularly beginners and intermediate developers, on ways to configure SSL HTTPS on a local development Node.js Express backend.

Overview:

We will configure SSL HTTPS with the aid of a self-signed certificate on our local machine. Note that this procedure should be done only in a local/development environment! In a production environment, it’s best to obtain a certificate from a third-party Certificate Authority like letsEncrypt, Certbot, and so on. To obtain more information about a Certificate Authority, check out this explainer.

Generate SSL HTTPS using OpenSSL

OpenSSL is a cross-platform, open-source tool used for most cryptographic and network communication operations. However, OpenSSL is available by default only in most Linux distributions and macOS systems. Hence, Windows users will have to directly install OpenSSL in order to use it. You can learn how to install OpenSSL on Windows with these step-by-step instructions.

Create a Certificate Key

SSL certificates are typically signed by Certificate Authorities, which are trusted, third-party organizations. Before issuing any certificate, they conduct a thorough check on a website or web app in order to ascertain its owner, function, and use.

However, no Certificate Authority issues a certificate for localhost because no one owns it. So, we’ll simulate the signing process that Certificate Authorities use on our local machine.

Let’s create a certificate key by typing the following commands in sequence:

$ mkdir ssl-cert
$ cd ssl-cert
$ mkdir Cert-Auth
$ cd Cert-Auth
$ openssl genrsa -out Cert-Auth.key -des3 2048
Enter fullscreen mode Exit fullscreen mode

Save this code

The commands above will generate a private key and ask for a simple passphrase. The user will enter and re-enter the passphrase for confirmation.

Creating a certificate on MacOS.
Creating a certificate on macOS.

Generate a Certificate Authority (.pem) file

Upon creating a certificate key, we’ll create a certificate authority pem file. We need this file to create the certificate(.crt) file.

To create the certificate(.crt) file, type the command below:

$ openssl req -x509 -sha256 -new -nodes -days 365 -key Cert-Auth.key -out Cert-Auth.pem
Enter fullscreen mode Exit fullscreen mode

Save this code

In the command above, we used the already created certificate key to generate the certificate pem file.

Generating a certificate authority pem file.
Generating a certificate authority pem file on macOS

Generate a Certificate Signing Request(.csr) file

The Certificate Authority (CA) key and CA certificate have now been generated. Since we've already created a CA, we can sign SSL certificates.

Next, we create a new directory called localhost in the root (ssl-cert) directory. Create a new file, localhost.ext, inside localhost.

$ mkdir localhost
$ cd localhost
$ touch localhost.ext
Enter fullscreen mode Exit fullscreen mode

Save this code

After creating the localhost.ext file, we will open the file and add the code snippets below to it.

authorityKeyIdentifier = keyid,issuer
basicConstraints = CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
IP.1 = 127.0.0.1
Enter fullscreen mode Exit fullscreen mode

Save this code

The code above simply sets the configuration that our SSL certificate will contain. Our certificate works for localhost and also 127.0.0.1. More domains can be added to this file if you want the certificate to work for other host addresses. To dive into this further, read this article.

Adding contents to a localhost.ext file on MacOS.
Adding contents to localhost.ext file on macOS

After editing the localhost.ext file, we will generate the certificate signing request (CSR). The command below will be used to create a key, which will then be used to generate a CSR.

$ openssl genrsa -out localhost.key -des3 2048
Enter fullscreen mode Exit fullscreen mode

Save this code

The commands above will generate a private key and ask for a simple passphrase. The user will enter and re-enter the passphrase for confirmation.

Generating a private key for the CSR request on MacOS.
Generating a private key for the CSR Request on macOS

Once you’ve done that, type the below command to generate the CSR:

$ openssl req -new -key localhost.key -out localhost.csr
Enter fullscreen mode Exit fullscreen mode

Save this code

The commands above will generate a CSR and ask for certain pieces of information. They will also request a challenge password. A "challenge password" is essentially an embedded, one-time shared secret between you and the SSL certificate issuer (CA) that the issuer may use to authenticate you should that ever be necessary.

Note the requested challenge password can be anything, but it should be a “strong” password.

Generating a CSR on MacOS.
Generating a CSR on macOS

Generate a Certificate(.crt) File

We can now use our CSR to ask the CA to sign a certificate. It should be noted that the location from which the user executes commands affects the paths for the CA.key and CA.pem files (relative paths).

$ openssl x509 -req -in localhost.csr -CA ../CA.pem -CAkey ../CA.key -CAcreateserial -days 365 -sha256 -extfile localhost.ext -out localhost.crt
Enter fullscreen mode Exit fullscreen mode

Save this code

This command accepts the certificate extensions file, the CA certificate (Cert-Auth.pem and Cert-Auth.key), and the CSR (localhost.csr) (localhost.ext). These parameters produce a localhost.crt certificate file that is valid for one year.

Generating a CSR file on MacOS.
Generating a CSR file on MacOS

We will decrypt localhost.key since our localhost.key is in encrypted form. we will do this with the command below:

$ openssl rsa -in localhost.key -out localhost.decrypted.key
Enter fullscreen mode Exit fullscreen mode

Save this code

Develop a server using Node.js that is being served up utilizing a localhost SSL certificate

In order to test the certificate, we will create a Node.js application with express installed. To do this, we will type the commands below in sequence:

$ mkdir ssl-nodejs
$ cd ssl-nodejs
$ npm init -y
$ npm i express
$ touch index.js
Enter fullscreen mode Exit fullscreen mode

Save this code

Upon installing the Node.js application, we will create an Express app with a “get” API route that simply outputs “hello world” upon a visit to the route.

const express = require('express');
const app = express();

app.use(express.json())
app.get('/', (req, res)=> {
 res.send('hello world')
})
module.exports = app
Enter fullscreen mode Exit fullscreen mode

Save this code

We will also import the Express app to our index.js file and use it to create the server.

const http = require('http');
const fs = require("fs")
const { getDesktopFolder } = require('platform-folders')
const path = require("path")
const https = require('https')
const app = require('./app')

const server = https.createServer({
 key: fs.readFileSync(`${getDesktopFolder()}/ssl-cert/localhost/localhost.decrypted.key`),
 cert: fs.readFileSync(`${getDesktopFolder()}/ssl-cert/localhost/localhost.crt`)
}, app)

server.listen(3000, ()=> {
 console.log('port running on', 3000)
})
Enter fullscreen mode Exit fullscreen mode

Save this code

Also, we added the dependency platform-folders which simply locates the absolute path of the desktop folder. Accompanied by the filesystem module, we will use this package to locate the localhost.decrypted.key and localhost.crt files on our PC from an absolute path.

After creating the server, start it using the below command:

$ node index.js
Enter fullscreen mode Exit fullscreen mode

Save this code

Configure the Chrome web browser and the Postman API client to allow certificates we signed as the Certificate Authority (CA)

Now that our server is serving up the SSL, we can test our https://localhost:3000 link in our Chrome browser as shown below:

A warning that your connection is not secure.
Localhost run in the browser

Even after serving up our localhost with SSL and inspecting the signed certificate, Chrome does not trust the CA that signed this certificate. This is correct behavior, because we signed it locally and didn’t use a third-party trusted Certificate Authority. Since this is for development purposes, we want to access localhost with our self-signed certificate.

Therefore, we will access the chrome://flags/#allow-insecure-localhost URL on our Chrome browser and toggle the Allow invalid certificates for resources loaded from localhost button to enabled.

Modifying the security settings of Chrome.

N/B: This should not be done in production. However, we do this for development purposes in order to view the response on localhost from the browser.

The new response on localhost.
The response on localhost

Access localhost with HTTPS from the browser and the Postman API client

From Postman, access SSL certificate verification in the general settings and make sure that SSL certificate verification is turned off.

Toggling SSL certificate verification in Postman's general settings page.
Toggling SSL certificate verification in Postman’s general settings page

N/B: This is not advised to be done on production. However, we do this for development purposes in order to view the response of localhost on Postman.

Once this is done, we can access the HTTPS localhost on Postman.

Accessing HTTPS localhost on Postman.
Accessibility https localhost on Postman

Generate SSL HTTPS using MK-CERT

mkcert is a simple tool used for making locally trusted development certificates. It requires no configuration, as opposed to the OpenSSL method explored previously, which is an advantage.

Installing MK-CERT

macOs:

We’ll use Homebrew to install mk-cert on macOS.

brew install mkcert
Enter fullscreen mode Exit fullscreen mode

Save this code

mk-cert installation on MacOS.
mk-cert installation on macOS

See more installation options for macOS.

Linux

Install mkcert on Linux.

Windows

Install mkcert on Windows.

Generate an SSL for localhost using MK-CERT

To create an SSL certificate for localhost, run the command below:

mkcert localhost
Enter fullscreen mode Exit fullscreen mode

Save this code

Creating a certificate for localhost.
Creating a certificate for localhost

However, you can also chose to create a locally trusted CA by running the command:

mkcert -install
Enter fullscreen mode Exit fullscreen mode

Save this code

This creates a local CA which is only trusted by your device. To locate the path to the local CA, you can type the command below:

mkcert -CAROOT
Enter fullscreen mode Exit fullscreen mode

Save this code

Develop a server using Node.js that is being served up utilizing a localhost SSL certificate

We’ll use our previous server example; however, we’ll make a few tweaks to the key and cert values passed into the server. mk-cert generates localhost.pem and localhost-key.pem files for localhost, therefore, the parameters of key and cert on our server will now contain the file paths to the localhost.pem and localhost-key.pem files, respectively.

const http = require('http');
const fs = require("fs")
const { getDesktopFolder } = require('platform-folders')
const path = require("path")
const https = require('https')
const app = require('./app')

const server = https.createServer({
 key: fs.readFileSync(`${getDesktopFolder()}/mk-cert-ssl/localhost-key.pem`),
 cert: fs.readFileSync(`${getDesktopFolder()}/mk-cert-ssl/localhost.pem`)
}, app)

server.listen(3000, ()=> {
 console.log('port running on', 3000)
})
Enter fullscreen mode Exit fullscreen mode

Save this code

Configure the Chrome web browser and the Postman API client to allow certificates we have signed as the CA

Since we have already configured the web browser to view self-signed certificates, we can easily view the result below:

hello world in the browser.
The response on localhost

Access localhost with HTTPS from the browser and the Postman API client

We can access the HTTPS localhost on Postman as shown below:

Accessing HTTPS localhost on Postman.
Accessibility https localhost on Postman

Conclusion

In this article, we explored different ways of configuring SSL HTTPS on a local development Node.js Express backend and explained the terminologies used in certificate creation. To learn more about the certificate creation process, check out this in-depth article.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .