bugl
bugl
HomeLearnPatternsPathsSearch
HomeLearnPatternsPathsSearch

Loading lesson path

Learn/Node.js/Core Modules
Node.js•Core Modules

Node.js HTTPS Module

Flash cards

Review the key moves

1/4
Core idea

What is the main idea behind Node.js HTTPS Module?

Lesson checks

Practice each idea before moving on

Short Mimo-style checks built from this lesson's code, terms, and sequence.

1Quick choice

Which statement best captures the main point of this lesson?

2Fill blank

Complete the missing token from the example code.

// ___ require()
3Order

Put the learning moves in the order that makes the concept easiest to apply.

SSL/TLS Certificates
Importing the Module
Introduction to the HTTPS Module

Introduction to the HTTPS Module

The HTTPS module is a core Node.js module that provides an implementation of the HTTPS protocol, which is essentially HTTP over TLS/SSL.

It's a secure version of the HTTP module, providing encrypted communication between clients and servers.

Why Use HTTPS?

HTTPS is crucial for modern web applications because it:

  • Encrypts Data : Protects sensitive information like passwords, credit card numbers, and personal data from eavesdropping
  • Authenticates Servers : Verifies that clients are communicating with the intended server
  • Ensures Data Integrity : Prevents data from being modified or corrupted during transfer
  • Builds Trust : Visual indicators (like the padlock icon) increase user confidence
  • Improves SEO : Search engines prioritize HTTPS websites in search results
  • Enables Modern Features : Many web APIs (like Geolocation, Service Workers) require HTTPS

How HTTPS Works

  • Client initiates a secure connection to the server
  • Encrypted session is established using asymmetric encryption
  • Symmetric encryption is used for the actual data transfer

Note

Modern HTTPS uses TLS (Transport Layer Security), which is the successor to SSL (Secure Sockets Layer). The terms are often used interchangeably, but SSL is now considered deprecated.

Important: As of 2023, all major browsers require HTTPS for new web features and APIs. Many browsers also mark non-HTTPS sites as "Not Secure."

Importing the Module

To use the HTTPS module in your Node.js application, you can import it using CommonJS or ES modules syntax:

// Using require()
const https = require('https');
// Using import (requires "type": "module" in package.json)
import https from 'https';

HTTPS vs HTTP API

The HTTPS module has the same interface as the HTTP module, with the main difference being that it creates connections using TLS/SSL.

This means all the methods and events available in the HTTP module are also available in the HTTPS module.

Note

The main difference in usage is that HTTPS requires SSL/TLS certificates, while HTTP does not.

SSL/TLS Certificates

HTTPS requires SSL/TLS certificates to establish secure connections. There are several types of certificates:

Types of Certificates

  • Self-Signed Certificates : For development and testing (not trusted by browsers)
  • Domain Validated (DV) : Basic validation, just verifies domain ownership
  • Organization Validated (OV) : Validates organization details
  • Extended Validation (EV) : Highest level of validation, shows company name in browser
  • Wildcard Certificates : Secures all subdomains of a domain

Generating Self-Signed Certificates

For development, you can create self-signed certificates using OpenSSL:

# Generate a private key (RSA 2048-bit)
openssl genrsa -out key.pem 2048
openssl req -new -x509 -key key.pem -out cert.pem -days 365 -nodes

Note

If there is no key.pem file present, you need to use the " -newkey " option instead of " -key " in the command above.

