proxy_ssl_server_name on 仅启用SNI发送功能,但不指定SNI内容;必须配合 proxy_ssl_name $host 等动态变量才能将原始请求域名作为SNI值传递给上游,否则因SNI固定导致证书不匹配而握手失败。

要让 Nginx 在代理请求到多租户 SaaS 存储(比如每个租户对应独立域名和专属 SSL 证书)时不出 TLS 握手失败,proxy_ssl_server_name on 是基础前提,但单开它还不够——必须配合 proxy_ssl_name 动态传递原始请求域名,否则上游无法选对证书。
为什么 proxy_ssl_server_name 单独开启会失效
Nginx 默认用 proxy_pass 中写的地址(如 https://storage.tenant-a.com)作为 TLS 握手时的 SNI 值。但在多租户场景下,真实请求可能是 shop-b.example.com 或 api-xyz.saas.io,而你后端存储服务是按 Host 区分租户并配了不同证书的。如果 SNI 固定为统一回源地址,上游就只能返回默认证书或直接拒绝连接。
所以:
- proxy_ssl_server_name on 只是“允许发 SNI”,不指定内容;
- 真正起作用的是 proxy_ssl_name,它决定发哪个域名过去。
正确配置 proxy_ssl_name 的关键写法
必须用变量动态取值,不能写死(除非所有租户共用一个证书):
- 推荐用
$host:标准化后的 Host 头,不含端口,大小写已归一,最稳妥; - 慎用
$http_host:可能带端口(如shop-a.com:443),某些后端会校验失败; - 避免纯字符串如
"shop-a.com":无法适配多租户动态路由。
示例配置:
location /files/ {proxy_pass https://10.0.0.50;
proxy_ssl_server_name on;
proxy_ssl_name $host;
proxy_set_header Host $host;
}
CDN 回源时的特殊处理
如果流量经 CDN(如阿里云全站加速、Cloudflare)再打到你的 Nginx,要注意 CDN 往往会重写 Host 头为源站域名(如 origin.yourdomain.com),这时 $host 就不是用户原始域名了。
⚠️ 已弃用 — 该技能已拆分为两个独立技能,以提升模块化程度:**webchat-https-proxy**(HTTPS/WSS 反向代理)和 **webchat-voi...**
解决办法是让 CDN 透传原始 Host:
- 在 CDN 控制台开启“透传 X-Forwarded-Host”或类似选项;
- Nginx 改用
proxy_ssl_name $http_x_forwarded_host;; - 同时确保 CDN 回源协议是 HTTPS(HTTP 回源会让
proxy_ssl_*指令完全不生效)。
结合多租户识别做增强兼容
如果你已在 server 块中用正则提取租户标识(如 ~^(?<tenant>.+)\.saas\.com$</tenant>),也可以把 proxy_ssl_name 绑定到该变量:
server_name ~^(?
location /api/ {
proxy_pass https://storage-backend;
proxy_ssl_server_name on;
proxy_ssl_name $tenant.saas.com;
}
}
这种写法更明确,适合租户域名规则固定、且后端严格按域名匹配证书的架构。










