需透传原始Host并配置proxy_ssl_name与proxy_ssl_trusted_certificate:CDN回源重写Host导致SNI错配,应启用proxy_ssl_server_name on、设proxy_ssl_name为$http_x_forwarded_host,并指定proxy_ssl_trusted_certificate信任后端证书链。
nginx)下的证书信任问题">
当请求经过 CDN 再到 Nginx,再转发至后端 HTTPS 服务时,证书信任问题往往不是单一环节出错,而是多个链路叠加导致的 TLS 握手失败、SNI 错配或证书校验被拒。核心在于:**CDN 回源行为会干扰 Host 头和 SNI,而 Nginx 默认不透传原始域名信息,后端无法选对证书;同时,若后端是自签或私有 CA 证书,Nginx 默认也不信任它。**
确保 SNI 正确传递到后端(解决“证书不匹配”)
CDN(如 Cloudflare、阿里云全站加速)回源时通常会重写 Host 头为源站配置域名(如 origin.example.com),而非用户原始访问域名(如 api.example.com)。这会导致 Nginx 的 $host 变成源站名,proxy_ssl_name 也跟着错,后端 TLS 握手时收到错误 SNI,无法选出对应证书。
- 在 CDN 控制台开启「透传原始 Host」或「保留客户端 Host」功能,使其添加
X-Forwarded-Host请求头 - Nginx 配置中启用 SNI 并动态设值:
proxy_ssl_server_name on;proxy_ssl_name $http_x_forwarded_host; - 同时建议补一句:
proxy_set_header X-Forwarded-Host $host;,方便后端日志识别真实域名
让 Nginx 信任后端 HTTPS 服务的证书(解决“SSL handshake failed”)
如果后端是内部服务(如自签证书、私有 CA 签发、或使用 mkcert 生成的证书),Nginx 默认不会信任其证书,proxy_pass https://... 会直接报 SSL certificate problem: unable to get local issuer certificate。
- 将后端证书的根 CA 或中间证书合并为 PEM 文件(如
backend-ca.crt) - 在 upstream 或 location 块中指定信任锚:
proxy_ssl_trusted_certificate /etc/nginx/certs/backend-ca.crt; - 关闭证书主机名验证(仅限内网可信环境):
proxy_ssl_verify off;
⚠️ 注意:生产外网环境严禁关闭proxy_ssl_verify,必须保持on并配全信任链
避免证书链缺失引发的客户端警告
即使 Nginx 自身能连通后端,若它对外提供 HTTPS 服务(如作为 CDN 源站),浏览器访问时仍可能提示“证书不受信任”——这常因 Nginx 配置的 ssl_certificate 文件未包含完整证书链(缺中间 CA)。
- 确认你的
.crt文件内容顺序为:站点证书 → 中间证书(可多段)→ 不含根证书 - 用命令快速检查:
openssl crl2pkcs7 -nocrl -certfile your-domain.crt | openssl pkcs7 -print_certs -noout
应输出全部证书,且末尾无报错 - 手机或 Safari 不信任?大概率是证书链拼接时混入空格、BOM 或乱码,建议用记事本逐段粘贴、手动换行、保存为 UTF-8 无 BOM 格式
验证配置是否真正生效
光改配置不验证,等于没做。关键看两点:Nginx 发出去的 SNI 是什么?它是否真能成功连接后端?
- 临时开启 Nginx debug 日志:
error_log /var/log/nginx/error.log debug;
触发一次请求后搜索client sent server name,确认日志中出现的是你期望的域名 - 用 OpenSSL 手动模拟 Nginx 行为:
openssl s_client -connect 后端IP:443 -servername api.example.com -CAfile backend-ca.crt
观察是否成功握手、返回的证书 CN 是否匹配 - 若用
curl -v https://nginx-ip测试,注意加-k仅跳过客户端校验,不能代替后端连通性验证