# Create a config file (san.cnf)
cat > san.cnf << EOF
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = US
ST = State
L = City
O = Organization
OU = Organizational Unit
CN = localhost
[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
IP.1 = 127.0.0.1
EOF
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout key.pem -out cert.pem -config san.cnf -extensions 'v3_req'

Only use them for development and testing purposes.

Obtaining Trusted Certificates

  • Paid CAs : DigiCert, GlobalSign, Comodo, etc.
  • Free CAs : Let's Encrypt, ZeroSSL, Cloudflare

Creating an HTTPS Server

Once you have your SSL/TLS certificates ready, you can create an HTTPS server in Node.js.

The HTTPS server API is very similar to the HTTP server API, with the main difference being the SSL/TLS configuration.

Basic HTTPS Server Example

Here's how to create a basic HTTPS server:

const https = require('https');
const fs = require('fs');
const path = require('path');
const sslOptions = {
 key: fs.readFileSync(path.join(__dirname, 'key.pem')),
 cert: fs.readFileSync(path.join(__dirname, 'cert.pem')),
 // Enable all security features
 minVersion: 'TLSv1.2',
 // Recommended security settings
 secureOptions: require('constants').SSL_OP_NO_SSLv3 |
 require('constants').SSL_OP_NO_TLSv1 |
 require('constants').SSL_OP_NO_TLSv1_1
};
// Create the HTTPS server
const server = https.createServer(sslOptions, (req, res) => {
 // Security headers
 res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
 res.setHeader('X-Content-Type-Options', 'nosniff');
 res.setHeader('X-Frame-Options', 'SAMEORIGIN');
 res.setHeader('X-XSS-Protection', '1; mode=block');
 res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
 // Handle different routes
 if (req.url === '/') {
 res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
 res.end('<h1>Welcome to the Secure Server</h1><p>Your connection is encrypted!</p>');
 } else if (req.url === '/api/status') {
 res.writeHead(200, { 'Content-Type': 'application/json' });
 res.end(JSON.stringify({ status: 'ok', time: new Date().toISOString() }));
} else {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('404 Not Found');
}
});
// Handle server errors server.on('error', (error) => {
console.error('Server error:', error);
});
// Start the server on port 3000 (HTTPS default is 443 but requires root)
const PORT = process.env.PORT || 3000;
server.listen(PORT, '0.0.0.0', () => {
 console.log(`Server running at https://localhost:${PORT}`);
 console.log('Press Ctrl+C to stop the server');
});

Note

On Unix-like systems, ports below 1024 require root privileges. For production, it's common to run Node.js on a high port (like 3000, 8080) and use a reverse proxy like Nginx or Apache to handle SSL termination.

Advanced Server Configuration

For production environments, you might need more advanced SSL/TLS configuration:

const https = require('https');
const fs = require('fs');
const path = require('path');
const tls = require('tls');
// Path to your SSL/TLS files
const sslOptions = {
 key: fs.readFileSync(path.join(__dirname, 'privkey.pem')),
 cert: fs.readFileSync(path.join(__dirname, 'cert.pem')),
 ca: [
 fs.readFileSync(path.join(__dirname, 'chain.pem'))
 ],
 // Recommended security settings
 minVersion: 'TLSv1.2',
 maxVersion: 'TLSv1.3',
 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-CHACHA20-POLY1305',
 'ECDHE-RSA-CHACHA20-POLY1305',
 'ECDHE-ECDSA-AES128-GCM-SHA256',
 'ECDHE-RSA-AES128-GCM-SHA256'
 ].join(':'),
 honorCipherOrder: true,
 // Enable OCSP Stapling
 requestCert: true,
 rejectUnauthorized: true,
 // Enable session resumption
 sessionTimeout: 300, // 5 minutes
 sessionIdContext: 'my-secure-app',
 // Enable HSTS preload
 hsts: {
 maxAge: 63072000, // 2 years in seconds
 includeSubDomains: true,
 preload: true
 },
 // Enable secure renegotiation
 secureOptions: require('constants').SSL_OP_LEGACY_SERVER_CONNECT |
 require('constants').SSL_OP_NO_SSLv3 |
 require('constants').SSL_OP_NO_TLSv1 |
 require('constants').SSL_OP_NO_TLSv1_1 |
 require('constants').SSL_OP_CIPHER_SERVER_PREFERENCE
};
// Create the HTTPS server
const server = https.createServer(sslOptions, (req, res) => {
 // Security headers
 const securityHeaders = {
 'Strict-Transport-Security': 'max-age=63072000; includeSubDomains; preload',
 'X-Content-Type-Options': 'nosniff',
 'X-Frame-Options': 'DENY',
 'X-XSS-Protection': '1; mode=block',
 'Content-Security-Policy': "default-src 'self'",
 'Referrer-Policy': 'strict-origin-when-cross-origin',
 'Permissions-Policy': 'geolocation=(), microphone=(), camera=()',
 };
 Object.entries(securityHeaders).forEach(([key, value]) => {
 res.setHeader(key, value);
 });
 // Handle requests
 if (req.url === '/') {
 res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
 res.end('<h1>Secure Node.js Server</h1><p>Your connection is secure!</p>');
 } else {
 res.writeHead(404, { 'Content-Type': 'text/plain' });
 res.end('404 Not Found');
}
});
// Handle server errors
server.on('error', (error) => {
 console.error('Server error:', error);
});
// Handle uncaught exceptions
process.on('uncaughtException', (error) => {
 console.error('Uncaught exception:', error);
 // Perform graceful shutdown
 server.close(() => process.exit(1));
});
// Handle unhandled promise rejections
process.on('unhandledRejection', (reason, promise) => {
 console.error('Unhandled Rejection at:', promise, 'reason:', reason);
});
// Handle graceful shutdown
const gracefulShutdown = () => {
 console.log('Shutting down gracefully...');
 server.close(() => {
 console.log('Server closed');
 process.exit(0);
 });
 // Force close server after 10 seconds
 setTimeout(() => {
 console.error('Forcing shutdown...');
 process.exit(1);
 }, 10000);
};
// Listen for shutdown signals
process.on('SIGTERM', gracefulShutdown);
process.on('SIGINT', gracefulShutdown);
// Start the server
const PORT = process.env.PORT || 3000;
const HOST = process.env.HOST || '0.0.0.0';
server.listen(PORT, HOST, () => {
 const { address, port } = server.address();
 console.log(`Server running at https://${address}:${port}`);
 // Output server information
 console.log('Node.js version:', process.version);
 console.log('Environment:', process.env.NODE_ENV || 'development');
 console.log('PID:', process.pid);
});

