Nginx Stream + SSL Preread 自动分流方案 — 技术问答归档
持续更新:每次技术问答后自动归档
最后更新:2026-10-06
A: 传统方案需要在 Nginx 的 HTTP 模块中直接监听外网端口并处理 SSL,所有 HTTP 和 HTTPS 流量必须使用同一端口。而 stream + ssl_preread 方案的优势:
ssl_preread 在 TCP 层检测 ClientHello,无需证书即可完成分流if ($scheme = http) 来做跳转?A: if 指令在 Nginx 中是 "if is evil" 的,有以下问题:
stream 上下文中无法使用 $scheme 变量(stream 不解析 HTTP)if 在 location 上下文中有已知的副作用和限制A: 是的。Nginx 的 map 指令在同一上下文中,如果多个 stream server 共享同一个 map,它们会路由到相同的后端。每个端口需要独立的服务组(不同的 SSL 终结端口和不同的后端),因此需要独立的 map 变量。
A: 模块化配置的优势:
nginx -t 可验证所有 include 文件nginx.conf 保持简洁,只负责全局配置和 include 指令backlog=4096 的含义是什么?需要调整吗?A: backlog 是 TCP 监听队列的最大长度。超过 backlog 的连接会被丢弃。
net.core.somaxconn)proxy_timeout 3600s 为什么要设这么大?A: 需要与 HTTP 模块的 proxy_read_timeout 保持一致:
proxy_next_upstream off 为什么禁用故障转移?A: 在 stream 上下文中:
include 指令的路径有什么要求?A:
include 路径可以是绝对路径或相对路径(相对于 nginx.conf 所在目录)include /etc/nginx/conf.d/*.conf;A: 可以,使用通配符证书 *.zhonjin.com 即可覆盖所有子域名:
chanking.zhonjin.com ✓mqtt.zhonjin.com ✓baolin.zhonjin.com ✓*.zhonjin.com ✓申请命令:
sudo certbot certonly --manual --preferred-challenges dns \
-d zhonjin.com -d "*.zhonjin.com"
A: 本方案中,不同子域名通过不同端口区分,而非 SNI 区分:
chanking.zhonjin.com:40130 → stream 端口 40130mqtt.zhonjin.com:40715 → stream 端口 40715baolin.zhonjin.com:40716 → stream 端口 40716每个 stream server 独立监听自己的端口,转发到对应的 HTTPS server,HTTPS server 通过 server_name 匹配域名。
ssl_preread 能否根据 SNI(域名)分流到不同后端?A: 可以。ssl_preread 不仅能检测是否为 TLS,还能读取 SNI 信息:
map $ssl_preread_server_name $sni_backend {
"mqtt.zhonjin.com" 127.0.0.1:8085;
"baolin.zhonjin.com" 127.0.0.1:5000;
default 127.0.0.1:5004;
}
但本方案使用端口区分,因此不需要 SNI 分流。
*.zhonjin.com 是否覆盖 zhonjin.com(不带子域名前缀)?A: 不覆盖。通配符证书只匹配 *.zhonjin.com,不匹配裸域 zhonjin.com。申请时需要同时指定:
-d zhonjin.com -d "*.zhonjin.com"
A: 主要瓶颈点:
ssl_session_cache 复用A:
shared:SSL_mqtt:5m 表示 5MB 共享内存A: 查看 stream 访问日志:
tail -f /var/log/nginx/stream_access_40715.log
# 正常 HTTP 访问应该看到 upstream 指向跳转端口
A: 常见原因:
return 301 URL 中端口写错了siteurl 配置为 HTTP排查:
curl -v http://mqtt.zhonjin.com:40715 2>&1 | grep Location
# 确认 Location 是 https:// 开头且端口正确
nginx -t 报错 "include file not found" 怎么办?A:
ls -la /etc/nginx/conf.d/zhonjin_http.confls -la /etc/nginx/stream.d/A:
nginx -t 通过A: 遵循检查清单:
nginx -t 通过后再 reloadA:
A: 树莓派 5 8G 完全够用:
A: 长期高频写入确实会影响 SD 卡寿命。建议:
A:
make -j4)新问答将按类别追加到对应章节中。