多域名https证书不匹配本质是tls握手时证书cn/san与访问域名不符,需同步排查四点:一查证书san是否覆盖访问域名;二查nginx server_name是否精确匹配且无默认块误配;三查ssl_certificate是否指向含域名证+中间证的fullchain.pem;四查反向代理时proxy_ssl_server_name on与proxy_ssl_name $host(或$http_x_forwarded_host)是否准确传递sni。

多域名 HTTPS 证书不匹配错误,本质是浏览器或客户端在 TLS 握手时发现服务器返回的证书中声明的域名(CN 或 SAN)与实际访问的域名对不上。Nginx 本身不生成告警,但配置偏差会让它返回错证——排查要从“证书是否覆盖”“Nginx 是否选对块”“链是否完整”“代理是否传准 SNI”四条线同步推进。
一、确认证书是否真正覆盖当前访问域名
这是最常被跳过的一步。通配符或单域名证书有明确覆盖边界:
- 用 openssl x509 -in cert.pem -text -noout | grep -A1 "Subject Alternative Name" 查看 SAN 列表,确保访问的完整域名(如 api.example.com)明确出现在其中;
- *.example.com 不覆盖 example.com(根域),也不覆盖 www.api.example.com(三级域);
- 多个子域名(如 www.example.com 和 admin.example.com)必须共存于同一张 SAN 证书中,不能靠两个 server 块分别引用两张单域名证书;
- Let’s Encrypt 用户请直接使用 fullchain.pem,别误用 cert.pem —— 后者不含中间证书,易被误判为“不匹配”。
二、检查 Nginx 是否加载了正确的 server 块
Nginx 按 server_name 匹配请求,但匹配逻辑很“机械”:
- 每个 HTTPS 域名应有独立的 server { listen 443 ssl; } 块,server_name 写全且精确,例如 server_name m.example.com mobile.example.com;;
- 避免把无关域名塞进同一个 server_name 列表——Nginx 不会“智能选证”,只会把这个块配的证书全部返回;
- 重点查第一个 listen 443 ssl 的 server 块:所有未被其他块匹配的请求(比如输错域名、DNS 解析到 IP 直连)都会落到它头上,如果它配的是 www.example.com 的证书,那访问 api.example.com 就必然报错;
- 生产环境建议加一个兜底块:server { listen 443 ssl default_server; return 444; },防止默认返回错误证书。
三、验证证书链是否完整拼接并正确加载
90% 的“证书不信任”其实是链断裂,不是域名不匹配:
- ssl_certificate 必须指向合并文件(如 fullchain.pem),顺序为:域名证书 + 中间证书(不含根证书);
- ssl_certificate_key 仍单独指向私钥,保持不变;
- 用命令实测:openssl s_client -connect example.com:443 -showcerts 2>/dev/null | grep "subject\|issuer",应看到至少两段不同 issuer 的证书输出;
- 若只看到一段,说明链缺失——检查文件内容、路径是否写错、权限是否为 nginx 可读(644)、reload 是否成功执行(nginx -t && nginx -s reload)。
四、如果是反向代理场景,重点抓 SNI 传递是否准确
当 Nginx 代理后端 HTTPS 服务(如 proxy_pass https://10.0.0.5)时,证书不匹配往往源于 SNI 没传过去:
- 必须在 location 块中启用:proxy_ssl_server_name on;
- 紧接着设:proxy_ssl_name $host;(推荐),它取标准化 Host 头(小写、无端口),比 $http_host 更可靠;
- 若经 CDN(如 Cloudflare),Host 头常被重写,此时改用:proxy_ssl_name $http_x_forwarded_host;,并确保 CDN 开启“透传原始 Host”;
- 验证是否生效:在后端服务开 debug 日志,搜索 client sent server name,确认收到的值是你期望的用户原始域名。











