先看日志关键词:出现“no shared cipher”即套件不匹配,“unable to get local issuer certificate”则为证书链不完整;再用openssl s_client -showcerts验证服务器是否下发中间证书,或分别测试-tls1_2/-tls1_3确认协议兼容性。

直接看日志里有没有明确的协议或套件提示,再用 openssl s_client 验证实际协商结果,就能快速区分是证书链不全还是算法不匹配。
先盯住错误日志里的关键词
Apache 或 Nginx 日志中出现 SSL_do_handshake() failed 本身只是表象,关键要看它前后紧挨着的上下文:
- 如果带
no shared cipher、no ciphers available或sslv3 alert handshake failure→ 基本锁定为加密套件不匹配 - 如果出现
unable to get local issuer certificate、verify error:num=20(unable to get local issuer certificate)或日志里没报错但客户端提示“证书不受信任”→ 很可能是证书链不完整 - 如果含
unsupported protocol、TLSv1.3 is not supported→ 是TLS 版本无交集,不是证书或套件问题 - 如果错误发生在
while SSL handshaking to upstream→ 问题在 Nginx 主动连后端,重点查proxy_ssl_server_name on和后端是否要求 SNI
用 openssl s_client 直接验证握手行为
绕过应用层,用 OpenSSL 工具模拟真实连接,观察协议和证书链实际表现:
- 查协议兼容性:分别测试 TLS 1.2 和 1.3
echo | openssl s_client -tls1_2 -connect example.com:443 -servername example.com 2>/dev/null | grep "Protocol\|Cipher"echo | openssl s_client -tls1_3 -connect example.com:443 -servername example.com 2>/dev/null | grep "Protocol\|Cipher"
→ 若某版本返回空或只显示 CONNECTED 后立即断开,说明该协议被拒绝 - 查证书链是否下发完整:
echo | openssl s_client -connect example.com:443 -servername example.com -showcerts 2>/dev/null
→ 看输出中是否包含全部证书(服务器证书 + 中间 CA),末尾证书的CA IssuersURI 是否可访问 - 强制触发吊销检查(辅助判断信任链):
echo | openssl s_client -connect example.com:443 -servername example.com -crl_check 2>&1 | grep "verify error\|revoked"
→ 若报num=10:certificate has expired或num=23:certificate revoked,说明吊销状态异常;若报unable to get certificate CRL,往往因中间证书缺失导致无法定位 CRL 地址
针对性验证两件事:证书链 vs 加密套件
两者排查路径完全不同,别混在一起试:
-
怀疑证书链不全:用浏览器或
curl -v https://domain访问,看是否提示“证书不可信”;再用openssl s_client -showcerts检查服务器是否真的发了中间证书;确认SSLCertificateChainFile(Apache)或ssl_trusted_certificate(Nginx)配置正确且文件可读 -
怀疑算法不匹配:在服务端配置中临时放宽限制——比如 Apache 的
SSLCipherSuite改成DEFAULT,Nginx 的ssl_ciphers改成HIGH:MEDIUM:!aNULL:!MD5;再用s_client -cipher指定套件测试,例如:openssl s_client -connect example.com:443 -cipher 'ECDHE-ECDSA-AES128-GCM-SHA256' -servername example.com
特别注意 Nginx 代理场景的常见误判
很多问题看似是证书链问题,其实是代理配置导致的假象:
- 若
curl -v https://backend-ip:port能通,但 Nginx 代理过去就报SSL_do_handshake() failed→ 几乎可以排除证书链问题,重点查:
– 是否开启proxy_ssl_server_name on(后端多域名必需)
– 是否误启proxy_ssl_verify on却没配proxy_ssl_trusted_certificate(会导致卡在验证环节)
–proxy_ssl_protocols是否与后端支持的版本一致 - 证书链不完整通常表现为明确的
certificate verify failed,而不是静默的握手失败或超时


