Security Best Practices

  • Always use the latest stable version of Node.js for security updates
  • Keep your dependencies up to date using npm audit and npm update
  • Use environment variables for sensitive configuration (never commit secrets to version control)
  • Implement rate limiting to prevent abuse
  • Regularly rotate your SSL/TLS certificates
  • Monitor your server for security vulnerabilities
  • Use a reverse proxy like Nginx or Apache in production for additional security features

Testing Your HTTPS Server

To test your HTTPS server, you can use curl or a web browser: curl -k https://localhost:3000 curl --cacert /path/to/ca.pem https://yourdomain.com

  • Open your web browser and navigate to https://localhost:3000

Making HTTPS Requests

The HTTPS module allows you to make secure HTTP requests to other servers.

This is essential for interacting with secure APIs and web services.

Basic GET Request

Here's how to make a simple GET request to an HTTPS endpoint:

const https = require('https');
const { URL } = require('url');
// Parse the target URL
const apiUrl = new URL('https://api.example.com/data');
// Request options
const options = {
 hostname: apiUrl.hostname,
 port: 443,
 path: apiUrl.pathname + apiUrl.search,
 method: 'GET',
 headers: {
 'User-Agent': 'MySecureApp/1.0',
 'Accept': 'application/json',
 'Cache-Control': 'no-cache'
 },
 // Security settings
 // Timeout in milliseconds
 timeout: 10000, // 10 seconds
};
console.log(`Making request to: https://${options.hostname}${options.path}`);
// Make the HTTPS request
const req = https.request(options, (res) => {
 const { statusCode, statusMessage, headers } = res;
 const contentType = headers['content-type'] || '';
 console.log(`Status: ${statusCode} ${statusMessage}`);
 console.log('Headers:', headers);
 // Handle redirects
 if (statusCode >= 300 && statusCode < 400 && headers.location) {
 console.log(`Redirecting to: ${headers.location}`);
 // In a real app, you'd handle the redirect
 res.resume(); // Discard the response body
 return;
 }
 // Check for successful response
 let error;
 if (statusCode !== 200) {
 error = new Error(`Request Failed.\nStatus Code: ${statusCode}`);
 } else if (!/^application\/json/.test(contentType)) {
 error = new Error(`Invalid content-type.\nExpected application/json but received ${contentType}`);
}
if (error) {
 console.error(error.message);
 res.resume(); // Consume response data to free up memory
 return;
}
// Process the response
let rawData = '';
res.setEncoding('utf8');
// Collect chunks of data
res.on('data', (chunk) => {
 rawData += chunk;
});
// Process the complete response
res.on('end', () => {
 try {
 const parsedData = JSON.parse(rawData);
 console.log('Response data:', parsedData);
 } catch (e) {
 console.error('Error parsing JSON:', e.message);
}
});
});
// Handle request errors req.on('error', (e) => {
console.error(`Request error: ${e.message}`);
if (e.code === 'ECONNRESET') {
 console.error('Connection was reset by the server');
} else if (e.code === 'ETIMEDOUT') {
console.error('Request timed out');
}
});
// Set a timeout for the entire request (including DNS lookup, TCP connect, etc.) req.setTimeout(15000, () => {
req.destroy(new Error('Request timeout after 15 seconds'));
});
// Handle socket errors (network-level errors) req.on('socket', (socket) => {
socket.on('error', (error) => {
 console.error('Socket error:', error.message);
 req.destroy(error);
});
// Set a timeout for the socket connection
socket.setTimeout(5000, () => {
 req.destroy(new Error('Socket timeout after 5 seconds'));
});
});
// End the request (required to send it) req.end();

