bugl
bugl
HomeLearnPatternsSearch
HomeLearnPatternsSearch

Loading lesson path

Learn/Node.js/Node.js Advanced
Node.js•Node.js Advanced

Node.js TLS/SSL Module

Concept visual

Node.js TLS/SSL Module

Pointer walk
two pointers
leftright102132436485116
left=0
right=6
1
3

Start at both ends

What is TLS/SSL?

Transport Layer Security (TLS) and its predecessor, Secure Socket Layer (SSL), are protocols that provide secure communication over a computer network. They ensure:

Privacy

: Communications are encrypted to prevent eavesdropping

Data integrity

: Message contents cannot be modified without detection

Authentication

: The identities of the communicating parties can be verified

Formula

TLS/SSL is commonly used for securing:

Web browsing (HTTPS) Email transmissions (SMTP, IMAP, POP3)

Instant messaging

Voice over IP (VoIP)

API communication

Using the TLS Module

To use the TLS module in Node.js, you need to require it:

const tls = require('tls');

TLS Server

Here's how to create a basic TLS server:

const tls = require('tls');
const fs = require('fs');
const path = require('path');
// Server options with TLS certificates const options = {
key: fs.readFileSync(path.join(__dirname, 'server-key.pem')), cert: fs.readFileSync(path.join(__dirname, 'server-cert.pem')),
// Request client certificate (optional)

requestCert: true, // Reject connections without authorized certificates (optional) rejectUnauthorized: false

};
// Create TLS server const server = tls.createServer(options, (socket) => {
console.log('Server connected', socket.authorized ? 'authorized' : 'unauthorized');
// Set encoding for data socket.setEncoding('utf8');
// Handle incoming data socket.on('data', (data) => {
console.log('Received:', data);
// Echo back the data socket.write(`You said: ${data}`);
});
// Handle socket closure socket.on('end', () => {
console.log('Socket ended');
});
// Write welcome message socket.write('Welcome to the TLS server!\n');
});
// Start TLS server const port = 8000;
server.listen(port, () => {
console.log(`TLS server running on port ${port}`);
});
This example requires certificate files (

Formula

server - key.pem and server - cert.pem
). For development purposes, you can generate self - signed certificates using OpenSSL.

Generating Self-Signed Certificates for Development

Formula

You can use OpenSSL to generate self - signed certificates for development and testing:

# Generate CA certificate openssl genrsa -out ca-key.pem 2048 openssl req -new -x509 -key ca-key.pem -out ca-cert.pem -days 365 # Generate server certificate openssl genrsa -out server-key.pem 2048 openssl req -new -key server-key.pem -out server-csr.pem openssl x509 -req -in server-csr.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -days 365 # Generate client certificate (optional, for mutual authentication) openssl genrsa -out client-key.pem 2048 openssl req -new -key client-key.pem -out client-csr.pem openssl x509 -req -in client-csr.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem -days 365

TLS Client

Creating a client that connects to a TLS server:

const tls = require('tls');
const fs = require('fs');
const path = require('path');
// Client options const options = {
// For mutual authentication (optional)
key: fs.readFileSync(path.join(__dirname, 'client-key.pem')), cert: fs.readFileSync(path.join(__dirname, 'client-cert.pem')),
// Server name for Server Name Indication (SNI)
servername: 'localhost',
// CA certificate to verify the server (optional)

Formula

ca: fs.readFileSync(path.join(__dirname, 'ca - cert.pem')),

// Reject unauthorized certificates rejectUnauthorized: true

};
// Connect to server const client = tls.connect(8000, 'localhost', options, () => {
// Check if authorized console.log('Client connected', client.authorized ? 'authorized' : 'unauthorized');
if (!client.authorized) {
console.log('Reason:', client.authorizationError);
}
// Send data to server client.write('Hello from TLS client!');
});
// Set encoding for received data client.setEncoding('utf8');
// Handle received data client.on('data', (data) => {
console.log('Received from server:', data);
// Send another message client.write('How are you?');
});
// Handle errors client.on('error', (error) => {
console.error('Connection error:', error);
});
// Handle connection end client.on('end', () => {
console.log('Server ended connection');
});
// Close connection after 5 seconds setTimeout(() => {
console.log('Closing connection');
client.end();
}, 5000);

