Exploring Methods of Creating SLL HTTPS for Localhost in Node.JS
Tags: node, backend
Published: 2022-12-09 15:44:29

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](https://aboutssl.org/certificate-authority/).

## Generate SSL HTTPS using OpenSSL

[OpenSSL](https://www.openssl.org/) 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](https://thesecmaster.com/procedure-to-install-openssl-on-the-windows-platform/).

### 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
```

[Save this code ](https://mariah.pieces.cloud/?p=afcd46a010)

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.

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/image8_aa6a18eb029e0065f7b1232e3a7c237b.png" alt="Creating a certificate on MacOS."/><figcaption>Creating a certificate on macOS.</figcaption></figure>

### 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
```

[Save this code](https://mariah.pieces.cloud/?p=60ff4e9bb5)

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

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/image1_3aa7187441d595f39570563ad4ed8834.png" alt="Generating a certificate authority pem file. "/><figcaption>Generating a certificate authority pem file on macOS</figcaption></figure>

### 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
```

[Save this code](https://mariah.pieces.cloud/?p=3a994dbe14)

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
```

[Save this code](https://mariah.pieces.cloud/?p=322c448827)

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](https://gist.github.com/cecilemuller/9492b848eb8fe46d462abeb26656c4f8#domain-name-certificate).

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/image2_7ff9c14e21783c29ffd16f220d7937e2.png" alt="Adding contents to a localhost.ext file on MacOS."/><figcaption>Adding contents to localhost.ext file on macOS</figcaption></figure>

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
```

[Save this code](https://mariah.pieces.cloud/?p=c1944cbf33)

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.

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/image3_2dad0306e648246120df0c6298e9565d.png" alt="Generating a private key for the CSR request on MacOS."/><figcaption>Generating a private key for the CSR Request on macOS</figcaption></figure>

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

```
$ openssl req -new -key localhost.key -out localhost.csr
```

[Save this code](https://mariah.pieces.cloud/?p=89544b867a)

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.

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/image7_fdc3c3a19e671ccaf877876f15723d9e.png" alt="Generating a CSR on MacOS."/><figcaption>Generating a CSR on macOS</figcaption></figure>

### 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
```

[Save this code](https://mariah.pieces.cloud/?p=3ad946bdc6)

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.

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/image6_1454a74fd4d87cacb726008a93cb8237.png" alt="Generating a CSR file on MacOS."/><figcaption>Generating a CSR file on MacOS</figcaption></figure>

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
```

[Save this code](https://mariah.pieces.cloud/?p=6ff345b937)

## 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
```

[Save this code](https://mariah.pieces.cloud/?p=b7294db60f)

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
```

[Save this code](https://mariah.pieces.cloud/?p=9d8d469538)

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)
})
```

[Save this code](https://mariah.pieces.cloud/?p=9ae640967f)

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
```

[Save this code](https://mariah.pieces.cloud/?p=29f34cbda7)

## 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](https://localhost:3000/) link in our Chrome browser as shown below:

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/image12_7ba3c3ccc0331ac691d3f1cf46c687da.png" alt="A warning that your connection is not secure."/><figcaption>Localhost run in the browser</figcaption></figure>

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](http://chrome://flags/#allow-insecure-localhost) URL on our Chrome browser and toggle the `Allow invalid certificates for resources loaded from localhost` button to `enabled`.

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/image11_4085aa0f1e7e5f105af1bf593adfda7c.png" alt="Modifying the security settings of Chrome."/></figure>

**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.

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/image4_17c923c8adabc6387c6d36284f9cba46.png" alt="The new response on localhost."/><figcaption>The response on localhost</figcaption></figure>

## 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.

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/image13_abc081ab60da78e10285cdb83d4b8a2b.png" alt="Toggling SSL certificate verification in Postman&#x27;s general settings page."/><figcaption>Toggling SSL certificate verification in Postman’s general settings page</figcaption></figure>

**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.

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/image5_af0fca62e42152b208891e6a4524b6b8.png" alt="Accessing HTTPS localhost on Postman."/><figcaption>Accessibility https localhost on Postman</figcaption></figure>

## 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
```

[Save this code](https://mariah.pieces.cloud/?p=f27c4a887d)

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/image9_06c6b1a2a62e0bca7fb7b41ce8de6f9a.png" alt="mk-cert installation on MacOS."/><figcaption>mk-cert installation on macOS</figcaption></figure>

[See more installation options for macOS. ](https://github.com/FiloSottile/mkcert#macos)

#### Linux

[Install mkcert on Linux.](https://github.com/FiloSottile/mkcert#linux)

#### Windows

[Install mkcert on Windows.](https://github.com/FiloSottile/mkcert#windows)

### Generate an SSL for localhost using MK-CERT

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

```
mkcert localhost
```

[Save this code](https://mariah.pieces.cloud/?p=4a7740ae87)

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/image10_1f31ac9875d1d302cba47a2491215d90.png" alt="Creating a certificate for localhost."/><figcaption>Creating a certificate for localhost</figcaption></figure>

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

```
mkcert -install
```

[Save this code](https://mariah.pieces.cloud/?p=1e444fbf64)

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
```

[Save this code](https://mariah.pieces.cloud/?p=7f86499b04)

### 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)
})
```

[Save this code](https://mariah.pieces.cloud/?p=9b6146a9d9)

**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:

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/image4_273bfff06ec5b474ca37a2ebef63ada0.png" alt="hello world in the browser."/><figcaption>The response on localhost</figcaption></figure>

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

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

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/image5_1246ddc340f94cfe5950a37beb0a6cb1.png" alt="Accessing HTTPS localhost on Postman."/><figcaption>Accessibility https localhost on Postman</figcaption></figure>

## 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](https://www.digicert.com/kb/ssl-support/openssl-quick-reference-guide.htm).