必须成对配置proxy_ssl_server_name on和proxy_ssl_name $host(或$http_x_forwarded_host),才能让nginx在静态ip反代时正确传递sni,避免tls握手失败导致502/403;仅开启前者而忽略后者仍会因sni值为ip而错配证书。

要解决静态反代(即 proxy_pass 写死 IP 地址)在 SNI 环境下报错的问题,核心不是“开启 proxy_ssl_server_name on”就万事大吉,而是必须让它和动态的 proxy_ssl_name 配合,把用户真实请求的域名准确传给后端。否则 TLS 握手阶段就失败,直接触发 502、403 或静默中断。
为什么静态 IP 反代会出 SNI 错误
当 proxy_pass https://10.0.0.100 这样写死 IP 时,Nginx 默认用这个 IP 当作 SNI 值发送——但后端一个 IP 上绑了多个 HTTPS 域名(比如 api.example.com 和 cdn.example.net),它根本无法凭 IP 匹配证书或路由。结果就是:
- 返回默认证书,浏览器提示“证书不匹配”
- TLS 握手被拒,Nginx 日志出现
SSL_do_handshake() failed - 部分云服务(如 S3 RGW、OBS)直接返回 403,而非明确提示
关键配置:必须成对启用并动态注入
不能只开开关,得告诉 Nginx “这次该发哪个域名”。配置必须放在 location 块中:
安装并运行 Aperture(Lightning Labs 的 L402 闪电反向代理),用于创建 L402 付费墙、配置付费 API 端点、为其他代理托管付费内容或测试 L402 认证流程。
-
proxy_ssl_server_name on;—— 启用 SNI 扩展发送能力 -
proxy_ssl_name $host;—— 用客户端请求头里的 Host 值作为 SNI 字段(最常用) - 若经 CDN 中转且 Host 被改写(如变成
origin.example.com),改用proxy_ssl_name $http_x_forwarded_host;,并确保 CDN 开启了“透传原始 Host”
配套必须同步处理的细节
SNI 对了,不代表一定能通。以下几项常被忽略,但直接影响成功率:
-
Host 请求头必须一致:加
proxy_set_header Host $host;,避免后端比对 SNI 和 Host 不一致而拒收 -
禁用 proxy_request_buffering:尤其代理 S3 等签名服务时,缓冲会破坏 Authorization 头字节顺序,导致 403;应设为
off -
不要用 IP 写 proxy_pass:哪怕后端是内网 IP,也建议配一个 DNS 别名(如
backend-api.internal),再在proxy_pass中使用该域名 -
验证是否生效:用
openssl s_client -connect 10.0.0.100:443 -servername api.example.com直接测试,看返回证书是否匹配
常见误区提醒
这些做法看似合理,实则无效或危险:
- 只写
proxy_ssl_server_name on,不设proxy_ssl_name→ SNI 值仍是 IP,白搭 - 写
proxy_ssl_name "static.example.com"(静态字符串),但实际请求是shop.example.com→ 域名硬编码,多租户场景直接崩 - 依赖
$http_host而非$host→ 可能含端口(如example.com:443),部分后端不接受带端口的 SNI - 生产环境长期开启
proxy_ssl_verify off→ 掩盖问题,不解决握手失败根源










