Nginx反向代理单IP多证书后端时TLS握手失败,根本原因是未正确配置SNI:必须同时启用proxy_ssl_server_name on并准确设置proxy_ssl_name(如$host或$host_x_forwarded_host),且upstream中需写死与证书SAN完全匹配的字符串。

Nginx 反向代理到单 IP 多证书后端时,TLS 握手失败、502 错误或证书校验报错,根本原因不是 Nginx 不支持 SNI,而是它默认不发 SNI,或发了但内容不对——`proxy_ssl_server_name on` 只是开关,真正起作用的是 `proxy_ssl_name` 的值是否准确反映了用户请求的域名。
必须同时配置两个指令
缺一不可,且顺序不能颠倒:
-
启用 SNI 扩展:在
location或upstream块中添加proxy_ssl_server_name on; -
指定 SNI 内容:紧接着写
proxy_ssl_name $host;(推荐)
——$host是标准化后的 Host 值(小写、无端口),比$http_host更安全可靠
应对 Host 被 CDN 或网关覆盖的情况
Cloudflare、阿里云全站加速、WAF 等常把回源 Host 改为源站名(如 origin.example.com),导致 $host 失真,SNI 错配:
- 在 CDN 控制台开启“透传原始 Host”,通常会自动携带
X-Forwarded-Host请求头 - Nginx 中改用:
proxy_ssl_name $http_x_forwarded_host; - 顺手补上:
proxy_set_header X-Forwarded-Host $host;,方便后端日志溯源
upstream 场景下要写死字符串
如果用了 upstream 做负载均衡,Nginx 在 TLS 握手阶段无法解析变量,$host 会失效:
upstream s3_gateway { server gateway-01.internal:443; }- 在对应
location中必须写:proxy_ssl_name "bucket-a.example.com";(加双引号,是字符串字面量) - 该值需与后端证书的 SAN 完全一致,大小写敏感
验证 SNI 是否真正发出
配置写对 ≠ 实际生效。必须确认 TLS 握手时发出的 SNI 值就是用户访问的域名:
- 在上游服务器(如另一台 Nginx 或 MinIO)开启 debug 日志:
error_log /var/log/nginx/error.log debug;,搜索client sent server name - 用 OpenSSL 模拟连接:
openssl s_client -connect 10.0.0.100:443 -servername bucket-a.example.com,检查返回证书的 CN/SAN 是否匹配 - 注意:Nginx 编译所用 OpenSSL 版本需 ≥1.0.2h,否则不支持 SNI 扩展