Server and Client Options

Both tls.createServer() and tls.connect() accept various options to configure the TLS connection:

Common Options key

: Private key in PEM format cert : Certificate in PEM format ca : Trusted CA certificates ciphers : Cipher suite specification string minVersion : Minimum TLS version to allow maxVersion : Maximum TLS version to allow

Server-specific Options requestCert

: Whether to request a certificate from clients rejectUnauthorized : Whether to reject clients with invalid certificates

SNICallback

: Function to handle SNI from the client

Client-specific Options servername

: Server name for SNI checkServerIdentity : Function to verify server hostname session

: A Buffer instance containing TLS session const tls = require('tls');
const fs = require('fs');
// Comprehensive server options const serverOptions = {

Formula

// Key and certificate key: fs.readFileSync('server - key.pem'), cert: fs.readFileSync('server - cert.pem'),
// Certificate Authority ca: [fs.readFileSync('ca - cert.pem')],

// Protocol version control minVersion: 'TLSv1.2', maxVersion: 'TLSv1.3',

Formula

// Cipher control ciphers: 'ECDHE - RSA - AES128 - GCM - SHA256:ECDHE - RSA - AES256 - GCM - SHA384',

// Client authentication requestCert: true, rejectUnauthorized: true, // Server Name Indication handling SNICallback: (servername, cb) => {

// Different certificates for different servernames if (servername === 'example.com') {
cb(null, tls.createSecureContext({

Formula

key: fs.readFileSync('example - key.pem'), cert: fs.readFileSync('example - cert.pem')
}));
} else {
// Default certificate cb(null, tls.createSecureContext({

Formula

key: fs.readFileSync('default - key.pem'), cert: fs.readFileSync('default - cert.pem')
}));
}
}
};
// Example client options const clientOptions = {
key: fs.readFileSync('client-key.pem'), cert: fs.readFileSync('client-cert.pem'), ca: [fs.readFileSync('ca-cert.pem')], servername: 'example.com', minVersion: 'TLSv1.2',
// Custom identity check function checkServerIdentity: (hostname, cert) => {
// Custom validation logic if (hostname !== cert.subject.CN) {
return new Error(`Certificate CN does not match hostname: ${hostname}`);
}
return undefined; // No error
},

// Session reuse session: savedTlsSession, // Previously saved session

};
Secure HTTP Server (HTTPS)

While the TLS module can be used directly, for HTTPS servers, Node.js provides a higher-level https module built on top of TLS:

const https = require('https');
const fs = require('fs');
const path = require('path');
// HTTPS server options const options = {
key: fs.readFileSync(path.join(__dirname, 'server-key.pem')), cert: fs.readFileSync(path.join(__dirname, 'server-cert.pem'))
};
// Create HTTPS server https.createServer(options, (req, res) => {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('<h1>Secure HTTPS Server</h1><p>This connection is encrypted using TLS.</p>');
}).listen(443, () => {
console.log('HTTPS server running on port 443');
});

The HTTPS module provides a more convenient way to create secure HTTP servers, but it uses the TLS module under the hood.

TLS with Express

You can also create an HTTPS server with Express:

const express = require('express');
const https = require('https');
const fs = require('fs');
const path = require('path');
// Create Express app const app = express();
// Define routes app.get('/', (req, res) => {
res.send('<h1>Secure Express App</h1><p>This connection is encrypted using TLS.</p>');
});
app.get('/api/data', (req, res) => {
res.json({
message: 'This is sensitive data', timestamp: new Date()
});
});
// HTTPS server options const options = {
key: fs.readFileSync(path.join(__dirname, 'server-key.pem')), cert: fs.readFileSync(path.join(__dirname, 'server-cert.pem'))
};
// Create HTTPS server with Express app const port = 443;
https.createServer(options, app).listen(port, () => {
console.log(`Secure Express app running on port ${port}`);
});

