必须启用 proxy_ssl_server_name on 并配置 proxy_ssl_name $host(或 $http_x_forwarded_host),同时设置 proxy_set_header host $host 和缓存键包含 $host,才能确保 nginx 回源多租户 saas 时正确传递租户域名级 sni 并实现租户隔离。

要让 Nginx 在负载均衡回源到多租户 SaaS 平台时不出 TLS 握手错误,关键不是只打开 proxy_ssl_server_name on,而是确保它把用户真实访问的租户域名作为 SNI 值发给后端——否则上游网关无法选证、路由失败,缓存和请求都会中断。
必须开启 SNI 扩展并绑定动态域名
Nginx 默认不发 SNI 字段,即使 proxy_pass 指向 HTTPS 地址,也会用配置里的字面地址(比如 https://10.0.0.100)当 SNI 名。这对单租户环境无感,但在一个 IP 托管多个租户域名(如 app.tenant-a.io、shop.tenant-b.com)的场景下必然错配:
- 在
location块中添加proxy_ssl_server_name on;—— 该指令仅对proxy_pass https://生效,且不能写在upstream块内部 - 紧接着配置
proxy_ssl_name $host;——$host已标准化(小写、去端口),比$http_host更可靠 - 避免写死值,例如
proxy_ssl_name "api.example.com";,除非所有流量都固定指向同一租户后端
应对 CDN 或网关覆盖 Host 头的情况
很多云平台(如 Cloudflare、阿里云全站加速)回源时会强制改写 Host 头为源站配置名(如 origin.prod.cloud),导致 $host 不再是用户原始域名:
安全更新和维护 CLI Proxy API(CPA)部署与配置。用于 CPA 镜像升级、配置变更、认证目录兼容修复、上线验证与回滚。适用于用户提到“CPA 更新/升级/配置改了/容器重建/回滚”等场景。
- 在 CDN 控制台启用“透传原始 Host”功能,通常表现为自动注入
X-Forwarded-Host请求头 - Nginx 中改用
proxy_ssl_name $http_x_forwarded_host; - 同时加一句
proxy_set_header X-Forwarded-Host $host;,方便下游服务识别真实租户上下文 - 别忘了保持 HTTP 层一致:
proxy_set_header Host $host;(不用$http_host,避免端口干扰)
缓存键必须与 SNI 域名对齐
启用 proxy_cache 后,若缓存键不含租户维度,不同租户的响应会互相覆盖,造成数据串扰或样式错乱:
- 禁止使用
$scheme$proxy_host$request_uri这类固定后端地址的键 ——$proxy_host是 IP 或内部域名,不随租户变化 - 推荐缓存键包含
$host或$http_x_forwarded_host,例如:proxy_cache_key "$host$request_uri$is_args$args"; - 搭配租户级缓存策略:
proxy_cache_valid 200 302 10m;,避免长缓存掩盖租户专属变更
验证 SNI 是否真正发出
配置写对不等于运行时生效。需确认 TLS 握手阶段实际发出的 SNI 值是否匹配预期:
- 在上游 SaaS 网关或测试服务端开启 debug 日志:
error_log /var/log/nginx/error.log debug;,搜索client sent server name或tlsext host name - 用 OpenSSL 手动模拟:
openssl s_client -connect 10.0.0.100:443 -servername app.tenant-a.io,观察返回证书的 CN/SAN 是否匹配 - 检查底层支持:
nginx -V | grep OpenSSL,确保 OpenSSL ≥ 1.0.2h 且编译时启用了enable-tlsext










