Nginx SSL握手超时主因是方向误判,需先据error.log中“while SSL handshaking to upstream”或“client: xxx”定位是代理后端失败还是服务端接收失败;常见错误为proxy_pass协议不匹配、缺失SNI或会话复用异常。

遇到 SSL_do_handshake() failed 并伴随连接超时,核心不是调大超时时间,而是先确认 Nginx 正在和谁“握手失败”——是它作为服务端接收客户端请求时失败,还是作为客户端去连后端服务(upstream)时失败。方向错了,所有配置调整都是徒劳。
看准错误日志里的关键线索
打开 /var/log/nginx/error.log,重点找带以下关键词的行:
-
while SSL handshaking to upstream → Nginx 主动连后端 HTTPS 服务失败,问题出在
proxy_pass https://...配置环节 -
while SSL handshaking, client: xxx.xxx.xxx.xxx → Nginx 接收外部 HTTPS 请求失败,问题出在
server块的证书、TLS 版本或 OCSP 配置上
绝大多数线上故障属于前者。别急着改 ssl_handshake_timeout,先定位方向。
检查 proxy_pass 协议是否真实匹配
这是最常见也最容易被忽略的错误:Nginx 配了 https://,但后端根本没开 HTTPS。
- 如果后端监听的是 HTTP(比如 Spring Boot 默认的 8080 端口),
proxy_pass必须写成http://127.0.0.1:8080;写成https://就会强制发起 TLS 握手,而对方只认 HTTP 请求,直接返回乱码或断连,日志报wrong version number - 验证方法:在 Nginx 服务器上执行
curl -v http://127.0.0.1:8080/health和curl -v https://127.0.0.1:8080/health,看哪个能通 - 如果后端确实是 HTTPS(如自签证书的 API),优先用域名访问(
curl -vk https://api.example.com),避免直连 IP 导致 SNI 缺失和证书校验失败
启用 SNI 并显式指定服务器名
当后端是多域名 HTTPS 服务(如 K8s Ingress、Cloudflare 或 Nginx 自身反代多个站点),必须让 Nginx 在 TLS 握手时带上正确的主机名。
- 在对应
location或upstream的 proxy 段中添加:proxy_ssl_server_name on; - 如果 upstream 是 IP 地址或泛域名,还需指定具体目标主机名:
proxy_ssl_name "api.example.com"; - 同时设置 Host 头保持一致:
proxy_set_header Host "api.example.com"; - 不加
proxy_ssl_server_name on,Nginx 默认不发送 SNI 扩展,后端无法识别该选哪张证书,直接拒绝握手,报sslv3 alert handshake failure
关闭 SSL 会话复用排查状态错乱
默认开启的 proxy_ssl_session_reuse on 可能引发兼容性问题,尤其在后端重启、证书轮换或负载节点不一致时。
- 复用的旧会话 ID 已失效,但 Nginx 仍尝试复用,导致收到提前的
CCS(Change Cipher Spec)消息,报错ccs received early - 临时解决方法:在 proxy 段中加入
proxy_ssl_session_reuse off;,然后重载配置nginx -s reload - 这不是长期方案,而是快速验证是否为会话复用导致;确认后可结合后端 TLS 实现版本做针对性优化