Using https.get() for Simple Requests

For simple GET requests, you can use the more concise https.get() method. This is a convenience method that automatically sets the HTTP method to GET and calls req.end() for you.

const https = require('https');
const { URL } = require('url');
// Parse the URL
const url = new URL('https://jsonplaceholder.typicode.com/posts/1');
// Request options
const options = {
 hostname: url.hostname,
 path: url.pathname,
 method: 'GET',
 headers: {
 'Accept': 'application/json',
 'User-Agent': 'MySecureApp/1.0'
 }
};
console.log(`Fetching data from: ${url}`);
// Make the GET request
const req = https.get(options, (res) => {
 const { statusCode } = res;
 const contentType = res.headers['content-type'];
 if (statusCode !== 200) {
 console.error(`Request failed with status code: ${statusCode}`);
 res.resume(); // Consume response data to free up memory
 return;
 }
 if (!/^application\/json/.test(contentType)) {
 console.error(`Expected JSON but got ${contentType}`);
 res.resume();
 return;
 }
 let rawData = '';
 res.setEncoding('utf8');
 // Collect data chunks
 res.on('data', (chunk) => {
 rawData += chunk;
 });
 // Process complete response
 res.on('end', () => {
 try {
 const parsedData = JSON.parse(rawData);
 console.log('Received data:', parsedData);
 } catch (e) {
 console.error('Error parsing JSON:', e.message);
 }
});
});
// Handle errors
req.on('error', (e) => {
 console.error(`Error: ${e.message}`);
});
// Set a timeout
req.setTimeout(10000, () => {
 console.error('Request timeout');
 req.destroy();
});

Making POST Requests

To send data to a server, you can use a POST request.

Here's how to make a secure POST request with JSON data:

const https = require('https');
const { URL } = require('url');
// Request data
const postData = JSON.stringify({
 title: 'foo',
 body: 'bar',
 userId: 1
});
// Parse the URL
const url = new URL('https://jsonplaceholder.typicode.com/posts');
// Request options
const options = {
 hostname: url.hostname,
 port: 443,
 path: url.pathname,
 method: 'POST',
 headers: {
 'Content-Type': 'application/json',
 'Content-Length': Buffer.byteLength(postData),
 'User-Agent': 'MySecureApp/1.0',
 'Accept': 'application/json'
 },
 timeout: 10000 // 10 seconds
};
console.log('Sending POST request to:', url.toString());
// Create the request
const req = https.request(options, (res) => {
 console.log(`Status Code: ${res.statusCode}`);
 console.log('Headers:', res.headers);
 let responseData = '';
 res.setEncoding('utf8');
 // Collect response data
 res.on('data', (chunk) => {
 responseData += chunk;
 });
 // Process complete response
 res.on('end', () => {
 try {
 const parsedData = JSON.parse(responseData);
 console.log('Response:', parsedData);
 } catch (e) {
 console.error('Error parsing response:', e.message);
 }
});
});
// Handle errors
req.on('error', (e) => {
 console.error(`Request error: ${e.message}`);
});
// Set a timeout
req.setTimeout(15000, () => {
 req.destroy(new Error('Request timeout after 15 seconds'));
});
// Write data to request body
req.write(postData);
// End the request
req.end();

Using Promises with HTTPS Requests

To make HTTPS requests more manageable, you can wrap them in a Promise:

const https = require('https');
const { URL } = require('url');
/**
* Makes an HTTPS request and returns a Promise
* @param {Object} options - Request options
* @param {string|Buffer} [data] - Request body (for POST, PUT, etc.)
* @returns {Promise<Object>} - Resolves with response data
*/
function httpsRequest(options, data = null) {
 return new Promise((resolve, reject) => {
 const req = https.request(options, (res) => {
 let responseData = '';
 // Collect response data
 res.on('data', (chunk) => {
 responseData += chunk;
 });
 // Process complete response
 res.on('end', () => {
 try {
 const contentType = res.headers['content-type'] || '';
 const isJSON = /^application\/json/.test(contentType);
 const response = {
 statusCode: res.statusCode,
 headers: res.headers,
 data: isJSON ? JSON.parse(responseData) : responseData
 };
 if (res.statusCode >= 200 && res.statusCode < 300) {
 resolve(response);
 } else {
 const error = new Error(`Request failed with status code ${res.statusCode}`);
 error.response = response;
 reject(error);
 }
 } catch (e) {
 e.response = { data: responseData };
 reject(e);
 }
 });
});
// Handle errors
req.on('error', (e) => {
 reject(e);
});
// Set timeout
req.setTimeout(options.timeout || 10000, () => {
 req.destroy(new Error('Request timeout'));
});
// Write data if provided
if (data) {
 req.write(data);
}
// End the request
req.end();
});
}
// Example usage
async function fetchData() {
 try {
 const url = new URL('https://jsonplaceholder.typicode.com/posts/1');
 const options = {
 hostname: url.hostname,
 path: url.pathname,
 method: 'GET',
 headers: {
 'Accept': 'application/json'
 },
 timeout: 5000
 };
 const response = await httpsRequest(options);
 console.log('Response:', response.data);
 } catch (error) {
 console.error('Error:', error.message);
 if (error.response) {
 console.error('Response data:', error.response.data);
 }
}
}
// Run the example
fetchData();

Best Practices for HTTPS Requests

  • Always validate and sanitize input data before sending it in a request
  • Use environment variables for sensitive information like API keys
  • Implement proper error handling and timeouts
  • Set appropriate headers (Content-Type, Accept, User-Agent)
  • Handle redirects appropriately (3xx status codes)
  • Implement retry logic for transient failures
  • Consider using a library like axios or node-fetch for more complex scenarios

HTTPS Server with Express.js

While you can use the core HTTPS module directly, most Node.js applications use a web framework like Express.js to handle HTTP/HTTPS requests.

Here's how to set up an Express application with HTTPS support.

Basic Express.js HTTPS Server

const express = require('express');
const https = require('https');
const fs = require('fs');
const path = require('path');
const helmet = require('helmet'); // Security middleware
// Create Express app
const app = express();
// Security middleware
app.use(helmet());
// Parse JSON and URL-encoded bodies
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Serve static files from 'public' directory
app.use(express.static(path.join(__dirname, 'public'), {
 dotfiles: 'ignore',
 etag: true,
 extensions: ['html', 'htm'],
 index: 'index.html',
 maxAge: '1d',
 redirect: true
}));
// Routes
app.get('/', (req, res) => {
 res.send('<h1>Welcome to Secure Express Server</h1>');
});
app.get('/api/status', (req, res) => {
 res.json({
 status: 'operational',
 timestamp: new Date().toISOString(),
 environment: process.env.NODE_ENV || 'development',
 nodeVersion: process.version
 });
});
// Error handling middleware
app.use((err, req, res, next) => {
 console.error(err.stack);
 res.status(500).json({ error: 'Something went wrong!' });
});
// 404 handler
app.use((req, res) => {
 res.status(404).json({ error: 'Not Found' });
});
// SSL/TLS options
const sslOptions = {
 key: fs.readFileSync(path.join(__dirname, 'key.pem')),
 cert: fs.readFileSync(path.join(__dirname, 'cert.pem')),
 // Enable HTTP/2 if available
 allowHTTP1: true,
 // Recommended security options
 minVersion: 'TLSv1.2',
 ciphers: [
 'TLS_AES_256_GCM_SHA384',
 'TLS_CHACHA20_POLY1305_SHA256',
 'TLS_AES_128_GCM_SHA256',
 'ECDHE-RSA-AES128-GCM-SHA256',
 '!DSS',
 '!aNULL',
 '!eNULL',
 '!EXPORT',
 '!DES',
 '!RC4',
 '!3DES',
 '!MD5',
 '!PSK'
 ].join(':'),
 honorCipherOrder: true
};
// Create HTTPS server
const PORT = process.env.PORT || 3000;
const server = https.createServer(sslOptions, app);
// Handle unhandled promise rejections
process.on('unhandledRejection', (reason, promise) => {
 console.error('Unhandled Rejection at:', promise, 'reason:', reason);
});
// Handle uncaught exceptions
process.on('uncaughtException', (error) => {
 console.error('Uncaught Exception:', error);
 // Perform cleanup and exit if needed
 process.exit(1);
});
// Graceful shutdown
const gracefulShutdown = (signal) => {
 console.log(`\nReceived ${signal}. Shutting down gracefully...`);
 server.close(() => {
 console.log('HTTP server closed.');
 // Close database connections, etc.
 process.exit(0);
 });
 // Force close server after 10 seconds
 setTimeout(() => {
 console.error('Forcing shutdown...');
 process.exit(1);
 }, 10000);
};
// Listen for shutdown signals
process.on('SIGTERM', gracefulShutdown);
process.on('SIGINT', gracefulShutdown);
// Start the server
const HOST = process.env.HOST || '0.0.0.0';
server.listen(PORT, HOST, () => {
 console.log(`Express server running at https://${HOST}:${PORT}`);
 console.log('Environment:', process.env.NODE_ENV || 'development');
 console.log('Press Ctrl+C to stop the server');
});

