需确认nginx是否启用proxy_ssl_server_name on并配合proxy_ssl_name $host,再通过后端debug日志核对client sent server name值与客户端host头是否一致,三者不一致即为sni错配根因。

直接看 Nginx 的 error_log 和 upstream 服务的 TLS debug 日志,重点比对客户端请求中 Host 头、Nginx 发出的 SNI 值、后端实际收到的 server_name 三者是否一致。Server Name 错误不是客户端“发错”,而是 Nginx 代理时没传对、或传了空值、或传了静态错误域名。
确认 Nginx 是否真正发送了 SNI
Nginx 默认不发 SNI,必须显式启用:
- 在 location 块中加 proxy_ssl_server_name on;(不能写在 http 或 upstream 块)
-
proxy_pass 必须用域名,如
https://api.example.com/;若写成 IP(如https://10.10.20.30/),SNI 字段为空 - 检查是否遗漏 proxy_ssl_name:多域名场景务必用
proxy_ssl_name $host;,确保 SNI 域名与请求 Host 头一致
验证 SNI 实际值是否准确
仅靠 Nginx 配置无法保证 SNI 正确,需实测抓取或日志佐证:
- 在后端 HTTPS 服务(如另一台 Nginx)开启 debug 日志:
error_log /var/log/nginx/debug.log debug; - 重启后端,发起一次请求,搜索日志中的
client sent server name或SSL_do_handshake行 - 对比:客户端原始请求 Host 头 → Nginx access_log 中的
$host→ 后端日志收到的 SNI 值。三者不一致即为根因
常见 Server Name 错误类型及表现
错误不在客户端,而在 Nginx 代理链路中被篡改或丢失:
-
空 SNI:proxy_pass 写 IP 或 upstream 定义未带域名,后端返回默认证书,报
SSL_ERROR_BAD_CERT_DOMAIN -
静态写死:如
proxy_ssl_name "backend.example.com";,但客户端访问的是app.example.com,导致证书 SAN 不匹配 -
Host 头被覆盖:前面有
proxy_set_header Host "xxx"且值与$host不同,而proxy_ssl_name $host仍取原始值,造成 SNI 与 Host 不一致 -
CDN 或中间层干扰:X-Forwarded-Host 被污染,需改用
proxy_ssl_name $http_x_forwarded_host;并校验其可信性
快速验证工具与命令
不用等线上报错,本地可模拟验证:
- 用 openssl 模拟客户端直连后端,强制指定 SNI:
openssl s_client -connect api.example.com:443 -servername app.example.com -showcerts
观察是否返回预期证书 - 在 Nginx access_log 中添加
"$host" "$ssl_server_name"字段(后者仅在 server 块有效,proxy 场景需靠后端日志反推) - 临时关闭会话复用:
proxy_ssl_session_reuse off;,排除因旧会话缓存导致 SNI 复用错乱的情况