Certificate Verification

TLS uses certificates to verify the identity of servers and optionally clients. Here's an example showing how to implement custom certificate verification:

const tls = require('tls');
const fs = require('fs');
// Custom verification function function validateCertificate(cert) {
// Basic certificate info console.log('Certificate subject:', cert.subject);
console.log('Certificate issuer:', cert.issuer);
console.log('Valid from:', cert.valid_from);
console.log('Valid to:', cert.valid_to);
// Check certificate validity period const now = new Date();
const validFrom = new Date(cert.valid_from);
const validTo = new Date(cert.valid_to);
if (now < validFrom || now > validTo) {
return { valid: false, reason: 'Certificate is not within its validity period' };
}

// Additional checks could include: // - Certificate revocation status // - Certificate chain validation

// - Public key strength return { valid: true };
}
// Create TLS client with custom validation const options = {
ca: [fs.readFileSync('ca-cert.pem')], checkServerIdentity: (hostname, cert) => {
// First check the certificate against our custom rules const validationResult = validateCertificate(cert);
if (!validationResult.valid) {
return new Error(validationResult.reason);
}
// Then verify the hostname matches the certificate const certCN = cert.subject.CN;
if (hostname !== certCN &&

!cert.subjectaltname ||

!cert.subjectaltname.includes(hostname)) {
return new Error(`Certificate name mismatch: ${hostname} !== ${certCN}`);
}
// Certificate is valid return undefined;
}
};
// Connect to server with custom verification const client = tls.connect(8000, 'example.com', options, () => {
if (client.authorized) {
console.log('Connection authorized');
client.write('Secure message');
} else {
console.log('Connection not authorized:', client.authorizationError);
}
});
// Handle connection events client.on('error', (error) => {
console.error('TLS error:', error);
});
client.on('end', () => {
console.log('Connection ended');
});

TLS Session Resumption

Session resumption allows clients to reconnect to a server without performing a full TLS handshake, improving performance:

const tls = require('tls');
const fs = require('fs');
const path = require('path');
// Server options const serverOptions = {
key: fs.readFileSync(path.join(__dirname, 'server-key.pem')), cert: fs.readFileSync(path.join(__dirname, 'server-cert.pem')),
// Enable session resumption sessionTimeout: 300, // Session timeout in seconds ticketKeys: Buffer.from('0123456789abcdef0123456789abcdef'), // 32 bytes for key encryption
};
// Create TLS server const server = tls.createServer(serverOptions, (socket) => {
console.log('Client connected');
// Check if this is a resumed session if (socket.isSessionReused()) {
console.log('Session reused!');
} else {
console.log('New session');
}
socket.on('data', (data) => {
console.log('Received:', data.toString());
socket.write('Hello back!');
});
socket.on('end', () => {
console.log('Client disconnected');
});
});
server.listen(8443, () => {
console.log('TLS server listening on port 8443');
// First client connection connectClient(() => {
// Second client connection - should use session resumption connectClient();
});
});
// Function to create a client with session resumption let savedSession = null;
function connectClient(callback) {
const clientOptions = {

Formula

rejectUnauthorized: false, // For self - signed certificates session: savedSession // Use saved session if available
};
const client = tls.connect(8443, 'localhost', clientOptions, () => {
console.log('Client connected. Authorized:', client.authorized);
console.log('Using session resumption:', client.isSessionReused());
// Save the session for future connections savedSession = client.getSession();
// Send data client.write('Hello server!');
// Close after a short delay setTimeout(() => {
client.end();
if (callback) setTimeout(callback, 100);
}, 100);
});
client.on('data', (data) => {
console.log('Client received:', data.toString());
});
client.on('error', (err) => {
console.error('Client error:', err);
});
}
Server Name Indication (SNI)

SNI allows a server to present different certificates for different hostnames on the same IP address and port:

const tls = require('tls');
const fs = require('fs');
const path = require('path');
// Load different certificates for different domains const serverOptions = {
SNICallback: (servername, cb) => {
console.log(`SNI request for: ${servername}`);
// Different certificate contexts based on hostname if (servername === 'example.com') {
const context = tls.createSecureContext({
key: fs.readFileSync(path.join(__dirname, 'example.com-key.pem')), cert: fs.readFileSync(path.join(__dirname, 'example.com-cert.pem'))
});
cb(null, context);
}
else if (servername === 'another.com') {
const context = tls.createSecureContext({
key: fs.readFileSync(path.join(__dirname, 'another.com-key.pem')), cert: fs.readFileSync(path.join(__dirname, 'another.com-cert.pem'))
});
cb(null, context);
}
else {
// Default certificate const context = tls.createSecureContext({
key: fs.readFileSync(path.join(__dirname, 'default-key.pem')), cert: fs.readFileSync(path.join(__dirname, 'default-cert.pem'))
});
cb(null, context);
}
},
// Default keys and certificates (used as a fallback)
key: fs.readFileSync(path.join(__dirname, 'default-key.pem')), cert: fs.readFileSync(path.join(__dirname, 'default-cert.pem'))
};
// Create server const server = tls.createServer(serverOptions, (socket) => {
socket.write(`Hello, you connected to ${socket.servername || 'unknown'}!\n`);
socket.end();
});
server.listen(8443, () => {
console.log('TLS SNI server running on port 8443');
});

Advanced Certificate Management

Proper certificate management is crucial for secure TLS communications. Here are some advanced techniques:

1. Certificate Chain and Multiple CAs const tls = require('tls');
const fs = require('fs');
const path = require('path');
// Load multiple CA certificates const caCerts = [
fs.readFileSync(path.join(__dirname, 'ca1-cert.pem')), fs.readFileSync(path.join(__dirname, 'ca2-cert.pem')), fs.readFileSync(path.join(__dirname, 'intermediate-cert.pem'))
];
// Server with multiple CA certificates const serverOptions = {
key: fs.readFileSync(path.join(__dirname, 'server-key.pem')), cert: fs.readFileSync(path.join(__dirname, 'server-cert.pem')), ca: caCerts,  // Array of CA certificates requestCert: true, rejectUnauthorized: true
};
const server = tls.createServer(serverOptions, (socket) => {
console.log('Client connected:', socket.authorized ? 'Authorized' : 'Unauthorized');
// Get peer certificate const cert = socket.getPeerCertificate();
console.log('Client certificate subject:', cert.subject);
console.log('Issuer:', cert.issuer.CN);
socket.write('Welcome to the secure server!\n');
socket.end();
});
server.listen(8000, () => {
console.log('TLS server running on port 8000');
});
  1. Certificate Revocation with CRL
const tls = require('tls');
const fs = require('fs');
const crypto = require('crypto');
// Load CRL (Certificate Revocation List)
const crl = fs.readFileSync('revoked-certs.pem');
// Parse CRL to check against const checkRevocation = (cert) => {

// In a real application, you would parse the CRL and check // if the certificate's serial number is in the revocation list