Using Environment Variables

It's a best practice to use environment variables for configuration. Create a .env file:

NODE_ENV=development
PORT=3000
HOST=0.0.0.0
SSL_KEY_PATH=./key.pem
SSL_CERT_PATH=./cert.pem

Then use the dotenv package to load them:

require('dotenv').config();
// Access environment variables
const PORT = process.env.PORT || 3000;
const HOST = process.env.HOST || '0.0.0.0';
const sslOptions = {
 key: fs.readFileSync(process.env.SSL_KEY_PATH),
 cert: fs.readFileSync(process.env.SSL_CERT_PATH)
 // ... other options
};

Production Deployment

In production, it's recommended to use a reverse proxy like Nginx or Apache in front of your Node.js application. This provides:

  • SSL/TLS termination
  • Load balancing
  • Static file serving
  • Request caching
  • Rate limiting
  • Better security headers
server {
 listen 443 ssl http2;
 server_name yourdomain.com;
 # SSL configuration
 ssl_certificate /path/to/your/cert.pem;
 ssl_certificate_key /path/to/your/key.pem;
 # Security headers
 add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
 add_header X-Content-Type-Options "nosniff" always;
 add_header X-Frame-Options "SAMEORIGIN" always;
 add_header X-XSS-Protection "1; mode=block" always;
 # Proxy to Node.js app
 location / {
 proxy_pass http://localhost:3000;
 proxy_http_version 1.1;
 proxy_set_header Upgrade $http_upgrade;
 proxy_set_header Connection 'upgrade';
 proxy_set_header Host $host;
 proxy_cache_bypass $http_upgrade;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 proxy_set_header X-Forwarded-Proto $scheme;
 }
 # Serve static files directly
 location /static/ {
 root /path/to/your/app/public;
 expires 30d;
 access_log off;
 }
}
# Redirect HTTP to HTTPS
server {
 listen 80;
 server_name yourdomain.com;
 return 301 https://$host$request_uri;
}
# Redirect HTTP to HTTPS
server {
 listen 80;
 server_name yourdomain.com;
 return 301 https://$host$request_uri;
}

Best Practices for Express.js with HTTPS:

  • Always use helmet middleware for security headers
  • Set secure session options (if using sessions)
  • Use environment variables for configuration
  • Implement proper error handling and logging
  • Use a reverse proxy in production
  • Keep your dependencies up to date
  • Use HTTP/2 for better performance
  • Implement rate limiting to prevent abuse
  • Use CORS middleware if your API is accessed from different domains

HTTP/2 with Node.js

HTTP/2 is a major revision of the HTTP protocol that provides significant performance improvements over HTTP/1.1. When combined with HTTPS, it offers both security and performance benefits for modern web applications.

Benefits of HTTP/2

Key Features of HTTP/2

  • Multiplexing : Multiple requests/responses can be sent in parallel over a single connection, eliminating head-of-line blocking
  • Header Compression : Reduces overhead by compressing HTTP headers (HPACK algorithm)
  • Server Push : Server can proactively send resources to the client before they're requested
  • Binary Protocol : More efficient to parse than HTTP/1.1's text-based format
  • Stream Prioritization : More important resources can be loaded first
  • Connection Multiplexing : Multiple streams can share a single TCP connection

Previous

Node.js HTTP Module

Next

Node.js File System Module