tls握手失败源于底层协议协商问题,非composer配置错误;需同步更新openssl、ca证书路径(curl.cainfo与openssl.cafile指向同一绝对路径)、镜像源tls可信性及signature字段完整性。

为什么镜像源同步卡在 TLS 握手失败
“Connection reset by peer”不是 Composer 配置错了,而是 TLS 握手被中间设备(防火墙、代理、老旧 OpenSSL)主动中断。抓包能看到 Client Hello 发出后没收到 Server Hello,紧接着出现 TCP RST 包——这说明问题发生在操作系统或 OpenSSL 层,和 composer.json 或镜像 URL 无关。
典型现象包括:composer diagnose 报 cURL error 35,curl -v https://packagist.org/packages.json 停在 * TLS handshake,或报 SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version。这些都指向底层 TLS 协议协商失败,而非网络连通性问题。
- CentOS 7 / RHEL 7 / Windows 上旧版 PHP(如 XAMPP 自带的 OpenSSL 1.0.2k)默认不支持 TLS 1.3,而 Packagist 已强制协商该协议
- 公司 HTTPS 解密代理(Zscaler、Netskope)会拦截并重置连接,尤其在 CI/CD 环境中常见
- Docker 容器基础镜像常缺失或未更新
/etc/ssl/certs/ca-certificates.crt
PHP 的 cafile 和 curl.cainfo 必须同路径且绝对
Composer 的 HTTPS 请求由 PHP 的 cURL 扩展发起,composer config -g cafile 对实际 TLS 握手完全无效。真正起效的是 php.ini 中的两个配置项:curl.cainfo 和 openssl.cafile,二者必须指向同一份最新 CA 证书文件,且路径为绝对路径。
操作步骤:
- 下载最新
cacert.pem到本地,例如:/usr/local/etc/php/cacert.pem(macOS/Linux)或C:/php/extras/ssl/cacert.pem(Windows) - 确认 CLI 模式加载的
php.ini:运行php --ini;Web 环境还需查phpinfo()中 “Loaded Configuration File” - 在对应
php.ini末尾添加两行(注意无转义、无引号、路径绝对):curl.cainfo = "/usr/local/etc/php/cacert.pem"openssl.cafile = "/usr/local/etc/php/cacert.pem" - 改完必须关闭终端重开(CLI)或重启
php-fpm/Apache(Web),否则php -i | grep cainfo仍显示旧值
镜像源配置与 TLS 校验的耦合关系
换镜像源本身不解决 TLS 问题,反而可能掩盖它。如果你用 composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/,但阿里云镜像因同步延迟返回 404,Composer 2.2+ 会 fallback 到官方源——此时 TLS 握手失败才暴露出来。
关键点在于:镜像只代理元数据请求(packages.json、provider-*.json),而包文件(.zip)仍走官方 CDN 或镜像站独立分发链路。两条路径的 TLS 配置必须各自成立。
- 若镜像站启用了自签名证书(如私有镜像),需额外将该证书追加到
cacert.pem,不能仅靠secure-http false绕过 -
secure-http false会允许 HTTP 镜像,但直接跳过证书校验,带来中间人风险,不推荐用于生产 - 验证是否生效:运行
composer diagnose,输出中应同时有secure-http: OK和HTTPS connectivity: OK
安全镜像配置下签名验证与 TLS 的双重依赖
真正安全的镜像配置要求 TLS 可信 + 官方签名验证同时成立。如果 TLS 握手失败导致元数据无法下载,signature 字段根本拿不到,security.signature true 就形同虚设。
也就是说:composer config -g security.signature true 能防包内容篡改,但前提是 TLS 层先把原始 packages.json 安全地传回来。两者是串联关系,不是可选其一。
容易忽略的细节:
- 镜像站若未同步
signature字段(如部分停更镜像),即使 TLS 正常,Composer 也会自动降级到无校验模式 -
repos.packagist.url配置仅代理元数据,但若该 URL 的 TLS 不可信,整个签名链就断了 - 某些镜像(如
https://packagist.phpcomposer.com)已多年未更新,不提供signature,也不再维护 TLS 证书
复杂点不在命令怎么敲,而在你得同时盯住 OpenSSL 版本、CA 证书路径、镜像同步状态、以及签名字段是否存在——四个环节任一断裂,都会表现为“镜像没加速”或“安装报错”,但根因完全不同。











