Skip to main content
HTTPS is the HTTP protocol over TLS/SSL. In Node.js this is implemented as a separate module.

Import

import https from 'node:https';
// or
const https = require('node:https');

Creating an HTTPS Server

Basic Server

import { createServer } from 'node:https';
import { readFileSync } from 'node:fs';

const options = {
  key: readFileSync('private-key.pem'),
  cert: readFileSync('certificate.pem')
};

const server = createServer(options, (req, res) => {
  res.writeHead(200);
  res.end('Hello World\n');
});

server.listen(8000);

With PFX Certificate

import { createServer } from 'node:https';
import { readFileSync } from 'node:fs';

const options = {
  pfx: readFileSync('certificate.pfx'),
  passphrase: 'sample'
};

const server = createServer(options, (req, res) => {
  res.writeHead(200);
  res.end('Hello World\n');
});

server.listen(8000);

Class: https.Server

This class is a subclass of tls.Server and emits events same as http.Server.

Methods

server.close([callback])

  • callback
  • Returns:
Stops the server from accepting new connections.

server.listen([port][, host][, callback])

Starts the HTTPS server listening for encrypted connections.

server.setTimeout([msecs][, callback])

  • msecs Default: 120000 (2 minutes)
  • callback
  • Returns:
Sets the timeout value for sockets.

Properties

server.timeout

  • Type: Default: 0 (no timeout)
The number of milliseconds of inactivity before a socket is presumed to have timed out.

server.keepAliveTimeout

  • Type: Default: 5000 (5 seconds)
The number of milliseconds of inactivity a server needs to wait for additional incoming data.

server.headersTimeout

  • Type: Default: 60000
Limit the amount of time the parser will wait to receive the complete HTTP headers.

server.maxHeadersCount

  • Type: Default: 2000
Limits maximum incoming headers count.

Class: https.Agent

An Agent object for HTTPS similar to http.Agent.

new Agent([options])

  • options
    • maxCachedSessions Maximum number of TLS cached sessions. Default: 100
    • servername Server name for SNI (Server Name Indication)
    • All options from http.Agent
import { Agent, request } from 'node:https';

const agent = new Agent({
  keepAlive: true,
  maxSockets: 10,
  maxCachedSessions: 50
});

const options = {
  hostname: 'encrypted.example.com',
  port: 443,
  path: '/',
  method: 'GET',
  agent: agent
};

const req = request(options, (res) => {
  // Handle response
});

Event: ‘keylog’

  • line Line of ASCII text in NSS SSLKEYLOGFILE format
  • tlsSocket The TLS socket instance
Emitted when key material is generated or received by a connection.
import https from 'node:https';
import fs from 'node:fs';

https.globalAgent.on('keylog', (line, tlsSocket) => {
  fs.appendFileSync('/tmp/ssl-keys.log', line, { mode: 0o600 });
});

HTTPS Methods

https.get(url[, options][, callback])

  • url
  • options
  • callback
  • Returns:
Like http.get() but for HTTPS.
import { get } from 'node:https';

get('https://encrypted.google.com/', (res) => {
  console.log('statusCode:', res.statusCode);
  console.log('headers:', res.headers);
  
  res.on('data', (d) => {
    process.stdout.write(d);
  });
}).on('error', (e) => {
  console.error(e);
});

https.request(url[, options][, callback])

  • url
  • options
    • protocol Default: 'https:'
    • port Default: 443
    • All options from http.request()
    • All options from tls.connect()
  • callback
  • Returns:
Makes a request to a secure web server.
import { request } from 'node:https';

const options = {
  hostname: 'encrypted.google.com',
  port: 443,
  path: '/',
  method: 'GET'
};

const req = request(options, (res) => {
  console.log('statusCode:', res.statusCode);
  console.log('headers:', res.headers);
  
  res.on('data', (d) => {
    process.stdout.write(d);
  });
});

req.on('error', (e) => {
  console.error(e);
});

req.end();

TLS/SSL Options

Certificate Options

const options = {
  key: fs.readFileSync('private-key.pem'),
  cert: fs.readFileSync('certificate.pem'),
  ca: fs.readFileSync('ca-cert.pem'),
  
  // Optional
  passphrase: 'secret',
  ciphers: 'HIGH:!aNULL:!MD5',
  honorCipherOrder: true,
  rejectUnauthorized: true
};

Client Certificate Authentication

