关键是要让Nginx缓存回源时将客户端原始域名作为SNI值发送:需配置proxy_ssl_server_name on和proxy_ssl_name $host(或$http_x_forwarded_host),确保上游按SNI匹配对应证书,并验证OpenSSL≥1.0.2h、回源为HTTPS且证书SAN包含该域名。

要让 Nginx 在缓存回源时正确对接 SNI 多证书后端(比如 CDN 回源目标、多租户网关或共用 IP 的 HTTPS 服务),关键不是只开 proxy_ssl_server_name on,而是让它把客户端原始请求的域名作为 SNI 值发出去——否则上游无法选对证书,TLS 握手失败,表现为 502、403 或证书不匹配告警。
必须开启 SNI 并绑定动态域名
默认情况下,Nginx 与 HTTPS 后端建连时不会发送 SNI 字段,它只用 proxy_pass 中写的地址(如 https://10.0.0.100)作为 TLS 握手依据。这在单证书环境可行,但在一个 IP 对应多个域名、各配独立证书的场景下必然出错。
- 在对应
location块中添加proxy_ssl_server_name on;,启用 SNI 扩展支持 - 紧接着配置
proxy_ssl_name $host;,确保 SNI 值等于客户端请求头中的 Host 域名($host已标准化为小写、不含端口,比$http_host更稳妥) - 避免写死值,例如
proxy_ssl_name "api.example.com";,除非所有流量都指向唯一后端域名
CDN 或缓存层透传 Host 头时的适配
如果前端有 CDN(如 Cloudflare、阿里云全站加速)或自建缓存层,它们常会重写 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;,方便后端识别真实请求来源 - 确认 CDN 实际走的是 HTTPS 回源;若回源协议是 HTTP,
proxy_ssl_*指令完全不生效
验证 SNI 是否真正发出
配置写对了 ≠ 运行时有效。必须确认 TLS 握手阶段实际发出的 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 your-domain.com,观察返回证书是否匹配该域名 - 检查 Nginx 编译信息:
nginx -V | grep OpenSSL,确保加载的是 OpenSSL ≥1.0.2h 且启用了 TLS extensions
配套基础项不能漏
SNI 正常工作还需几个支撑点,缺一不可:
-
proxy_pass必须指向 HTTPS 地址(如https://10.0.0.100),指向 HTTP 或纯 IP 不触发 SNI - 建议显式设置
proxy_set_header Host $host;,保持请求头与 SNI 一致,避免后端因 Host 不匹配做错误跳转或拒绝 - 若上游证书链不完整或域名 SAN 不含 SNI 值,即使 SNI 正确也会报证书不匹配,需同步校验后端证书


















