启用 proxy_ssl_server_name on 是解决 Nginx 反向代理 HTTPS 后端时 SNI 冲突导致 502 或 403 的关键动作,但必须配合 proxy_ssl_name 和 proxy_set_header Host 才能确保上游正确识别域名并选用对应证书。

启用 proxy_ssl_server_name on 是解决 Nginx 反向代理 HTTPS 后端时 SNI 冲突导致 502 或 403 的关键动作,但它本身不“自动解决问题”,必须配合 proxy_ssl_name 和正确的 Host 头控制,才能让上游服务器准确识别目标域名并选用对应证书。
为什么默认会出 SNI 冲突
Nginx 默认在 TLS 握手阶段不发送 SNI 扩展。当 proxy_pass 指向一个 HTTPS 地址(如 https://api.example.com)时,它仅用该域名做 DNS 解析得到 IP,但建立 TLS 连接时仍以 IP 为依据——这导致上游无法知道客户端本意访问哪个域名。尤其在以下场景中极易触发冲突:
- 后端是多租户网关或 CDN,同一 IP 托管多个域名及独立证书
- 使用
upstream块且 server 定义为 IP(如server 10.0.0.10:443),SNI 字段完全为空 - 客户端通过 Host 头区分业务,但 Nginx 未将 Host 映射为 SNI 值
必须同时配置的三项核心指令
单独开启 proxy_ssl_server_name on 不足以修复问题。以下三者需共存,缺一不可:
安全更新和维护 CLI Proxy API(CPA)部署与配置。用于 CPA 镜像升级、配置变更、认证目录兼容修复、上线验证与回滚。适用于用户提到“CPA 更新/升级/配置改了/容器重建/回滚”等场景。
- proxy_ssl_server_name on:启用 TLS 握手时发送 SNI 扩展的能力(Nginx 1.7.0+ 支持)
-
proxy_ssl_name:明确指定 SNI 字段内容。若需动态适配不同请求,推荐用
proxy_ssl_name $host;;若固定后端,可用proxy_ssl_name "api.example.com";(注意加引号) -
proxy_set_header Host:设置上游可见的 Host 请求头。不能依赖
$host或$http_host(可能被恶意篡改),应写死为后端期望的域名,例如proxy_set_header Host "api.example.com";
upstream 场景下的特别处理
当使用 upstream 块做负载均衡或复用连接时,proxy_ssl_name 不能省略——即使 upstream 中已写域名,Nginx 仍需显式告知 TLS 层该用哪个名称发起握手:
- upstream 定义保持简洁,只写域名+端口:
upstream api_backend { server api.example.com:443; } - location 中必须包含:
proxy_ssl_server_name on;、proxy_ssl_name "api.example.com";、proxy_set_header Host "api.example.com"; - proxy_pass 必须指向该 upstream:
proxy_pass https://api_backend/;(协议必须为 https)
多域名动态代理的进阶写法
若一台 Nginx 需代理多个不同后端 HTTPS 域名(如按原始 Host 路由到不同 API 网关),可用 map 实现 SNI 动态映射:
- 先定义映射关系:
map $host $upstream_sni { hostnames; site-a.com "api.a.com"; site-b.com "api.b.com"; default "fallback.api.com"; } - 在 location 中使用:
proxy_ssl_name $upstream_sni;,配合proxy_ssl_server_name on;即可按需透传 SNI - 此时
proxy_set_header Host也建议设为对应值(可同样用 map 控制),避免 Host 与 SNI 不一致被严格校验的网关拒绝

















