nginx 不支持正向代理 https 流量,仅适用于反向代理场景;必须启用 proxy_ssl_server_name on 并显式配置 proxy_ssl_name "目标域名",且 proxy_pass 必须使用域名而非 ip,host 请求头需与 sni 域名严格一致,最后需通过日志或 openssl 验证生效。

Nginx 本身不支持正向代理 HTTPS 流量(即客户端通过 Nginx 访问任意外部 HTTPS 网站),这是关键前提。你遇到的“正向代理中 SNI 握手失败”,实际几乎都发生在 误用 Nginx 做正向代理 的场景下——Nginx 并非为此设计,它没有 CONNECT 方法的完整 TLS 透传能力,无法像 Squid 或专用代理软件那样原样转发客户端的 Client Hello(含 SNI)。
真正可行且符合 Nginx 定位的,是反向代理:你控制后端域名,Nginx 作为服务出口代理到特定外部 HTTPS 服务(如 API、S3、云网关)。此时 SNI 问题有明确解法。
以下按实际适用场景分述:
必须启用 proxy_ssl_server_name 并配对 proxy_ssl_name
Nginx 默认不会在 TLS 握手时发送 SNI 字段。光写 proxy_pass https://api.example.com 不够,必须显式开启并指定值:
- 加
proxy_ssl_server_name on;—— 打开 SNI 发送开关 - 加
proxy_ssl_name "api.example.com";—— 显式填入目标域名(必须加英文双引号,不能写$host或不加引号)
这两条缺一不可,否则上游收到空 SNI 或错误域名,直接拒连或返回默认证书。
proxy_pass 必须用域名,不能用 IP
Nginx 不会从请求头自动提取域名补全 SNI,它只认 proxy_pass 指令里写的字符串:
- ✅ 正确:
proxy_pass https://api.example.com/;(结尾斜杠建议保留) - ❌ 错误:
proxy_pass https://10.10.20.30/;或https://[2001:db8::1]/—— 此时 SNI 字段为空,必然失败
即使用了upstream,upstream块里写server api.example.com:443;也不够,proxy_ssl_name仍需在location中显式写死。
Host 请求头必须与 SNI 域名严格一致
很多外部服务(如 AWS S3、阿里云 API 网关、Istio 入口网关)会同时校验 SNI 和 Host 请求头:
- 若 SNI 是
"api.example.com",则必须配proxy_set_header Host "api.example.com"; - 切忌混用:一边写
proxy_ssl_name $host,一边写proxy_set_header Host "static.com",极易触发 403 或 502
验证是否真正生效,不能只 reload
配置正确 ≠ 实际发出的 SNI 正确。必须主动验证:
- 在上游服务侧(如另一台 Nginx 或抓包)开启 debug 日志,搜索
client sent server name确认值 - 或在 Nginx 机器上用 OpenSSL 手动模拟:
openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts
观察是否能拿到正确证书,再对比经 Nginx 代理后的结果。
不复杂但容易忽略。











