Installing an SSL Certificate on Node.js

Installing an SSL Certificate on Node.js

Andrew Johnson

Node.js takes a different approach to HTTPS than traditional web servers. There is no configuration file to edit and no service to bind. The SSL Certificate is loaded directly in application code through the built-in https module, which gives developers complete control and also complete responsibility for getting the chain right.

This guide covers the standard https server setup, correct Intermediate Certificate handling, and the reverse proxy question that every production Node.js deployment eventually faces.

Prerequisites and Required Files

You need your issued SSL Certificate file and the ca-bundle containing the Intermediate Certificates, both available in the tracking system after issuance. View Our Tracking & SSL Management 🔗

You also need the Private Key generated alongside your Certificate Signing Request (CSR). Trustico® does not retain Private Keys, so the copy on your server is the only one in existence. Learn About Generating a CSR 🔗

Place all three files in a directory outside the public and static folders of your application. Restrict the Private Key so only the application user can read it, for example with chmod 600 yourdomain.key.

Creating the HTTPS Server

The https module accepts the SSL Certificate, the Private Key, and the chain as options when the server is created. Reading the files synchronously at startup is the normal pattern, since the application cannot serve traffic without them anyway.

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

const options = {
  key: fs.readFileSync('/etc/ssl/private/yourdomain.key'),
  cert: fs.readFileSync('/etc/ssl/certs/yourdomain.crt'),
  ca: fs.readFileSync('/etc/ssl/certs/yourdomain.ca-bundle')
};

https.createServer(options, (req, res) => {
  res.writeHead(200);
  res.end('HTTPS is working');
}).listen(443);

The ca option is the part most tutorials omit, and skipping it produces a server that works in desktop browsers while failing on mobile devices and in command line clients. Desktop browsers quietly repair incomplete chains from their cache, which hides the problem until a stricter client connects. Learn About Intermediate Certificates 🔗

An alternative pattern concatenates the SSL Certificate and ca-bundle into one file and passes the combined file through the cert option alone. Both approaches produce an identical chain on the wire, so choose whichever fits your deployment tooling.

Express, Fastify, and similar frameworks plug into the same mechanism. Pass the request handler of the framework to https.createServer in place of the inline function shown above.

Binding Port 443 Without Root Privileges

Ports below 1024 are privileged on Linux, and running a Node.js application as root to reach port 443 is poor practice. The cleaner options are granting the Node.js binary the bind capability, or listening on a high port behind a redirect.

sudo setcap 'cap_net_bind_service=+ep' $(which node)

Many production deployments avoid the question entirely by terminating Transport Layer Security (TLS) at a reverse proxy such as NGINX, with Node.js listening on a local port behind it. The SSL Certificate then installs on the proxy rather than in the application. Learn About SSL Offloading 🔗

Verifying the Installation

Restart the application and load the site over HTTPS. Then run an external scan, which checks the chain exactly as a fresh client receives it and catches the missing ca option mistake immediately. Trustico® provides free checking tools for this purpose. Explore Our Trustico® SSL Tools 🔗

Troubleshooting Common Installation Problems

An error reading key values mismatch or a TLS handshake failure at startup means the Private Key does not pair with the SSL Certificate being loaded. This usually traces to a CSR that was regenerated after submission. A reissue against the current CSR resolves it cleanly. Learn About Reissuing Your SSL Certificate 🔗

An EACCES error on listen means the process lacks permission for the privileged port. Apply the capability grant shown above, or move the application behind a proxy.

Tip : Node.js reads the SSL Certificate files once at startup, so a reissued SSL Certificate does not take effect until the application restarts. Build the restart into your replacement procedure to avoid serving an expired SSL Certificate from memory.

Chain errors reported only by mobile devices or tools such as curl mean the ca option is missing or points at the wrong file. Add the ca-bundle and restart.

Professional Installation Assistance

Application-level HTTPS is quick to set up, but production environments mixing proxies, containers, and multiple services can complicate where the SSL Certificate belongs.

Trustico® offers a Premium Installation service where our technicians complete the installation on your behalf. Discover Our Premium Installation Service 🔗

Back to Blog

Most Popular Questions

Frequently asked questions covering HTTPS configuration in Node.js, including the https module options, the ca option for Intermediate Certificates, privileged port binding, reverse proxy termination, restart requirements after a reissue, startup error diagnosis, and the Trustico® Premium Installation service.

Loading the SSL Certificate Through the https Module

Node.js has no configuration file for HTTPS, so the SSL Certificate, the Private Key, and the chain are passed as the cert, key, and ca options when the server is created. Reading the files synchronously at startup is the normal pattern, and frameworks such as Express and Fastify plug into the same mechanism by passing their request handler to https.createServer.

The ca Option Most Tutorials Omit

Skipping the ca option produces a server that works in desktop browsers while failing on mobile devices and in command line clients, because desktop browsers quietly repair incomplete chains from their cache. An alternative pattern concatenates the SSL Certificate and ca-bundle into one file passed through the cert option alone, and both approaches produce an identical chain on the wire.

Binding Port 443 Without Root Privileges

Ports below 1024 are privileged on Linux, and running a Node.js application as root to reach port 443 is poor practice. The cleaner options are granting the Node.js binary the bind capability with setcap, or listening on a high port behind a redirect.

Terminating TLS at a Reverse Proxy Instead

Many production deployments terminate Transport Layer Security (TLS) at a reverse proxy such as NGINX, with Node.js listening on a local port behind it. The SSL Certificate then installs on the proxy rather than in the application.

Application Restarts After a Reissue

Node.js reads the SSL Certificate files once at startup, so a reissued SSL Certificate does not take effect until the application restarts. Build the restart into the replacement procedure to avoid serving an expired SSL Certificate from memory.

Key Mismatch and EACCES Errors at Startup

A key values mismatch error or a Transport Layer Security (TLS) handshake failure at startup means the Private Key does not pair with the SSL Certificate, which usually traces to a regenerated Certificate Signing Request (CSR) and is resolved cleanly by a reissue. An EACCES error on listen means the process lacks permission for the privileged port, fixed by the capability grant or by moving the application behind a proxy.

Premium Installation Assistance for Node.js Environments

Production environments mixing proxies, containers, and multiple services can complicate where the SSL Certificate belongs. Trustico® offers a Premium Installation service where our technicians complete the installation on your behalf.

Stay Updated - Our RSS Feed

There's never a reason to miss a post! Subscribe to our Atom/RSS feed and get instant notifications when we publish new articles about SSL Certificates, security updates, and news. Use your favorite RSS reader or news aggregator.

Subscribe via RSS/Atom