关键是要让Nginx在TLS握手时将客户端真实请求的域名作为SNI值发送给后端,需同时启用proxy_ssl_server_name on并动态设置proxy_ssl_name $host;,配合CDN透传原始Host头,再通过debug日志验证SNI值是否准确发出。

要解决后端 HTTPS 服务因 SNI 不匹配导致的证书选择错误、连接中断或 502 错误,关键不是单纯开启 proxy_ssl_server_name on,而是让它传对值——即让 Nginx 在 TLS 握手时,把客户端真实请求的域名作为 SNI 发送给后端。否则后端无法返回对应证书,甚至可能触发业务层逻辑(如租户识别)异常。
必须开启 SNI 支持
Nginx 默认不发送 SNI,所以第一步是显式启用:
-
proxy_ssl_server_name on;必须加在 location 或 upstream 对应作用域内 - 该指令只对
proxy_pass https://...生效,HTTP 回源无效 - 若使用 upstream 块定义后端,需确保该块被 location 正确引用,且
proxy_ssl_server_name配置在 location 中而非 upstream 内
动态设置 proxy_ssl_name 才能匹配多域名
仅开启 SNI 不够。Nginx 默认用 proxy_pass 后写的域名(如 https://backend.example.com)作为 SNI 值,这在多域名场景下会固定错配。
- 应配合
proxy_ssl_name $host;,让 SNI 值随客户端 Host 头动态变化 -
$host是标准化后的 Host 值(不含端口、小写),比$http_host更稳妥 - 不能写死为某个域名(如
proxy_ssl_name shop-a.com;),除非所有请求都指向同一后端域名
注意 CDN 回源时 Host 头被覆盖的情况
很多 CDN(如 Cloudflare、阿里云全站加速)回源时会重写 Host 头为源站配置域名,导致 $host 变成 CDN 设定的源站名,而非用户原始域名。
- 需在 CDN 控制台开启“透传原始 Host”功能,通常表现为传递
X-Forwarded-Host或X-Real-Host - Nginx 中改用
proxy_ssl_name $http_x_forwarded_host; - 同时建议加
proxy_set_header X-Forwarded-Host $host;确保下游可读取原始值
验证是否真正生效
光看配置是否写对不够,得确认 SNI 值确实按预期发出:
- 在上游 HTTPS 服务(如另一台 Nginx)开启 debug 日志:
error_log /var/log/nginx/error.log debug; - 重启后发起请求,搜索日志中
SSL_do_handshake或client sent server name相关行 - 确认收到的 SNI 值与客户端请求的域名一致,而非固定后端域名或空值











