“Connection reset by peer”或cURL error 35是TLS握手被中间设备中断所致,非Composer故障;需先运行composer diagnose和curl -v https://packagist.org/packages.json确认TLS失败,再检查OpenSSL版本、配置cafile或php.ini中curl.cainfo/openssl.cafile。

Composer 提示 SSL 连接被重置(Connection reset by peer 或 cURL error 35),不是 Composer 崩了,也不是你配错了 composer.json,而是 TLS 握手在底层被中间设备掐断了——常见于企业内网、云主机、老旧 OpenSSL 环境,或代理强制重签证书的场景。
怎么确认是 TLS 握手失败而不是网络不通
别急着改配置,先做三件事验证根源:
- 运行
composer diagnose,盯住 “HTTPS connectivity” 和 “GitHub API connectivity” 两行,若标 ERROR 且含cURL error 35或SSL connect error,基本锁定 TLS 协商问题 - 手动测底层 cURL:
curl -v https://packagist.org/packages.json,如果也卡在* TLS handshake或直接报error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version,说明不是 DNS 或路由问题 - 查 OpenSSL 版本:
openssl version,输出为OpenSSL 1.0.2k(如 CentOS 7 默认)或更低,就几乎可以确定不支持 TLS 1.3,而 Packagist 已逐步强制要求
为什么 composer config -g secure-http false 没用
这个命令只是让 Composer 允许降级到 HTTP 源,但 packagist.org 会 301 强制跳转回 HTTPS,最终仍要走 TLS 握手——错误照旧,只是可能变成 connection reset 或 301 redirect loop。它还带来真实风险:
- 私有仓库若配置为 HTTP,依赖可能被中间人劫持
- 该设置对
cURL error 35完全无效,因为握手失败发生在协议协商层,还没到证书校验那步 - 执行后
composer install -vvv日志里依然卡在某个 HTTPS URL,毫无改善
Windows 下 curl.cainfo 配置失效的典型原因
很多 Windows 用户按教程写了 curl.cainfo = "C:phpextrassslcacert.pem",但依然报错,问题往往出在路径解析和权限上:
- 单反斜杠
在 php.ini 中会被当转义符处理,必须写成双反斜杠C:\php\extras\ssl\cacert.pem或正斜杠C:/php/extras/ssl/cacert.pem - PHP CLI 和 Web 服务(如 Apache)可能加载不同 php.ini,运行
php --ini和php -i | grep "Loaded Configuration File"必须分别确认 - 证书文件路径必须是绝对路径,且 PHP 进程有读权限;若放在用户目录(如
C:UsersMecacert.pem),某些服务账户无法访问 - 改完 php.ini 后,CLI 模式需关闭当前终端重开,Web 模式必须重启
php-fpm或 Apache,只刷新页面没用
企业内网必须配 cafile 而不是靠系统证书
公司用了自建 CA 或代理重签证书时,系统默认根证书包(如 Mozilla 的 cacert.pem)根本不管用——你浏览器能打开 packagist.org 是因为浏览器信任了公司根证书,但 PHP 的 cURL 不自动继承。
正确做法是显式告诉 Composer 用哪个内部证书:
- 拿到公司 IT 提供的 PEM 格式根证书(通常是
company-root.crt或internal-ca.pem) - 执行:
composer config -g cafile /path/to/company-root.pem(Linux/macOS)或composer config -g cafile C:\certs\company-root.pem(Windows) - 验证是否生效:
composer diagnose输出中应明确显示CA file: /path/to/company-root.pem - 注意:该配置仅作用于 Composer 自身 HTTP 客户端(php-http),不影响
git clone等操作;若项目还用 git 拉取私有包,需额外配git config --global http.sslCAInfo
真正麻烦的从来不是“怎么跳过”,而是“怎么让 TLS 握手稳稳跑通”。OpenSSL 版本、CA 路径、证书格式、进程权限、CLI/Web 配置分离——漏掉任意一环,都会在某个深夜让你对着 cURL error 35 发呆十分钟。











