必须启用 proxy_ssl_server_name 并动态设置 proxy_ssl_name 为 $host 或 $http_x_forwarded_host,确保 sni 字段与客户端请求域名一致,否则多域名证书无法正确匹配,导致 tls 握手失败。

要让 Nginx 在反向代理 HTTPS 后端时正确匹配多域名证书,关键不是只打开 proxy_ssl_server_name,而是必须让它把用户真实请求的域名作为 SNI 字段发给后端——否则后端无法选出对应证书,TLS 握手直接失败,常见表现为 502、SSL_do_handshaking failed 或证书校验错误。
必须同时启用 SNI 并动态指定域名值
proxy_ssl_server_name on 只是开启发送 SNI 的能力,它本身不决定发什么内容。Nginx 默认用 proxy_pass 中写的地址(比如 https://10.0.0.100 或 https://backend.example.com)当 SNI 值,这在单证书场景可行,但面对一个 IP 托管多个域名(如 shop-a.com、api.b.net)时必然错配。
- 在
location块中添加:proxy_ssl_server_name on; - 紧接着配置:
proxy_ssl_name $host;(推荐)或proxy_ssl_name $http_host;,确保 SNI 值与客户端请求头中的 Host 一致 - 避免写死静态值,例如
proxy_ssl_name "api.example.com";,除非所有请求都指向同一后端域名
应对 CDN 或网关导致的 Host 失真
Cloudflare、阿里云全站加速等 CDN 回源时,常会重写 Host 头为源站配置名(如 origin.example.com),导致 $host 不再是用户原始域名,SNI 随之错配。
安装并运行 Aperture(Lightning Labs 的 L402 闪电反向代理),用于创建 L402 付费墙、配置付费 API 端点、为其他代理托管付费内容或测试 L402 认证流程。
- 在 CDN 控制台开启“透传原始 Host”功能,通常体现为传递
X-Forwarded-Host或X-Real-Host请求头 - Nginx 中改用:
proxy_ssl_name $http_x_forwarded_host; - 同时建议加上:
proxy_set_header X-Forwarded-Host $host;,方便下游服务识别真实请求来源
upstream 场景下不能用变量,必须写死 SNI 字符串
当使用 upstream 块定义后端(如负载多个网关实例),Nginx 在 SSL 握手阶段无法解析变量,$host 会被忽略或报错。
-
upstream块内只写地址,不配 SNI:upstream s3_gateway {<br> server gateway-01.internal:443;<br> server gateway-02.internal:443;<br>} - 在引用该 upstream 的
location中,必须显式写字符串:proxy_ssl_name "bucket-a.example.com";(带双引号) - 该值需与后端证书的 SAN(Subject Alternative Name)完全一致,大小写敏感;泛域名证书(
*.storage.example.com)则填具体子域(my-bucket.storage.example.com)
验证 SNI 是否真正按预期发出
配置写对 ≠ 实际生效。必须确认 TLS 握手时 Client Hello 中的 SNI 字段确实是目标域名。
- 在上游服务器(如另一台 Nginx 或测试 OpenSSL 服务端)开启 debug 日志:
error_log /var/log/nginx/error.log debug;
搜索日志中client sent server name条目,核对值是否匹配 - 更直接的方式:用 OpenSSL 模拟请求
openssl s_client -connect 后端IP:443 -servername your-domain.com
观察返回证书的 CN 或 SAN 是否与该域名一致 - 注意:
proxy_ssl_server_name仅对proxy_pass https://生效;若 CDN 实际走 HTTP 回源,该指令完全不触发










