HTTPS握手失败需抓包定位具体断点:TCP三次握手成功后,观察ClientHello是否发出、ServerHello是否返回、有无Fatal Alert;常见原因包括防火墙拦截、证书不可信、TLS版本或密码套件不匹配、SNI配置错误。

抓包确认是哪一环节断开
HTTPS握手失败不等于网络不通,可能是证书、协议版本或SNI配置问题。直接看composer install报错往往只有“Connection failed”或“SSL handshake failed”,信息太模糊。必须用tcpdump或Wireshark抓包,过滤目标域名(如repo.packagist.org),重点观察TCP三次握手是否成功、Client Hello是否发出、Server Hello是否返回、有无Alert报文。
常见现象包括:
— Client Hello发出去后没收到任何响应(防火墙拦截或DNS解析错误)
— 收到Server Hello但立刻跟一个Fatal Alert(证书不可信或TLS版本不匹配)
— TLS 1.3握手被降级或Server不支持所选cipher suite
检查PHP cURL和OpenSSL的TLS能力
Composer底层依赖PHP的cURL扩展,而cURL又绑定系统OpenSSL。不同PHP版本默认启用的TLS版本和密码套件差异很大。运行以下命令确认实际能力:
php -r "print_r(curl_version());"
关注features字段中的CURL_VERSION_SSL和CURL_VERSION_TLSAUTH_SRP,再查OpenSSL版本:
php -r "print(openssl_version()['version']);"
关键点:
— PHP 7.2+ 默认启用TLS 1.2,但若系统OpenSSL — PHP 8.1+ 默认禁用TLS 1.0/1.1,若源站只支持TLS 1.1(极少见但存在),就会静默失败
— 某些CentOS 7自带OpenSSL 1.0.2k不支持X25519密钥交换,遇到新证书会握手失败
绕过证书验证只是临时手段,不能定位根本原因
很多人加-vvv后看到SSL certificate problem: unable to get local issuer certificate就去配curl.cainfo或改composer.json加"secure-http": false。这掩盖了真实问题:
- 如果
curl.cainfo路径写错或证书包过期(如cacert.pem超过6个月未更新),即使设了也无效 -
secure-http: false只影响HTTP源,对HTTPS repo(如packagist.org)完全不起作用 - 真正的问题常是系统CA路径未被PHP识别:用
php -r "print(openssl_get_cert_locations()['default_cert_file']);"确认PHP实际读取的CA文件路径,再检查该文件是否存在、可读、包含ISRG Root X1等当前主流根证书
用openssl s_client直连测试最可靠
这是定位握手失败最直接的方式,完全绕过Composer和cURL封装:
openssl s_client -connect repo.packagist.org:443 -servername repo.packagist.org -tls1_2
注意必须带-servername(SNI),否则Nginx/Apache可能返回默认虚拟主机证书;指定-tls1_2或-tls1_3可排除协议协商干扰。观察输出中的Verify return code(0表示证书链可信)、New, TLSv1.2, Cipher is ...(确认协议和cipher可用)。若卡在“CONNECTED(00000003)”无后续,说明TCP通但TLS层被阻断;若出现verify error:num=20:unable to get local issuer certificate,就是CA缺失或路径不对。
这个命令的结果,比Composer日志里的任何堆栈都更接近真相。很多情况下,问题出在容器镜像里没装ca-certificates包,或Alpine Linux用的是ca-certificates-bundle而非标准路径,这些细节容易被忽略。