// For demonstration, we'll just check against a known revoked serial const revokedSerials = [
'0123456789ABCDEF', // Example revoked serial
'FEDCBA9876543210'
];
const certInfo = crypto.certificateVerify(

cert.raw, 'sha256', Buffer.from(''), Buffer.from('')

);
return !revokedSerials.includes(certInfo.serialNumber.toString('hex').toUpperCase());
};
const server = tls.createServer({
key: fs.readFileSync('server-key.pem'), cert: fs.readFileSync('server-cert.pem'), requestCert: true, rejectUnauthorized: true,
// Custom certificate validation checkServerIdentity: (host, cert) => {
if (!checkRevocation(cert)) {
return new Error('Certificate has been revoked');
}
return undefined; // No error means certificate is valid
}
}, (socket) => {
// Handle connection console.log('Client connected:', socket.authorized ? 'Authorized' : 'Unauthorized');
socket.end('Hello secure world!\n');
});
server.listen(8000);
3. Automatic Certificate Management with Let's Encrypt const tls = require('tls');
const https = require('https');
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
class TLSCertManager {
constructor(domain, email) {
this.domain = domain;
this.email = email;
this.certDir = path.join(__dirname, 'certs', domain);
this.ensureCertDir();
}
ensureCertDir() {
if (!fs.existsSync(this.certDir)) {
fs.mkdirSync(this.certDir, { recursive: true });
}
}
async getCertificates() {
const keyPath = path.join(this.certDir, 'privkey.pem');
const certPath = path.join(this.certDir, 'cert.pem');
const chainPath = path.join(this.certDir, 'chain.pem');
// Check if certificates exist and are valid if (this.certsValid(keyPath, certPath, chainPath)) {
return {
key: fs.readFileSync(keyPath), cert: fs.readFileSync(certPath), ca: fs.readFileSync(chainPath)
};
}
// Use certbot to obtain new certificates return await this.obtainCertificates();
}
certsValid(keyPath, certPath, chainPath) {
try {
if (!fs.existsSync(keyPath) || !fs.existsSync(certPath) || !fs.existsSync(chainPath)) {
return false;
}
// Check if certificate is valid for at least 7 more days const cert = fs.readFileSync(certPath);
const notAfter = cert.toString().match(/Not After : (.*?)\n/)[1];
const expiryDate = new Date(notAfter);
const now = new Date();
return (expiryDate - now) > 7 * 24 * 60 * 60 * 1000; // 7 days in ms
} catch (err) {
console.error('Error checking certificate validity:', err);
return false;
}
}
async obtainCertificates() {
try {
// This is a simplified example - in production, use a proper ACME client console.log('Obtaining new certificates from Let\'s Encrypt...');
// In a real application, you would use an ACME client like 'greenlock' or 'acme'
// This is just a placeholder to illustrate the concept execSync(`certbot certonly --standalone -d ${this.domain} --email ${this.email} --agree-tos --non-interactive`);
// Copy certificates to our certs directory const certs = {
key: fs.readFileSync(`/etc/letsencrypt/live/${this.domain}/privkey.pem`), cert: fs.readFileSync(`/etc/letsencrypt/live/${this.domain}/cert.pem`), ca: fs.readFileSync(`/etc/letsencrypt/live/${this.domain}/chain.pem`)
};
// Save certificates for future use fs.writeFileSync(path.join(this.certDir, 'privkey.pem'), certs.key);
fs.writeFileSync(path.join(this.certDir, 'cert.pem'), certs.cert);
fs.writeFileSync(path.join(this.certDir, 'chain.pem'), certs.ca);
return certs;
} catch (err) {
console.error('Failed to obtain certificates:', err);
throw err;
}
}
}
// Usage example async function createSecureServer() {
const certManager = new TLSCertManager('example.com', 'admin@example.com');
try {
const certs = await certManager.getCertificates();
const server = https.createServer({

key: certs.key, cert: certs.cert, ca: certs.ca, requestCert: true, rejectUnauthorized: true

}, (req, res) => {
res.writeHead(200);
res.end('Hello, secure world!\n');
});
server.listen(443, () => {
console.log('HTTPS server running on port 443');
});
// Schedule certificate renewal check (e.g., daily)
setInterval(async () => {
try {
await certManager.getCertificates();
} catch (err) {
console.error('Certificate renewal check failed:', err);
}
}, 24 * 60 * 60 * 1000); // Check daily
} catch (err) {
console.error('Failed to start secure server:', err);
process.exit(1);
}
}
createSecureServer();

Note:

The Let's Encrypt example is simplified. In production, use a well-maintained ACME client library and follow Let's Encrypt's rate limits and best practices.

Security Best Practices

When using TLS in production applications, consider these security best practices:

1. Use Strong TLS Versions const options = {
// Disable older TLS versions minVersion: 'TLSv1.2',

// Explicitly disallow TLS 1.0 and 1.1 secureOptions: crypto.constants.SSL_OP_NO_TLSv1 | crypto.constants.SSL_OP_NO_TLSv1_1

};
2. Configure Strong Cipher Suites const options = {
// Prioritize modern, secure cipher suites ciphers: [
'TLS_AES_256_GCM_SHA384',
'TLS_CHACHA20_POLY1305_SHA256',
'TLS_AES_128_GCM_SHA256',

Formula

'ECDHE - RSA - AES256 - GCM - SHA384',
'ECDHE - RSA - AES128 - GCM - SHA256'

].join(':')

};
  1. Use Perfect Forward Secrecy

Formula

// Cipher suites with ECDHE (Elliptic Curve Diffie - Hellman Ephemeral) support PFS
const options = {

Formula

ciphers: 'ECDHE - RSA - AES128 - GCM - SHA256:ECDHE - RSA - AES256 - GCM - SHA384'
};
  1. Implement OCSP Stapling (Online Certificate Status Protocol)
const tls = require('tls');
const https = require('https');
const fs = require('fs');
const path = require('path');
// Server with OCSP stapling const serverOptions = {
key: fs.readFileSync(path.join(__dirname, 'server-key.pem')), cert: fs.readFileSync(path.join(__dirname, 'server-cert.pem')), ca: fs.readFileSync(path.join(__dirname, 'ca-cert.pem')),

// Enable OCSP stapling requestOCSP: true, // OCSP response cache timeout (in milliseconds)

ocspCache: new tls.OCSPCache({

Formula

max: 1000, // Maximum number of cached responses maxAge: 60 * 60 * 1000 // Cache for 1 hour
})
};
// Create HTTPS server with OCSP stapling const server = https.createServer(serverOptions, (req, res) => {
res.writeHead(200);
res.end('Hello with OCSP stapling!\n');
});
// Handle OCSP request errors server.on('OCSPRequest', (cert, issuer, callback) => {
if (!cert || !issuer) {
return callback(new Error('No certificate or issuer provided'));
}
// Get OCSP URL from certificate const ocspUrl = tls.getOCSPURL(cert);
if (!ocspUrl) {
return callback(new Error('No OCSP URL in certificate'));
}
console.log('OCSP request for:', cert.subject.CN);

// In a real application, you would make an OCSP request here

// and return the response via the callback
// For demonstration, we'll just return a dummy response const ocspResponse = Buffer.from('OCSP response would go here');
callback(null, ocspResponse);
});
server.listen(443, () => {
console.log('HTTPS server with OCSP stapling running on port 443');
});
// Client that verifies OCSP stapling const clientOptions = {
host: 'example.com', port: 443, rejectUnauthorized: true, requestOCSP: true  // Request OCSP stapling from server
};
const req = https.request(clientOptions, (res) => {
console.log('Response status code:', res.statusCode);
// Get the OCSP response from the server const ocspResponse = res.socket.getOCSPResponse();
if (ocspResponse) {
console.log('Received OCSP response');

// Verify the OCSP response here

} else {
console.log('No OCSP response received');
}
res.on('data', (chunk) => {
console.log('Received data:', chunk.toString());
});
});
req.on('error', (err) => {
console.error('Request error:', err);
});
req.end();
  1. ALPN and SNI Support Application-Layer Protocol Negotiation (ALPN) and Server Name Indication (SNI) are important TLS extensions that enable protocol negotiation and virtual hosting:
const tls = require('tls');
const http2 = require('http2');
const https = require('https');
const fs = require('fs');
const path = require('path');
// Server with ALPN and SNI support const serverOptions = {

// ALPN protocols in order of preference

Formula

ALPNProtocols: ['h2', 'http/1.1'],

// SNI callback for multiple domains SNICallback: (servername, cb) => {

