Last updated: 2026-02-11
Node.js TLS/SSL Configuration Guide
This guide provides recommended TLS/SSL settings for Node.js applications. Node.js uses the built-in tls and https modules, which wrap OpenSSL, to provide encrypted connections for both servers and clients.
Prerequisites
- Node.js 18 or later (LTS with TLS 1.3 support)
- OpenSSL 1.1.1 or later (bundled with Node.js)
- A valid TLS certificate and private key (PEM format)
HTTPS Server Configuration
Basic HTTPS Server
Use https.createServer() with TLS options to serve HTTPS:
const https = require('node:https');
const fs = require('node:fs');
const options = {
cert: fs.readFileSync('/etc/ssl/certs/server.crt'),
key: fs.readFileSync('/etc/ssl/private/server.key'),
ca: fs.readFileSync('/etc/ssl/certs/ca.crt'),
};
const server = https.createServer(options, (req, res) => {
res.writeHead(200);
res.end('Hello, TLS!\n');
});
server.listen(443);
TLS Protocol Versions
Restrict connections to TLS 1.2 and TLS 1.3:
const options = {
cert: fs.readFileSync('/etc/ssl/certs/server.crt'),
key: fs.readFileSync('/etc/ssl/private/server.key'),
minVersion: 'TLSv1.2',
maxVersion: 'TLSv1.3',
};
Cipher Suite Configuration
Specify strong cipher suites for TLS 1.2. TLS 1.3 ciphers are managed automatically by OpenSSL and cannot be overridden via the ciphers option.
const options = {
cert: fs.readFileSync('/etc/ssl/certs/server.crt'),
key: fs.readFileSync('/etc/ssl/private/server.key'),
minVersion: 'TLSv1.2',
ciphers: [
'TLS_AES_256_GCM_SHA384',
'TLS_CHACHA20_POLY1305_SHA256',
'TLS_AES_128_GCM_SHA256',
'ECDHE-ECDSA-AES256-GCM-SHA384',
'ECDHE-RSA-AES256-GCM-SHA384',
'ECDHE-ECDSA-AES128-GCM-SHA256',
'ECDHE-RSA-AES128-GCM-SHA256',
'ECDHE-ECDSA-CHACHA20-POLY1305',
'ECDHE-RSA-CHACHA20-POLY1305',
].join(':'),
honorCipherOrder: true,
};
ECDH Curve
Specify the ECDH curves for key exchange:
const options = {
// ...certificates...
ecdhCurve: 'X25519:P-256:P-384',
};
Secure Options
Disable insecure features via secureOptions:
const crypto = require('node:crypto');
const options = {
// ...certificates...
secureOptions:
crypto.constants.SSL_OP_NO_SSLv2 |
crypto.constants.SSL_OP_NO_SSLv3 |
crypto.constants.SSL_OP_NO_TLSv1 |
crypto.constants.SSL_OP_NO_TLSv1_1 |
crypto.constants.SSL_OP_NO_COMPRESSION,
};
When using
minVersion: 'TLSv1.2', theSSL_OP_NO_*flags for older protocols are set automatically. TheSSL_OP_NO_COMPRESSIONflag is still useful to explicitly disable TLS compression.
Client Certificate Verification (mTLS)
Require and verify client certificates for mutual TLS:
const options = {
cert: fs.readFileSync('/etc/ssl/certs/server.crt'),
key: fs.readFileSync('/etc/ssl/private/server.key'),
ca: fs.readFileSync('/etc/ssl/certs/ca.crt'),
requestCert: true,
rejectUnauthorized: true,
};
Access client certificate details in the request handler:
const server = https.createServer(options, (req, res) => {
const cert = req.socket.getPeerCertificate();
console.log('Client CN:', cert.subject.CN);
res.writeHead(200);
res.end('Authenticated\n');
});
Express.js HTTPS
Wrap an Express application with HTTPS:
const https = require('node:https');
const fs = require('node:fs');
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello, TLS!');
});
const options = {
cert: fs.readFileSync('/etc/ssl/certs/server.crt'),
key: fs.readFileSync('/etc/ssl/private/server.key'),
minVersion: 'TLSv1.2',
ciphers: [
'ECDHE-ECDSA-AES256-GCM-SHA384',
'ECDHE-RSA-AES256-GCM-SHA384',
'ECDHE-ECDSA-AES128-GCM-SHA256',
'ECDHE-RSA-AES128-GCM-SHA256',
'ECDHE-ECDSA-CHACHA20-POLY1305',
'ECDHE-RSA-CHACHA20-POLY1305',
].join(':'),
honorCipherOrder: true,
};
https.createServer(options, app).listen(443);
TLS for Outbound Connections
HTTPS Client Requests
Configure TLS when making outbound HTTPS requests:
const https = require('node:https');
const options = {
hostname: 'api.example.com',
port: 443,
path: '/data',
method: 'GET',
ca: fs.readFileSync('/etc/ssl/certs/ca.crt'),
minVersion: 'TLSv1.2',
// For client certificate authentication:
cert: fs.readFileSync('/etc/ssl/certs/client.crt'),
key: fs.readFileSync('/etc/ssl/private/client.key'),
};
const req = https.request(options, (res) => {
// handle response
});
req.end();
Low-Level TLS Connections
Use tls.connect() for non-HTTP TLS connections:
const tls = require('node:tls');
const options = {
host: 'db.example.com',
port: 5432,
ca: fs.readFileSync('/etc/ssl/certs/ca.crt'),
minVersion: 'TLSv1.2',
checkServerIdentity: tls.checkServerIdentity,
};
const socket = tls.connect(options, () => {
console.log('Connected, authorized:', socket.authorized);
});
Complete Server Example
const https = require('node:https');
const crypto = require('node:crypto');
const fs = require('node:fs');
const server = https.createServer(
{
// Certificates
cert: fs.readFileSync('/etc/ssl/certs/server.crt'),
key: fs.readFileSync('/etc/ssl/private/server.key'),
ca: fs.readFileSync('/etc/ssl/certs/ca.crt'),
// Protocol versions
minVersion: 'TLSv1.2',
maxVersion: 'TLSv1.3',
// Cipher suites (TLS 1.2)
ciphers: [
'ECDHE-ECDSA-AES256-GCM-SHA384',
'ECDHE-RSA-AES256-GCM-SHA384',
'ECDHE-ECDSA-AES128-GCM-SHA256',
'ECDHE-RSA-AES128-GCM-SHA256',
'ECDHE-ECDSA-CHACHA20-POLY1305',
'ECDHE-RSA-CHACHA20-POLY1305',
].join(':'),
honorCipherOrder: true,
// ECDH curves
ecdhCurve: 'X25519:P-256:P-384',
// Security options
secureOptions: crypto.constants.SSL_OP_NO_COMPRESSION,
// Session tickets
sessionTimeout: 300,
},
(req, res) => {
res.writeHead(200, { 'Strict-Transport-Security': 'max-age=63072000' });
res.end('Secure response\n');
}
);
server.listen(443, () => {
console.log('HTTPS server listening on port 443');
});
Verification
Test your server with openssl s_client:
openssl s_client -connect localhost:443 -tls1_2
openssl s_client -connect localhost:443 -tls1_3
Check the negotiated protocol and cipher:
echo | openssl s_client -connect localhost:443 2>/dev/null | grep -E 'Protocol|Cipher'
Verify from Node.js itself:
const tls = require('node:tls');
const socket = tls.connect({ host: 'localhost', port: 443, rejectUnauthorized: false }, () => {
console.log('Protocol:', socket.getProtocol());
console.log('Cipher:', socket.getCipher());
socket.end();
});