必须启用proxy_ssl_server_name,否则Nginx反向代理HTTPS时TLS握手不携带SNI,上游无法区分虚拟主机;开启后默认用$proxy_host作为SNI值,支持proxy_ssl_name自定义。

当 Nginx 作为反向代理,把 HTTPS 请求转发给上游(比如 CDN 回源、多域名共用同一 IP 的后端服务器),而上游依赖 SNI(Server Name Indication)来区分虚拟主机时,必须显式启用 proxy_ssl_server_name,否则 TLS 握手阶段不携带 SNI,上游无法正确选择证书和站点,导致连接失败或返回默认站点。
为什么需要 proxy_ssl_server_name
Nginx 默认在与上游建立 HTTPS 连接时,不发送 SNI 扩展。这意味着即使你配置了 proxy_pass https://example.com,Client Hello 中的 SNI 字段仍是空的或使用 IP 地址。上游若托管多个 HTTPS 域名(如 blog.example.com、api.example.com 共享 10.0.0.1:443),就无法识别该请求应路由到哪个虚拟主机。
开启 proxy_ssl_server_name on 后,Nginx 会在 TLS 握手时主动带上 SNI,值默认为 $proxy_host(即 proxy_pass 指定的域名),从而让上游能正确匹配 SSL 证书和 server 块。
基础配置写法
以下是最小可用示例,用于代理到带 SNI 的 HTTPS 上游:
- 确保
proxy_pass使用的是域名而非 IP(SNI 本质是传域名) - 添加
proxy_ssl_server_name on; - 可选:用
proxy_ssl_name显式指定 SNI 值(例如回源时需填 CDN 要求的特定 host)
示例配置:
location / {
proxy_pass https://blog.dianduidian.com;
proxy_ssl_server_name on;
# proxy_ssl_name "blog.dianduidian.com"; # 可省略,默认即 $proxy_host
}配合 proxy_ssl_name 精确控制 SNI 内容
某些场景下,proxy_pass 域名和实际要发送的 SNI 不一致。典型例子是 CDN 回源:
- 你配置
proxy_pass https://10.0.1.5:443(用 IP 直连后端) - 但 CDN 要求回源 SNI 必须是
origin.example.com,否则拒绝服务
此时需同时启用 SNI 并自定义名称:
location / {
proxy_pass https://10.0.1.5:443;
proxy_ssl_server_name on;
proxy_ssl_name "origin.example.com";
}proxy_ssl_name 支持变量,例如 proxy_ssl_name "$host";,适合泛域名代理场景。
验证是否生效
最直接的方式是抓包观察 TLS Client Hello:
- 用
tcpdump -i any port 443 -w upstream.pcap抓 Nginx 到上游的流量 - 用 Wireshark 打开,过滤
tls.handshake.type == 1(Client Hello) - 展开 TLS → Extensions → Server Name → server_name_list → Host Name,确认有对应域名
若无此字段,说明 proxy_ssl_server_name 未生效或上游地址用了 IP 导致 SNI 自动禁用。


