console.log('SNI request for:', servername);
try {
let context;
// Create different contexts for different domains if (servername === 'example.com') {
context = tls.createSecureContext({
key: fs.readFileSync(path.join(__dirname, 'example.com-key.pem')), cert: fs.readFileSync(path.join(__dirname, 'example.com-cert.pem')),

// Enable OCSP stapling for this domain requestOCSP: true, // Custom cipher suites for this domain ciphers: [ 'TLS_AES_256_GCM_SHA384', 'TLS_CHACHA20_POLY1305_SHA256', 'TLS_AES_128_GCM_SHA256' ].join(':')

});
} else {
// Default context for other domains context = tls.createSecureContext({
key: fs.readFileSync(path.join(__dirname, 'default-key.pem')), cert: fs.readFileSync(path.join(__dirname, 'default-cert.pem')),
// Less strict ciphers for legacy clients ciphers: [
'TLS_AES_256_GCM_SHA384',
'TLS_CHACHA20_POLY1305_SHA256',
'TLS_AES_128_GCM_SHA256',

Formula

'ECDHE - RSA - AES256 - GCM - SHA384',
'ECDHE - RSA - AES128 - GCM - SHA256'

].join(':')

});
}
// Set ALPN protocols for this context context.setALPNProtocols(['h2', 'http/1.1']);
// Return the created context if (cb) {
cb(null, context);
} else {
return context;
}
} catch (err) {
console.error('SNI callback error:', err);
if (cb) {
cb(err);
} else {
throw err;
}
}
},
// Default key and cert (used if SNI is not supported by client)
key: fs.readFileSync(path.join(__dirname, 'default-key.pem')), cert: fs.readFileSync(path.join(__dirname, 'default-cert.pem'))
};

Formula

// Create HTTP/2 server with ALPN and SNI
const http2Server = http2.createSecureServer(serverOptions, (req, res) => {
const protocol = req.socket.alpnProtocol;
res.writeHead(200);
res.end(`Hello from ${req.socket.servername} using ${protocol}\n`);
});
http2Server.on('error', (err) => {
console.error('HTTP/2 server error:', err);
});
http2Server.on('stream', (stream, headers) => {
const protocol = stream.session.alpnProtocol;
const hostname = stream.session.servername || 'unknown';
stream.respond({
'content-type': 'text/plain; charset=utf-8',
':status': 200
});
stream.end(`HTTP/2 stream from ${hostname} using ${protocol}\n`);
});

// Create HTTPS server with ALPN and SNI

const httpsServer = https.createServer(serverOptions, (req, res) => {
const protocol = req.socket.alpnProtocol;
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end(`Hello from ${req.socket.servername} using ${protocol || 'HTTP/1.1'}\n`);
});
// Handle upgrade to HTTP/2 httpsServer.on('upgrade', (req, socket, head) => {
const protocol = req.socket.alpnProtocol;
if (protocol === 'h2') {
http2Server.emit('connection', socket);
} else {
socket.destroy();
}
});
// Start servers const PORT = 443;
httpsServer.listen(PORT, () => {
console.log(`HTTPS server running on port ${PORT}`);
});
// Client example function makeRequest(hostname, port = 443) {
const options = {
hostname, port, path: '/', method: 'GET',

// Enable ALPN

Formula

ALPNProtocols: ['h2', 'http/1.1'],

// Set SNI servername: hostname,

Formula

// Verify certificate rejectUnauthorized: false, // For testing with self - signed certs

// Custom check for server identity checkServerIdentity: (host, cert) => {

// Implement custom certificate validation return undefined; // No error means success
}
};
const req = https.request(options, (res) => {
console.log(`Status: ${res.statusCode}`);
console.log('ALPN Protocol:', res.socket.alpnProtocol);
console.log('Negotiated Protocol:', res.socket.getProtocol());
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log('Response:', data.trim());
});
});
req.on('error', (err) => {
console.error('Request error:', err);
});
req.end();
}

// Example usage

// makeRequest('example.com');
// makeRequest('another-domain.com');
  1. Use HTTP Strict Transport Security (HSTS)
// In an Express application app.use((req, res, next) => {
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
next();
});

Previous

Node.js VM Module

Next

Node.js Net Module