排查nginx stream模块tls转发配置冲突,核心在于确认ngx_stream_ssl_module是否启用、ssl指令仅限server块内、sni/alpn路由需map配合默认值、openssl验证实际证书与会话复用。

排查 Nginx Stream 模块处理 TLS 转发时的配置冲突,核心在于理清 模块启用状态、作用域层级、SSL 指令生效条件与 SNI/ALPN 路由逻辑 四个层面。Stream 的 TLS 行为不走 HTTP 流程,错误常静默或表现为连接中断、证书不匹配、协议协商失败,而非明显报错。
确认 stream_ssl_module 是否真正可用
仅检查 --with-stream 不够,ngx_stream_ssl_module 是独立模块,需额外编译支持:
- 运行
nginx -V 2>&1 | grep -o with-stream-ssl,有输出才表示已启用;若无,即使写了ssl_certificate在 stream 块里,Nginx 启动会直接报unknown directive "ssl_certificate" - 动态模块需在
nginx.conf顶层显式加载:load_module /usr/lib/nginx/modules/ngx_stream_ssl_module.so;(路径依系统而异),且该行必须在events块之前 -
nginx -T | grep "stream_ssl"可验证模块是否被成功载入
检查 SSL 指令是否写在合法作用域
Stream 模块中 TLS 相关指令有严格位置要求:
-
ssl_certificate、ssl_certificate_key、ssl_protocols、ssl_ciphers等只能出现在 stream → server 块内,不能写在 upstream 或全局 stream 块外 - 写在
http{}或location{}中会报错,因为它们属于不同模块上下文 -
proxy_ssl_*类指令(如proxy_ssl on)是用于出向 TLS(即 Nginx 主动连上游带 TLS),必须和proxy_pass在同一server块,且仅在此处生效
验证 SNI 和 ALPN 路由是否按预期匹配
当用 ssl_preread on + map 实现多域名或协议分流时,冲突常源于匹配逻辑错误:
-
$ssl_preread_server_name在客户端未发送 SNI 时为空字符串,若 map 中没设默认值,会导致 upstream 变量未定义,连接直接拒绝 -
ssl_alpn需配合map $ssl_preread_alpn_protocols使用;ALPN 字符串含逗号分隔(如"h2,http/1.1"),正则匹配要加~*并注意转义 - 用
openssl s_client -connect ip:port -servername example.com -alpn h2可验证 SNI 和 ALPN 是否被正确提取,再比对 Nginx error log 中的preread变量值
观察实际 TLS 握手行为,而非只信配置语法
nginx -t 通过不代表 TLS 转发正常:
- 用
openssl s_client -connect your.ip:port -servername domain.com -tls1_2查看返回的证书 Subject、Issuer 是否与ssl_certificate指向一致;若显示的是其他证书,说明匹配到了别的server块或 fallback 到了 default_server - 检查握手后是否复用会话:
openssl s_client ... -reconnect输出中出现Reused, SSL handshake has read 0 bytes才表示ssl_session_cache生效 - 开启
error_log /var/log/nginx/error.log debug;(需重新编译含 debug 日志支持),可捕获ssl_preread变量值、SNI 匹配过程、证书加载路径等关键线索











