版本概述

Node.js 12.x
已弃用
Node.js 12 是较旧的 LTS 版本,支持基本的 HTTPS 功能,但缺少一些现代 TLS 特性。已于 2022 年停止维护。
⚠️ 注意: Node.js 12 已停止维护,存在安全风险,强烈建议升级到 Node.js 18 或 20。
Node.js 14.x
稳定版本
Node.js 14 是稳定的 LTS 版本,支持 TLS 1.3,提供了更好的 SSL/TLS 支持。配置方式与 Node.js 12 类似。
Node.js 16.x
稳定版本
Node.js 16 是稳定的 LTS 版本,默认启用 TLS 1.3,提供了更好的性能和安全性。
Node.js 18.x
推荐版本
Node.js 18 是当前推荐的 LTS 版本,支持所有现代 SSL/TLS 特性,包括完整的 TLS 1.3 支持。
✅ 推荐: Node.js 18 是目前最稳定和推荐的版本,支持所有现代 SSL/TLS 特性。
Node.js 20.x
当前版本
Node.js 20 是当前的 LTS 版本,提供最新的安全特性和性能优化,完全支持 TLS 1.3。
Node.js 版本 状态 TLS 1.2 TLS 1.3 OpenSSL 版本 推荐使用
Node.js 12.x 已弃用 ⚠️ 需配置 1.1.1
Node.js 14.x 稳定 1.1.1
Node.js 16.x 稳定 1.1.1
Node.js 18.x LTS 3.0.x ✅ 推荐
Node.js 20.x LTS 3.0.x

证书格式处理

Node.js 可以直接使用 .crt 和 .key 文件,也可以使用合并后的证书链文件。

证书文件准备

步骤 1:合并证书链(如果需要)

# # 合并主证书和中间证书cat your_domain.crt intermediate_ca.crt > fullchain.crt # # 确保私钥文件存在# your_domain.key

文件权限设置

# # 设置私钥文件权限(仅所有者可读)chmod 600 your_domain.key # # 设置证书文件权限chmod 644 fullchain.crt
💡 提示: Node.js 支持 PEM 格式的证书和私钥文件,这是最常见的格式。如果您的证书是其他格式,需要先转换。

HTTPS 服务器配置

基本 HTTPS 服务器(原生 Node.js)

const https = require('https'); const fs = require('fs'); const options = { key: fs.readFileSync('/path/to/your_domain.key'), cert: fs.readFileSync('/path/to/fullchain.crt') }; const server = https.createServer(options, (req, res) => { res.writeHead(200); res.end('Hello HTTPS!'); }); server.listen(443, () => { console.log('HTTPS server running on port 443'); });

包含中间证书的配置

const https = require('https'); const fs = require('fs'); const options = { key: fs.readFileSync('/path/to/your_domain.key'), cert: fs.readFileSync('/path/to/your_domain.crt'), ca: [ fs.readFileSync('/path/to/intermediate_ca.crt'), fs.readFileSync('/path/to/root_ca.crt') ] }; const server = https.createServer(options, (req, res) => { res.writeHead(200); res.end('Hello HTTPS!'); }); server.listen(443);
📝 配置说明:
  • key:key:私钥文件路径
  • cert:cert:证书文件路径(可以是合并后的 fullchain.crt)
  • ca:ca:中间证书数组(可选,如果 cert 已包含完整链则不需要)

Express.js SSL 配置

Express.js 基本配置

const express = require('express'); const https = require('https'); const fs = require('fs'); const app = express(); app.get('/', (req, res) => { res.send('Hello HTTPS!'); }); const options = { key: fs.readFileSync('/path/to/your_domain.key'), cert: fs.readFileSync('/path/to/fullchain.crt') }; https.createServer(options, app).listen(443, () => { console.log('Express HTTPS server running on port 443'); });

Express.js 高级配置

const express = require('express'); const http = require('http'); const https = require('https'); const fs = require('fs'); const app = express(); app.get('/', (req, res) => { res.send('Hello!'); }); // HTTP 服务器(重定向到 HTTPS) http.createServer((req, res) => { res.writeHead(301, { "Location": "https://" + req.headers['host'] + req.url }); res.end(); }).listen(80); // HTTPS 服务器 const options = { key: fs.readFileSync('/path/to/your_domain.key'), cert: fs.readFileSync('/path/to/fullchain.crt') }; https.createServer(options, app).listen(443, () => { console.log('HTTPS server running on port 443'); });

