同一个 443 端口跑多个 TLS 服务:Nginx stream + SNI 分流实战

举报
yd_245773411 发表于 2026/10/18 09:38:17 2026/10/18
【摘要】 一、问题:一个公网 IP,443 端口只能给一个服务云主机通常只有一个公网 IPv4,但业务上经常需要让 443 端口同时服务多个 TLS 后端:主站、内部管理面板、以及一个需要长连接的私有隧道服务。用七层反向代理做不到这件事——七层必须先在 Nginx 里完成 TLS 握手,再按 Host 或路径转发,后端拿到的就是明文 HTTP,原来的 TLS 服务根本没法工作。正确的位置是把分流下沉到...

一、问题:一个公网 IP,443 端口只能给一个服务

云主机通常只有一个公网 IPv4,但业务上经常需要让 443 端口同时服务多个 TLS 后端:主站、内部管理面板、以及一个需要长连接的私有隧道服务。用七层反向代理做不到这件事——七层必须先在 Nginx 里完成 TLS 握手,再按 Host 或路径转发,后端拿到的就是明文 HTTP,原来的 TLS 服务根本没法工作。

正确的位置是把分流下沉到四层:Nginx 用 ssl_preread 只看 ClientHello 里的 SNI 字段,按域名把原始 TCP 流量丢给不同后端,TLS 握手完全交给后面的服务自己完成。Nginx 全程不碰证书,也不需要为每个域名准备证书。

二、结构

客户端 → 公网 443 → nginx stream(ssl_preread 读 SNI)→ 命中域名转发到对应 upstream;没命中(IP 直连、未知域名)走 default 分支。整个链路只有一次 TCP 连接,Nginx 不终止 TLS。

三、核心配置

stream {
    map $ssl_preread_server_name $backend {
        www.example.com   web;
        panel.example.com panel;
        default           fallback;
    }
    upstream web      { server 127.0.0.1:8443;  }
    upstream panel    { server 127.0.0.1:9443;  }
    upstream fallback { server 127.0.0.1:8443;  }
    server {
        listen 443;
        listen [::]:443;
        ssl_preread on;
        proxy_pass $backend;
        proxy_protocol on;
        proxy_connect_timeout 5s;
        proxy_timeout 600s;
    }
}

ssl_preread 必须开在 server 块里,map 才能读到 $ssl_preread_server_name。proxy_timeout 建议调大,长连接业务默认 10 分钟就断会很难受。

四、三个实际踩过的坑

1) 出现空 SNI 全部落到 default。客户端用 IP 直连、或者先发明文 HTTP 探测时,$ssl_preread_server_name 是空字符串,会走 default。所以 default 分支要能兜住这些流量,否则表现为"连接被重置",排查时容易误判成防火墙问题。

2) 打开 proxy_protocol 后日志全是 127.0.0.1。后端站点必须补上 set_real_ip_from 127.0.0.1; real_ip_header proxy_protocol; 两行,否则访问日志、限流、风控全部按本机地址计算,等于失效。

3) 后端监听地址写成了 0.0.0.0。这样等于留了一条绕过分流的旁路,任何人直连该端口都能跳过 SNI 判断。内部上游统一监听 127.0.0.1,再用安全组把高位端口全部关掉,才算是真的收口。

五、验证

用 openssl s_client -connect IP:443 -servername www.example.com 看返回的证书链,再用另一个 -servername 对比,两次拿到的证书应该不同;如果相同,说明 map 没生效或者后端监听串了。最后 curl -I https://域名 确认业务正常,nginx -t && systemctl reload nginx 确认配置可回滚。

六、小结

四层分流的本质是"不碰 TLS":代理和站点各自完成握手,互不干扰,新增后端只是加一个 map 条目加一个 upstream。代价是 Nginx 看不到 HTTP 层信息,所有按路径、按 Header 的策略都要下沉到后端。想清楚这条边界,配置其实只有二十来行。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。