Nginx stream四层代理中listen 443 ssl仅是TLS启用开关,必须配合--with-stream_ssl_module编译、ssl_certificate/ssl_certificate_key证书配置及ssl_protocols等指令才能实现加密传输。

在 Nginx 的 stream 四层代理中,仅写 listen 443 ssl; 并不能自动实现加密传输——它只是一个“开关”,真正启用 TLS 加密需满足多个前提和配套配置。
核心要点是:listen ... ssl; 是 TLS 启用的触发标识,但必须搭配证书、协议控制、模块支持才能生效。
必须启用的模块
Nginx 默认不带四层 TLS 能力。编译时需明确包含:
-
--with-stream(基础 stream 模块) -
--with-stream_ssl_module(提供ssl_certificate、ssl_verify_client等指令) - (推荐)
--with-stream_ssl_preread_module(用于 SNI/ALPN 提取,不影响加密本身,但对路由有用)
验证方式:
nginx -V 2>&1 | grep -E 'with-stream|stream_ssl'
若无输出,需重编译或加载动态模块(如 load_module /usr/lib/nginx/modules/ngx_stream_ssl_module.so;),且该行必须放在主配置最顶部(user 指令之前)。
基础 TLS 终止配置(单向加密)
这是实现“对外 TCP 加密传输”的最小可行配置:
stream {
upstream backend {
server 192.168.1.100:8080;
}
server {
listen 8443 ssl;
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 4h;
proxy_pass backend;
proxy_timeout 1h;
}
}说明:
- 客户端连接
8443端口时,会与 Nginx 完成 TLS 握手,链路全程加密; - Nginx 解密后,以明文 TCP 转发给后端(即 TLS 终止);
- 后端无需支持 TLS,适合 MySQL、Redis、自定义 TCP 服务等场景;
-
ssl_certificate和ssl_certificate_key是强制项,缺一不可;路径需确保 Nginx 进程有读取权限(如chmod 600私钥)。
如需双向认证(mTLS),额外加三步
单纯 listen ... ssl + 服务端证书,只做服务端身份认证(客户端验证 Nginx)。要让 Nginx 同时校验客户端身份,还需:
-
ssl_client_certificate /etc/nginx/ssl/ca.pem;
指向受信任的根 CA 证书(PEM 格式),用于验证客户端证书签名链; -
ssl_verify_client on;
开启强制校验;设为optional表示尝试校验但不拒绝; - 确保
ssl_client_certificate文件存在且格式正确,否则 Nginx 启动失败或连接被拒。
⚠️ 注意:
ssl_verify_client on却没配ssl_client_certificate,Nginx 会报错退出。
实际生效的关键细节
- 配置必须放在
stream { }块内,不能嵌套在http { }或其他块中; -
listen指令中的ssl标识是必需的,没有它,所有ssl_*指令会被忽略; - 证书域名/IP 需匹配客户端访问地址(如用 IP 访问,证书应含对应 IP Subject Alternative Name);
- 防火墙需放行监听端口(如
8443),且客户端需支持所选 TLS 版本和密码套件。
验证是否成功
用 OpenSSL 测试握手:
openssl s_client -connect your-nginx-ip:8443 -servername example.com
若看到 Verify return code: 0 (ok) 且有 SSL handshake has read X bytes,说明 TLS 已建立。
若需进一步确认是否 mTLS,可加 -cert client.crt -key client.key 并观察服务端是否要求证书。
配置本身不复杂,但每个环节都可能成为断点:模块缺失、路径错误、权限不足、证书链不全、协议不兼容……逐项核对比盲目堆参数更有效。


















