关键在于正确配置 proxy_ssl_server_name on 和 proxy_ssl_name $host,否则 Nginx 默认以 IP 或固定域名发送 SNI,导致单 IP 多证书后端因 SNI 不匹配而 TLS 握手失败、返回默认证书或 502 错误。
要让 Nginx 在反向代理到单 IP 多证书后端(如多租户 SaaS、云存储网关、CDN 回源目标)时不出错,关键不是只打开 SNI,而是让
把客户端真正请求的域名准确传过去——
只是开关,
才决定发什么。
为什么单 IP 多证书场景下默认会失败
后端用一个 IP 托管多个 HTTPS 域名(比如
shop-a.example.com
和
shop-b.example.com
),每个域名配了独立证书。Nginx 默认用
中的 IP 或写死域名当 SNI 值,结果所有请求都发同一个 SNI,后端只能返回默认证书或直接拒绝,导致 TLS 握手失败、502 错误、登录跳转异常等。
必须同时配置的两个指令
缺一不可:
启用 SNI 扩展
:在
或
块中加
指定 SNI 内容
:紧跟着写
(推荐)或
;
已标准化、不含端口,更稳妥
应对 Host 被覆盖的常见变体
前端有 CDN、WAF 或 API 网关时,它们常把
头改写为源站名(如
),导致
失真:
开启 CDN 的“透传原始 Host”功能,让它带上
头
Nginx 中改用
顺带加上
,方便后端日志溯源
验证是否真正生效
不能只看配置有没有写,得确认 TLS 握手时发出的 SNI 值就是用户访问的域名:
在上游服务(如另一台 Nginx)开启 debug 日志:
,搜索
看输出值
用 OpenSSL 手动模拟:
,检查返回证书的 SAN 是否匹配
注意:若上游不支持 SNI,或 OpenSSL 版本低于 1.0.2h,仍会失败
proxy_ssl_nameproxy_ssl_server_name onproxy_ssl_nameproxy_pass https://10.0.0.100locationupstreamproxy_ssl_server_name on;proxy_ssl_name $host;proxy_ssl_name $http_host;$hostHostorigin.example.com$hostX-Forwarded-Hostproxy_ssl_name $http_x_forwarded_host;proxy_set_header X-Forwarded-Host $host;error_log /var/log/nginx/error.log debug;client sent server nameopenssl s_client -connect 10.0.0.100:443 -servername shop-a.example.com