版本配置差异

Node.js 12.x 配置

const https = require('https'); const fs = require('fs'); const options = { key: fs.readFileSync('/path/to/your_domain.key'), cert: fs.readFileSync('/path/to/fullchain.crt'), secureProtocol: 'TLSv1_2_method', // 或 TLSv1_3_method ciphers: 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384' }; const server = https.createServer(options, (req, res) => { res.writeHead(200); res.end('Hello HTTPS!'); }); server.listen(443);

Node.js 14.x / 16.x 配置

const https = require('https'); const fs = require('fs'); const options = { key: fs.readFileSync('/path/to/your_domain.key'), cert: fs.readFileSync('/path/to/fullchain.crt'), minVersion: 'TLSv1.2', maxVersion: 'TLSv1.3', ciphers: 'TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384' }; const server = https.createServer(options, (req, res) => { res.writeHead(200); res.end('Hello HTTPS!'); }); server.listen(443);

Node.js 18.x / 20.x 配置(推荐)

const https = require('https'); const fs = require('fs'); const options = { key: fs.readFileSync('/path/to/your_domain.key'), cert: fs.readFileSync('/path/to/fullchain.crt'), minVersion: 'TLSv1.2', maxVersion: 'TLSv1.3', ciphers: [ 'TLS_AES_256_GCM_SHA384', 'TLS_AES_128_GCM_SHA256', 'ECDHE-RSA-AES128-GCM-SHA256', 'ECDHE-RSA-AES256-GCM-SHA384', 'ECDHE-RSA-CHACHA20-POLY1305' ].join(':'), honorCipherOrder: true }; const server = https.createServer(options, (req, res) => { res.writeHead(200); res.end('Hello HTTPS!'); }); server.listen(443);
⚠️ 重要差异:
  • Node.js 12 需要明确指定 TLS 协议版本
  • Node.js 14+ 默认支持 TLS 1.3,但建议明确配置
  • Node.js 18+ 使用 OpenSSL 3.0,加密套件名称可能不同
  • 新版本推荐使用 minVersion 和 maxVersion 而不是 secureProtocol

TLS 协议配置

启用 TLS 1.2 和 TLS 1.3

const options = { key: fs.readFileSync('/path/to/your_domain.key'), cert: fs.readFileSync('/path/to/fullchain.crt'), minVersion: 'TLSv1.2', maxVersion: 'TLSv1.3' };

禁用不安全的协议

const options = { key: fs.readFileSync('/path/to/your_domain.key'), cert: fs.readFileSync('/path/to/fullchain.crt'), minVersion: 'TLSv1.2', // // 禁用 TLS 1.0 和 1.1 rejectUnauthorized: true // // 拒绝无效证书};

配置加密套件(Node.js 18+)

const options = { key: fs.readFileSync('/path/to/your_domain.key'), cert: fs.readFileSync('/path/to/fullchain.crt'), minVersion: 'TLSv1.2', maxVersion: 'TLSv1.3', ciphers: [ 'TLS_AES_256_GCM_SHA384', // // TLS 1.3 'TLS_AES_128_GCM_SHA256', // // TLS 1.3 'ECDHE-RSA-AES128-GCM-SHA256', // // TLS 1.2 'ECDHE-RSA-AES256-GCM-SHA384', // // TLS 1.2 'ECDHE-RSA-CHACHA20-POLY1305' // // TLS 1.2 ].join(':'), honorCipherOrder: true };
⚠️ 安全建议:
  • 禁用 SSLv2、SSLv3、TLSv1.0、TLSv1.1
  • 仅启用 TLS 1.2 和 TLS 1.3
  • 使用强加密套件
  • 定期更新 Node.js 版本

HTTP 到 HTTPS 重定向

使用中间件重定向(Express)

const express = require('express'); const app = express(); // // 强制 HTTPS 中间件app.use((req, res, next) => { if (req.header('x-forwarded-proto') !== 'https') { res.redirect(`https://${req.header('host')}${req.url}`); } else { next(); } }); app.get('/', (req, res) => { res.send('Hello HTTPS!'); }); // // 检查协议(适用于反向代理)app.listen(3000);

方法二:使用 Nginx 反向代理

const express = require('express'); const enforce = require('express-enforces-ssl'); const app = express(); // 强制 HTTPS app.use(enforce()); app.get('/', (req, res) => { res.send('Hello HTTPS!'); }); app.listen(3000);

原生 Node.js 重定向

const http = require('http'); const https = require('https'); const fs = require('fs'); // HTTP 服务器(重定向) http.createServer((req, res) => { res.writeHead(301, { 'Location': 'https://' + req.headers['host'] + req.url }); res.end(); }).listen(80); // HTTPS 服务器 const options = { key: fs.readFileSync('/path/to/your_domain.key'), cert: fs.readFileSync('/path/to/fullchain.crt') }; https.createServer(options, (req, res) => { res.writeHead(200); res.end('Hello HTTPS!'); }).listen(443);

最佳实践

  • 使用环境变量存储证书路径
  • 设置正确的文件权限
  • 使用完整的证书链
  • 仅启用 TLS 1.2 和 TLS 1.3
  • 配置强加密套件
  • 使用 HTTP/2(Node.js 8.4+)
  • 配置 HSTS 头
  • 定期更新 Node.js 和依赖包
  • 监控证书有效期
  • 使用进程管理器(如 PM2)管理 HTTPS 服务
  • 生产环境配置示例(Node.js 18+)

    const https = require('https'); const fs = require('fs'); const express = require('express'); const app = express(); // // 安全头设置app.use((req, res, next) => { res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains'); res.setHeader('X-Content-Type-Options', 'nosniff'); res.setHeader('X-Frame-Options', 'DENY'); res.setHeader('X-XSS-Protection', '1; mode=block'); next(); }); app.get('/', (req, res) => { res.send('Hello HTTPS!'); }); const options = { key: fs.readFileSync(process.env.SSL_KEY_PATH || '/etc/ssl/private/your_domain.key'), cert: fs.readFileSync(process.env.SSL_CERT_PATH || '/etc/ssl/certs/fullchain.crt'), minVersion: 'TLSv1.2', maxVersion: 'TLSv1.3', ciphers: [ 'TLS_AES_256_GCM_SHA384', 'TLS_AES_128_GCM_SHA256', 'ECDHE-RSA-AES128-GCM-SHA256', 'ECDHE-RSA-AES256-GCM-SHA384', 'ECDHE-RSA-CHACHA20-POLY1305' ].join(':'), honorCipherOrder: true }; https.createServer(options, app).listen(443, () => { console.log('HTTPS server running on port 443'); });
    📝 说明:
    • 使用环境变量存储敏感路径,提高安全性
    • 配置安全响应头,增强安全性
    • 使用标准端口 443 需要 root 权限或配置端口转发
    • 建议使用反向代理(Nginx)处理 SSL,Node.js 处理应用逻辑

    常见问题

    问题 1:证书文件读取错误

    错误: 错误信息:Error: ENOENT: no such file or directory

    解决:

    1. 检查证书文件路径是否正确(使用绝对路径)
    2. 确认文件是否存在
    3. 检查文件权限(私钥文件应为 600)
    4. 验证文件格式是否正确(PEM 格式)

    问题 3:端口被占用

    错误: 错误信息:Error: listen EADDRINUSE: address already in use :::443

    解决:

    1. 检查端口是否被其他进程占用:lsof -i :443 或 netstat -tulpn | grep 443
    2. 修改应用使用的端口号
    3. 使用反向代理(Nginx)处理 SSL,Node.js 使用其他端口
    4. 使用反向代理(Nginx)处理 SSL,Node.js 使用其他端口

    问题 2:TLS 握手失败

    错误: 错误信息:Error: SSL routines:ssl3_read_bytes:sslv3 alert handshake failure

    解决:

    1. 检查证书链是否完整
    2. 验证证书是否过期
    3. 确认 ca 选项配置正确(如果使用)
    4. 验证私钥和证书是否匹配
    5. 验证私钥和证书是否匹配

    问题 4:权限不足

    错误: 错误信息:Error: listen EACCES: permission denied

    解决:

    1. 使用端口 443 需要 root 权限(不推荐直接运行)
    2. 使用反向代理(Nginx)处理 SSL,Node.js 使用非特权端口
    3. 使用 setcap 给 Node.js 二进制文件设置权限(Linux)
    4. 使用端口转发(iptables)将 443 转发到应用端口

    问题 5:证书链不完整

    解决: 问题:浏览器显示证书警告,提示证书链不完整

    解决:

    1. 确保包含中间证书:cat your_domain.crt intermediate.crt > fullchain.crt
    2. 在配置中使用 ca 选项包含中间证书
    3. 验证证书链:openssl verify -CAfile fullchain.crt your_domain.crt