proxy_ssl_name用于动态指定TLS SNI值以解决多租户SaaS回源握手失败,须配合proxy_ssl_server_name on启用,并设为$host等变量透传客户端请求域名。

要解决反向代理到多租户 SaaS 环境时因 TLS SNI 不匹配导致的握手失败,核心是让 Nginx 在与后端 HTTPS 服务建立连接时,发送正确的域名作为 SNI 值——这正是 proxy_ssl_name 的作用。它必须配合 proxy_ssl_server_name on 使用,且值需动态对应客户端实际请求的租户域名。
明确 SNI 冲突的根源
多租户 SaaS 后端常以单 IP 托管多个域名(如 tenant-a.example.com、tenant-b.example.com),每个域名配独立证书。Nginx 默认用 proxy_pass 中写的地址(如 https://10.0.0.5 或 https://backend.internal)作为 SNI 发送给后端。一旦后端依赖 SNI 选证或路由租户,就会返回默认证书或拒绝连接,造成握手失败或业务逻辑错乱(比如登录失败、租户数据串扰)。
关键配置项必须协同生效
以下四项缺一不可:
-
启用 SNI 扩展:必须写
proxy_ssl_server_name on;,否则 Nginx 根本不发 SNI 字段; -
动态指定 SNI 值:用
proxy_ssl_name $host;(推荐)或proxy_ssl_name $http_host;,确保传给后端的是客户端原始请求头中的 Host 域名; -
透传原始 Host 头:加
proxy_set_header Host $host;,避免后端误判租户标识; -
禁用硬编码静态值:不要写死
proxy_ssl_name "tenant-a.example.com";,除非所有请求都固定指向该租户。
适配多租户的典型配置模式
根据你的路由方式选择写法:
-
基于 server_name 多域名共存:在
server块中直接使用$host:server {<br> listen 443 ssl;<br> server_name tenant-a.example.com tenant-b.example.com;<br> location / {<br> proxy_pass https://10.0.0.100:443;<br> proxy_ssl_server_name on;<br> proxy_ssl_name $host;<br> proxy_set_header Host $host;<br> }<br>} -
基于正则提取租户名并路由:先用
map或server_name ~^...提取租户变量,再用于 SNI:map $host $upstream_sni {<br> default "default.internal";<br> "tenant-a.example.com" "api-tenant-a.internal";<br> "tenant-b.example.com" "api-tenant-b.internal";<br>}<br>location / {<br> proxy_pass https://$upstream_sni;<br> proxy_ssl_server_name on;<br> proxy_ssl_name $upstream_sni;<br>}
验证是否生效的简单方法
修改配置后重载 Nginx,用 curl 模拟回源请求观察后端日志或抓包确认:
- 发起请求:
curl -H "Host: tenant-a.example.com" https://your-nginx-ip/health; - 检查后端 TLS 握手日志中收到的 SNI 是否为
tenant-a.example.com; - 若仍失败,临时关闭
proxy_ssl_verify排除证书校验干扰,聚焦 SNI 本身是否送达。











