Skip to content

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

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', the SSL_OP_NO_* flags for older protocols are set automatically. The SSL_OP_NO_COMPRESSION flag 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();
});