const options = {
  hostname: 'example.com',
  port: 443,
  path: '/',
  method: 'GET',
  key: fs.readFileSync('client-key.pem'),
  cert: fs.readFileSync('client-cert.pem'),
  ca: fs.readFileSync('ca-cert.pem')
};

https.request(options, (res) => {
  // Handle response
}).end();

Certificate Validation

Custom Certificate Validation

import { checkServerIdentity } from 'node:tls';
import { Agent, request } from 'node:https';
import { createHash } from 'node:crypto';

function sha256(s) {
  return createHash('sha256').update(s).digest('base64');
}

const options = {
  hostname: 'github.com',
  port: 443,
  path: '/',
  method: 'GET',
  checkServerIdentity: function(host, cert) {
    const err = checkServerIdentity(host, cert);
    if (err) {
      return err;
    }
    
    // Pin the public key
    const pubkey256 = 'expected-public-key-hash';
    if (sha256(cert.pubkey) !== pubkey256) {
      const msg = 'Certificate verification error: ' +
        `The public key of '${cert.subject.CN}' ` +
        'does not match our pinned fingerprint';
      return new Error(msg);
    }
  }
};

options.agent = new Agent(options);
const req = request(options, (res) => {
  console.log('statusCode:', res.statusCode);
});

SNI (Server Name Indication)

Server-side SNI

import { createServer } from 'node:https';
import { readFileSync } from 'node:fs';

const options = {
  SNICallback: (servername, cb) => {
    if (servername === 'example.com') {
      cb(null, tls.createSecureContext({
        key: readFileSync('example-key.pem'),
        cert: readFileSync('example-cert.pem')
      }));
    } else {
      cb(new Error('Unknown servername'));
    }
  }
};

const server = createServer(options, (req, res) => {
  res.end('Hello');
});

Client-side SNI

const options = {
  hostname: 'example.com',
  servername: 'example.com', // SNI value
  port: 443
};

https.request(options, (res) => {
  // Handle response
}).end();

Global Agent

https.globalAgent

Global instance of https.Agent for all HTTPS client requests.
import https from 'node:https';

// Configure global agent
https.globalAgent.maxSockets = 50;
https.globalAgent.keepAlive = true;

// Use global agent
https.get('https://example.com', (res) => {
  // Uses global agent
});

Example: REST API Client

import { request } from 'node:https';

function apiRequest(path, method, data = null) {
  return new Promise((resolve, reject) => {
    const options = {
      hostname: 'api.example.com',
      port: 443,
      path: path,
      method: method,
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer token123'
      }
    };
    
    const req = request(options, (res) => {
      let body = '';
      
      res.on('data', (chunk) => {
        body += chunk;
      });
      
      res.on('end', () => {
        if (res.statusCode >= 200 && res.statusCode < 300) {
          resolve(JSON.parse(body));
        } else {
          reject(new Error(`HTTP ${res.statusCode}`));
        }
      });
    });
    
    req.on('error', reject);
    
    if (data) {
      req.write(JSON.stringify(data));
    }
    
    req.end();
  });
}

// Usage
await apiRequest('/users', 'GET');
await apiRequest('/users', 'POST', { name: 'John' });

Example: HTTPS Proxy

import { createServer } from 'node:https';
import { request as httpsRequest } from 'node:https';
import { readFileSync } from 'node:fs';

const server = createServer({
  key: readFileSync('proxy-key.pem'),
  cert: readFileSync('proxy-cert.pem')
}, (req, res) => {
  const options = {
    hostname: 'target-server.com',
    port: 443,
    path: req.url,
    method: req.method,
    headers: req.headers
  };
  
  const proxyReq = httpsRequest(options, (proxyRes) => {
    res.writeHead(proxyRes.statusCode, proxyRes.headers);
    proxyRes.pipe(res);
  });
  
  req.pipe(proxyReq);
  
  proxyReq.on('error', (err) => {
    res.writeHead(500);
    res.end('Proxy Error');
  });
});

server.listen(8443);

Generating Self-Signed Certificates

For Development

# Generate private key and certificate
openssl req -x509 -newkey rsa:2048 -nodes -sha256 \
  -subj '/CN=localhost' \
  -keyout private-key.pem \
  -out certificate.pem

# Generate PFX certificate
openssl pkcs12 -certpbe AES-256-CBC -export \
  -out certificate.pfx \
  -inkey private-key.pem \
  -in certificate.pem \
  -passout pass:sample