nginx https故障排查需分层定位:服务端连接失败(证书链、tls版本、时间偏差)、代理后端失败(sni未开、proxy_ssl_server_name缺失)、静态资源403/404(location匹配、root/alias混淆、selinux权限)。

排查 Nginx HTTPS 疑难杂症,不能只盯着证书是否“能亮小锁”,而要按请求链路分层定位:是客户端连不上 Nginx(服务端问题),还是 Nginx 连不上后端(代理客户端问题),又或是静态资源路径/权限/匹配逻辑出错(HTTP 服务层问题)。抓包不是万能的起点,而是验证假设的关键手段。下面从三个最易混淆的方向切入,直击高频故障根因。
一、先看 error.log,锁定握手发生在哪一端
打开 /var/log/nginx/error.log,搜索 SSL_do_handshake() failed,重点看紧邻错误行的上下文:
- 含 to upstream → 说明 Nginx 正以 HTTPS 客户端身份连接后端失败。常见原因:后端实际监听 HTTP、SNI 未开启、proxy_ssl_name 与证书 SAN 不符、信任 CA 文件缺失或路径不可读。
- 含 client: xxx.xxx.xxx.xxx(无 upstream)→ 说明浏览器/App 连接 Nginx 服务端失败。常见原因:证书链不完整(缺中间证书)、TLS 版本或密码套件无交集、私钥权限错误(应为 600)、系统时间偏差超 5 分钟。
二、区分两类 HTTPS 流量,用 curl 和 openssl 验证
别靠浏览器刷新猜问题。用命令快速切片验证:
-
验证 Nginx 服务端是否正常:
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com -showcerts
检查输出中是否有完整的证书链,且最后一级能回溯到系统可信根(如 /etc/ssl/certs/ca-certificates.crt)。 -
验证 Nginx 到后端的 HTTPS 代理是否通:
curl -v https://backend-internal.example.com --resolve backend-internal.example.com:443:10.0.1.20
(把 IP 换成你 upstream 的真实地址)观察是否握手成功、证书域名是否匹配。若失败,再检查 Nginx 配置中是否设置了 proxy_ssl_server_name on; 和 proxy_ssl_name "backend-internal.example.com";
三、抓包聚焦关键节点,避免信息过载
Wireshark 或 Sniffmaster 抓包时,不建议全局抓,而是按角色分段:
- 在客户端侧抓:确认浏览器发出的是 TLSv1.2 还是 TLSv1.3,Client Hello 中是否带 SNI,有无立即收到 TCP RST 或 Alert 协议报文。
-
在 Nginx 服务器侧抓(仅限内网):
tcpdump -i any port 443 -w nginx-server.pcap
看是否收到 Client Hello;若没收到,问题在防火墙或负载均衡器;若收到但无 Server Hello,大概率是证书加载失败或监听配置错误。 -
在 upstream 后端侧抓:
tcpdump -i any port 443 -w backend.pcap
若完全没流量,说明 proxy_pass 写错了协议(比如写了 http:// 却该用 https://);若看到 Client Hello 但无响应,说明后端未启用 HTTPS 或拒绝了 SNI。
四、静态资源 403/404 不是证书问题,是 location 匹配陷阱
HTTPS 能打开首页但 /js/app.js 404?这不是 SSL 层的问题。典型诱因:
-
正则 location 劫持了路径:如
location ~ \.(js|css)$ { }优先级高于location /api/,导致本该转发的请求被当成静态文件本地查找,自然 404。 -
root 与 alias 混用:用
alias /data/static/;时,location /assets/ 对应物理路径就是 /data/static/;但用root /data/static;时,location /assets/ 对应的是 /data/static/assets/ —— 差一个目录层级就全错。 - SELinux 或文件权限拦截:Nginx 工作进程(如 www-data)无法读取 /var/www/html/assets/ 下的文件,即使证书全对,也会返回 403。











