How to make Node.js running HTTPS localhost on macOS

Steffo Dimfelt
5 min readSep 22, 2020

This journey began when I needed to hook up Node.js and React.js. One big issue was that I wanted to fetch data in React when in localhost, but the browser complained about unsecured connection.

And I really really really wanted to develop on a local machine…

The journey

  1. The main problem
  2. The SSL Certification
  3. Node HTTPS Server
  4. Detour
  5. Move that Certification!
  6. Reload Server
  7. References

1. The main problem

The main problem is that Chrome (because I’m using Chrome) consider localhost to be “Not Secure”. In my case, my first setup was an HTTP-server and this didn’t, of course, pass the security check.

No, sir!

Using HTTPS instead of HTTP should solve my problem, but Chrome did not get charmed by my Node-masterpiece:

const express = require('express')
const https = require('https')
const app = express()
app.get('/', function (req, res) {
res.send('hello world')
})
https.createServer(app)
const PORT = 5001;
const port = process.env.PORT||PORT;
app.listen(port);
console.log(`Running on ${PORT}`);

2. The SSL Certification

To make the node server secure, it needs a SSL certification. The certification has two parts — a key and a certification. The key is used to crypt/decrypt the certification, and the certification is… the certification.

With that in mind. Lets do some certification stuff.

To have the key and certification in one place, I did a folder under the root-folder and named it certification (I know, I’m very clever.).
Inside the certification folder I created a file called reg.cnf and put this content:

[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = Country (initials like US, UK)
ST = State
L = Location
O = Organization Name
OU = Organizational Unit
CN = www.localhost.com
[v3_req]
keyUsage = critical, digitalSignature, keyAgreement
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = www.localhost.com
DNS.2 = localhost.com
DNS.3 = localhost

The bolded part is up to you to fill in. It’s important that Country is only two letters, otherwise the certification can’t be generated. My information looks like this:

C = SE
ST = Stockholm
L = Stockholm
O = MyCompany
OU = Dev Department

In the certification folder I used the Terminal and typed:

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout cert.key -out cert.pem -config req.cnf -sha256

This line of code generates two files — cert.key and cert.perm

3. Node HTTPS Server

I now have my key and certification. These files will now be an option when creating a HTTPS Server.

Besides the httpsOptions, I also need to import File System. Otherwise Node won’t find the files.

const express = require('express')
const https = require('https')
const fs = require('fs')
const app = express()app.get('/', function (req, res) {
res.send('hello world')
})
const httpsOptions = {
key: fs.readFileSync('./certification/cert.key'),
cert: fs.readFileSync('./certification/cert.pem')
}
https.createServer(httpsOptions, app)const PORT = 5001;
const port = process.env.PORT||PORT;
app.listen(port);
console.log(`Running on ${PORT}`);

Ok! Everything is set! Lets go!

4. Detour

Here I got a problem, besides the certification, and that is that I can’t even reach the certification. In the information box, there should be a Certification option. But there isn’t. What’s the problem?

The answer is the I put a listener on app. It should listen to the https.createServer instead. So remove this line:

app.listen(port);

And add this instead:

https.createServer(httpsOptions, app).listen(port)

This is how it should look like:

const express = require('express')
const https = require('https')
const fs = require('fs')
const app = express()app.get('/', function (req, res) {
res.send('hello world')
})
const httpsOptions = {
key: fs.readFileSync('./certification/cert.key'),
cert: fs.readFileSync('./certification/cert.pem')
}
const PORT = 5001;
const port = process.env.PORT||PORT;
https.createServer(httpsOptions, app).listen(port)console.log(`Running on ${PORT}`);

5. Move that Certification!

Now we can reach the Certification option by clicking on Not Secure in browsers search bar.

Click on the Certificate option and a new window will open.

Now — drag that little icon, gently, and drop it on your Desktop.

Double click on the icon and enter password

Now you are in your Keychain. Double click on the certificate again.

Choose Always Trust option.

And confirm changes.

You can move the certificate on the Desktop to the Bin.

Now we are done! Take a coffee break.

Oh! Sorry! There is one more part!

6. Reload server

Cut the server with CTRL + C and restart the Node server. Sometimes you also have to close down the browser. You have to try.

If you are using Nodemon, just reload the page.

Now you got that fancy padlock and a secure localhost.

Well, hello to you, too.

7. References

https://www.digicert.com/blog/not-secure-warning-what-to-do/
https://stackoverflow.com/a/49784278/5900793

--

--

Steffo Dimfelt

Twentyfive years of graphic design. Six years of development. A lifetime of curiosity.