根本原因是PHP cURL缺少可信根证书文件,导致SSL验证失败;应检查openssl_get_cert_locations()返回的default_cert_file路径是否有效,并优先使用系统CA包而非第三方证书文件。

Composer 连不上 Packagist 或私有仓库,报 SSL certificate problem: unable to get local issuer certificate 或 cURL error 60,根本原因不是网络不通,而是 PHP cURL 没法验证远端 HTTPS 证书链——它找不到可信的根证书(CA)文件。
确认当前 cafile 是否为空或无效
Composer 默认依赖 PHP 的 openssl.cafile 或 curl.cainfo 配置。如果这两个 ini 项没设,或指向了不存在/过期的 PEM 文件,就会失败。
执行以下命令检查真实生效路径:
php -r "print_r(openssl_get_cert_locations());"
重点关注 default_cert_file 和 default_cert_dir 的值。常见问题包括:
-
default_cert_file指向一个空文件、损坏的 PEM,或根本不存在(如/usr/lib/ssl/cert.pem在某些 Alpine 容器中压根没生成) - PHP 是从源码编译且未指定
--with-curl或--with-openssl路径,导致 CA 路径硬编码为无效值 - 系统更新了 CA 包(如 Debian 的
ca-certificates),但 PHP 没重启,仍缓存旧路径
临时修复:用 composer config 强制指定 cafile
不改 PHP 全局配置,只让 Composer 自己带证书走。推荐使用系统级 CA 包(更可靠),而不是下载单个 crt 文件:
- Debian/Ubuntu:
composer config -g repo.packagist.org.ssl.certificate-authority /etc/ssl/certs/ca-certificates.crt - CentOS/RHEL:
composer config -g repo.packagist.org.ssl.certificate-authority /etc/pki/tls/certs/ca-bundle.crt - macOS(Homebrew PHP):
composer config -g repo.packagist.org.ssl.certificate-authority /opt/homebrew/etc/ca-certificates/cert.pem
这条命令会写入全局 auth.json,等价于在 ~/.composer/auth.json 中添加:
{
"repositories": {
"packagist.org": {
"type": "composer",
"url": "https://packagist.org",
"ssl": {
"certificate-authority": "/etc/ssl/certs/ca-certificates.crt"
}
}
}
}
注意:repo.packagist.org.ssl.certificate-authority 是 Composer 2.2+ 的写法;旧版用 github-oauth 同级的 http-basic 下配 ssl.certificate-authority 不生效。
容器或 CI 环境中避免硬编码路径
Docker 构建时,/etc/ssl/certs/ca-certificates.crt 可能尚未生成(尤其 Alpine)。不要在 Dockerfile 里直接 RUN composer install,而应先确保 CA 就位:
- Alpine:
RUN apk add --no-cache ca-certificates && update-ca-certificates - Debian/Ubuntu:
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/* - 然后才运行
composer install,且不额外配cafile——靠系统默认即可
若必须覆盖,用环境变量更灵活:COMPOSER_CAFILE=/etc/ssl/certs/ca-certificates.crt composer install。这个变量优先级高于 config 和 php.ini。
别用 openssl.cafile 直接指向 curl-ca-bundle.crt
有人从 cURL 官网下载 curl-ca-bundle.crt,再在 php.ini 里写 openssl.cafile=/path/to/curl-ca-bundle.crt。这看似能过 SSL 校验,但实际埋雷:
- 该 bundle 已多年未更新,漏掉大量新根证书(比如 Let’s Encrypt 的 ISRG Root X1/X2)
- 和系统 CA 包不一致,本地
curl https://packagist.org成功,但php -r "file_get_contents('https://packagist.org')"失败 - Composer 2.5+ 默认启用
verify-peer,强制校验域名(SNI),旧 bundle 缺少中间证书会导致握手失败
永远优先用发行版维护的 CA 包路径,而不是第三方 CRT 文件。
真正要盯住的只有两件事:PHP 运行时看到的 default_cert_file 是否存在且可读;Composer 的 ssl.certificate-authority 配置是否指向同一个有效路径。其他“关 SSL”“换 HTTP”“加 -k”都是掩耳盗铃,线上环境禁用。










