必须开启proxy_ssl_server_name on并配合proxy_ssl_name $host;和proxy_set_header Host $host;,三者一致才能准确传递客户端域名至后端SNI,避免证书错配导致SSL_do_handshake()失败、502或403错误。

要解决 Nginx 代理到多域名后端时因 SNI 不匹配导致的 TLS 握手报错(如 SSL_do_handshake() failed、tlsv1 alert internal error 或 502/403),关键不是单独设置 proxy_ssl_name,而是让它和 proxy_ssl_server_name on 协同工作,把客户端真实请求的域名准确传给后端。
必须开启 SNI 发送能力
Nginx 默认不发送 SNI 字段。即使 proxy_pass 指向 HTTPS 地址,若没显式启用,TLS 握手时仍会以 IP 或 upstream 名称作为目标,导致后端无法选证。
- 在
location或upstream对应的 proxy 块中添加:proxy_ssl_server_name on; - 该指令仅在
proxy_pass使用 HTTPS 协议时生效(如https://backend.example.com) - 低于 Nginx 1.7.0 的版本不支持,需升级
动态指定 SNI 值,不能写死
proxy_ssl_name 决定 TLS Client Hello 中实际发送的域名。它必须与客户端原始请求一致,否则后端返回默认证书或直接拒连。
- 最常用且推荐:
proxy_ssl_name $host;(已标准化,不含端口,来自 Host 请求头) - 若经 CDN(如 Cloudflare)中转且 Host 被覆盖,改用:
proxy_ssl_name $http_x_forwarded_host;,前提是 CDN 开启了原始 Host 透传 - 绝对避免:
proxy_ssl_name "api.example.com";—— 多域名场景下硬编码会导致其他租户请求 SNI 错配
同步透传 Host 请求头
仅传 SNI 不够。部分后端(尤其是云网关、SaaS 多租户网关)会校验 SNI 与 Host 头是否一致,不一致则拒绝请求。
- 加上:
proxy_set_header Host $host; - 若使用
$http_x_forwarded_host传 SNI,建议也加:proxy_set_header X-Forwarded-Host $host;,方便后端日志识别真实租户 - 不要让 CDN 或中间层覆盖 Host 头,否则
$host就失真了
验证是否真正生效
配置写对 ≠ 实际生效。必须确认 Nginx 发出的 SNI 确实是你期望的域名。
- 在上游服务器(如另一台 Nginx)开启 debug 日志:
error_log /var/log/nginx/error.log debug; - 触发一次请求后,搜索日志中的
client sent server name,看值是否匹配客户端 Host - 或用
openssl s_client -connect your-upstream:443 -servername expected-domain.com手动验证上游是否对指定 SNI 返回正确证书 - 抓包辅助:用
tcpdump抓 Nginx 到上游的 443 流量,Wireshark 查看 Client Hello 的 Server Name Indication 字段


















