必须同时配置proxy_ssl_server_name on和proxy_ssl_name $host(或$http_x_forwarded_host),否则sni不生效;仅开启前者仅启用发送能力,真正决定sni值的是后者,且需动态匹配客户端请求域名以避免多证书错配。

只写 proxy_ssl_server_name on 并不能真正开启出站 SNI 支持——它只是打开 TLS 握手时发送 Server Name 扩展的“开关”,但不指定发什么域名。SNI 是否生效,关键看 proxy_ssl_name 是否设置、设得是否正确。
必须搭配 proxy_ssl_name 才算完整启用
proxy_ssl_server_name on 本身不设值,Nginx 默认会用 proxy_pass 中写的地址(比如 https://10.0.0.100 或 https://api.internal)作为 SNI 域名。这在单证书、固定后端的场景下可能“凑合能用”,但在现代多租户、CDN 回源、云存储网关等动态场景中必然错配。
- 若后端是一个 IP 托管多个域名(如
shop-a.example.com和shop-b.example.com),SNI 错配会导致 TLS 握手失败、返回默认证书或直接中断连接 - 错误日志典型提示:
SSL_do_handshake() failed、tlsv1 alert internal error、peer closed connection in SSL handshake - 必须在同一作用域(如
location块)中同时配置:proxy_ssl_server_name on;proxy_ssl_name $host;
动态场景推荐用 $host,而非 $http_host
$host 是 Nginx 内部标准化后的 Host 值:小写、不含端口、优先取请求行 Host 头,比 $http_host 更可靠,避免因客户端带端口(如 example.com:8080)导致 SNI 发送非法字符串。
安装并运行 Aperture(Lightning Labs 的 L402 闪电反向代理),用于创建 L402 付费墙、配置付费 API 端点、为其他代理托管付费内容或测试 L402 认证流程。
- 适用于大多数按 Host 路由的微服务网关、SaaS 平台、对象存储网关
- 若请求经过 CDN(如 Cloudflare、阿里云全站加速),其常重写 Host 头为源站名(如
origin.example.com),此时$host已失真 - 应配合 CDN 开启“透传原始 Host”功能,并改用:
proxy_ssl_name $http_x_forwarded_host;
同时建议补上:proxy_set_header X-Forwarded-Host $host;
upstream 场景下 proxy_ssl_name 必须是字符串字面量
当使用 upstream 块做负载均衡(如对接多个 gateway-01.internal:443 实例),Nginx 在 SSL 握手阶段无法展开变量,$host 等变量在 upstream 内部不生效。
-
proxy_ssl_name必须写在引用upstream的location块中,且值必须是带引号的字符串,例如:proxy_ssl_name "api.tenant-a.com"; - 该值需与后端证书的 SAN(Subject Alternative Name)完全一致,大小写敏感
- 泛域名证书(如
*.storage.example.com)可填具体子域(如my-bucket.storage.example.com)
验证 SNI 是否真按预期发出
配置写对 ≠ 运行有效。必须确认 Nginx 实际 TLS 握手时发送的 SNI 值就是你期望的那个域名。
- 在上游服务器(如另一台 Nginx 或测试网关)开启 debug 日志:
error_log /var/log/nginx/error.log debug;
请求触发后,搜索日志中的client sent server name字样 - 更直接的方式:用 OpenSSL 手动模拟
openssl s_client -connect 10.0.0.100:443 -servername shop-a.example.com
观察返回证书的 CN/SAN 是否匹配该域名 - 注意:
proxy_ssl_server_name仅对proxy_pass https://生效;HTTP 回源时整套配置被忽略










