关键是开启 proxy_ssl_server_name on 并动态设置 proxy_ssl_name $host;,确保 Nginx 将客户端真实请求域名作为 SNI 发送给多租户后端,同时透传 Host 头并验证 debug 日志或 OpenSSL 握手结果。

要让 Nginx 在缓存回源时正确连接多租户 SaaS 后端,关键不是只打开 proxy_ssl_server_name,而是让它把用户真实请求的域名作为 SNI 发送给后端——否则后端无法识别租户,会返回默认证书或直接断连。
必须开启 SNI 扩展
Nginx 默认关闭 TLS 的 SNI 扩展(proxy_ssl_server_name off),这意味着它在跟后端建立 HTTPS 连接时,Client Hello 里不带 Server Name 字段。而多租户 SaaS 后端(比如一个 IP 上跑着 tenant-a.example.com 和 tenant-b.example.com)完全依赖这个字段来选证书和路由请求。
- 在
location块中添加proxy_ssl_server_name on; - 该指令只对
proxy_pass https://...生效,HTTP 回源无需配置 - 如果用了
upstream块,proxy_ssl_server_name必须写在引用它的location里,不能写在upstream内部
动态传入租户域名作为 SNI 值
仅开启 SNI 不够。Nginx 默认用 proxy_pass 中写的地址(如 https://10.0.0.100 或 https://api.saas.internal)当 SNI 名,这在多租户场景下必然错配。
- 用
proxy_ssl_name $host;—— 推荐,$host已标准化,不含端口,且优先取请求行 Host,再 fallback 到请求头 - 避免写死
proxy_ssl_name "api.example.com";,除非所有流量都指向同一租户后端 - 若 CDN 透传了原始 Host 到自定义头(如
X-Forwarded-Host),可用proxy_ssl_name $http_x_forwarded_host;
保持 Host 请求头与 SNI 一致
SNI 是 TLS 层的标识,Host 头是 HTTP 层的标识。两者应匹配,否则部分 SaaS 后端会在 TLS 握手成功后,再根据 Host 头做租户识别,出现逻辑错位。
- 加上
proxy_set_header Host $host; - 不要用
$http_host(可能含端口),也不要省略——即使后端不校验,也建议保留一致性 - 配合
X-Real-IP、X-Forwarded-For等头一并透传,便于后端日志和限流
验证是否生效
配置完别急着上线,先确认 SNI 值是否真发出去了:
- 开启 Nginx debug 日志(
error_log /var/log/nginx/error.log debug;),搜索SSL_do_handshake或tlsext host name关键字 - 用 OpenSSL 手动模拟:
openssl s_client -connect 10.0.0.100:443 -servername tenant-a.example.com,对比 Nginx 实际发出的 SNI 是否一致 - 观察错误日志是否还有
certificate verify failed或tlsv1 alert internal error,这些往往是 SNI 未传或传错的信号











