必须同时配置 proxy_ssl_server_name on 和 proxy_ssl_name 才能正确启用 SNI;默认用 proxy_pass 地址作域名,动态场景推荐 proxy_ssl_name $host,且需同步设置 Host 头。

只写 proxy_ssl_server_name on 并不能真正开启 SNI 支持——它只是打开 TLS 握手时发送 Server Name 扩展的“开关”,但不指定发什么域名。现代负载均衡(如 CDN 回源、多租户网关、SaaS 存储)依赖的是“正确的域名”被传过去,否则后端无法匹配证书,直接 TLS 握手失败。
必须搭配 proxy_ssl_name 才算完整启用
proxy_ssl_server_name on 本身不设值,Nginx 默认用 proxy_pass 中写的地址(比如 https://10.0.0.100 或 https://api.internal)作为 SNI 域名。这在单证书环境能蒙混过关,但在一个 IP 对应多个域名的场景下必然错配。
- 动态场景(推荐):加
proxy_ssl_name $host;——$host已标准化为小写、不含端口,优先取请求行 Host,比$http_host更稳妥 - CDN 回源常见情况:若 CDN 改写了 Host 头(如变成
origin.example.com),需 CDN 开启“透传原始 Host”,并在 Nginx 改用proxy_ssl_name $http_x_forwarded_host; - upstream 场景注意:变量在 upstream 内部不生效,
proxy_ssl_name必须写在location块中,且若后端是固定域名(如gateway.tenant-a.com),就得写成带引号的字符串:proxy_ssl_name "gateway.tenant-a.com";
别忘了 Host 头也要同步一致
SNI 是 TLS 层标识,Host 是 HTTP 层标识。很多后端(尤其是 SaaS 网关或 Istio sidecar)会双重校验:先靠 SNI 选证书,再靠 Host 头路由租户。两者不一致可能引发 502、403 或登录跳转错误。
- 务必添加
proxy_set_header Host $host;(不是$http_host,避免端口干扰) - 建议补充
proxy_set_header X-Forwarded-Host $host;,方便下游服务还原原始意图 - 若租户通过子域名识别(如
shop-a.example.com),可用map提取并透传:proxy_set_header X-Tenant-ID $tenant;
验证是否真的生效,不能只看配置
配置写对 ≠ 运行有效。必须确认 Nginx 实际发出的 SNI 值就是你期望的那个租户域名。
- 在上游服务器(如另一台 Nginx 或测试网关)开启 debug 日志:
error_log /var/log/nginx/error.log debug;,搜索client sent server name - 用 OpenSSL 手动模拟握手:
openssl s_client -connect 10.0.0.100:443 -servername shop-a.example.com,观察返回证书是否匹配该域名 - 若日志显示
server name: ""或固定 IP,说明proxy_ssl_name未生效、变量为空,或 upstream 解析阶段丢失了上下文











