ssl.cafile必须指向含中间ca与根ca的完整pem格式证书链文件,且需全局配置、绝对路径、php进程有读权限,并同步配置php.ini中curl.cainfo和openssl.cafile。

composer config --global ssl.cafile 指向的必须是 PEM 链文件,不是密钥
很多人搜“SSL证书密钥存放路径”,误以为 ssl.cafile 是用来放私钥(key.pem)或站点证书(cert.pem)的——它不是。Composer 的 ssl.cafile 只接受「根 CA + 中间 CA 合并后的 PEM 格式信任链文件」,用于验证远程 HTTPS 仓库服务器的身份,不涉及你的私钥或域名证书。
常见错误现象:
- 把
server.key或fullchain.pem直接配进ssl.cafile→ 报cURL error 60,且无明确提示 - 用 Windows 记事本保存 PEM 文件 → 插入 BOM 或换行符损坏 → OpenSSL 解析失败
- 只放了公司内网根 CA,没加中间 CA → 验证链断裂,仍失败
正确做法:
- 确认你拿到的是 PEM 编码的 CA 证书(以
-----BEGIN CERTIFICATE-----开头) - 若只有 DER 格式(如
.cer),先转:openssl x509 -inform DER -in ca.cer -outform PEM -out ca.pem - 若需合并中间 CA 和根 CA:用
cat intermediate.pem root.pem > company-ca-bundle.pem(别手写拼接) - 全局设置:
composer config --global ssl.cafile /etc/ssl/certs/company-ca-bundle.pem
php.ini 中 openssl.cafile 和 curl.cainfo 必须同时配且路径一致
Composer ≥2.5 不再只依赖 cURL,而是优先用 OpenSSL 初始化上下文。如果只配了 curl.cainfo 没配 openssl.cafile,或两者指向不同路径,就会静默忽略 ssl.cafile 配置,继续报错。
检查当前 PHP 实际读取路径:
php -r "print_r(openssl_get_cert_locations());"
重点看 ini_cafile 和 default_cert_file 是否一致、是否为绝对路径、文件是否存在且可读(ls -l /path/to/file 看大小是否 > 0 KB)。
实操建议:
- 编辑
php.ini,确保两行都存在且值相同:openssl.cafile="/etc/ssl/certs/company-ca-bundle.pem"curl.cainfo="/etc/ssl/certs/company-ca-bundle.pem" - 如果路径是符号链接(如
/etc/ssl/certs/ca-certificates.crt),用readlink -f确认真实路径,并检查权限(至少644) - 改完后重启 PHP 进程(CLI 下需新开终端;fpm 需
sudo systemctl reload php-fpm)
Git 克隆私有仓库时,composer config --global ssl.cafile 不起作用
这是最常被忽略的一点:Composer 在安装包时,若源是 Git HTTPS 地址(如 https://gitlab.example.com/acme/utils.git),实际执行的是 git clone 命令,而 Git 完全不读 composer.json 或 composer config 的任何 SSL 设置。
Git 自己走系统 cURL 或 OpenSSL,只认环境变量:
- Linux/macOS:
export GIT_SSL_CAINFO=/etc/ssl/certs/company-ca-bundle.pem(建议加到~/.bashrc或~/.zshrc) - Windows:
set GIT_SSL_CAINFO=C:\php\extras\ssl\company-ca-bundle.pem
验证是否生效:
git -c http.sslCAInfo=/etc/ssl/certs/company-ca-bundle.pem ls-remote https://gitlab.example.com/acme/utils.git
如果这步通了,但 composer install 还报错,说明问题出在 Composer 自身的 HTTP 请求(比如访问私有 Packagist 镜像),这时才轮到 ssl.cafile 和 php.ini 生效。
证书路径权限和格式比内容更常导致失败
绝大多数 “配置了却没用” 的情况,根源不在证书内容本身,而在路径或格式层面:
- PHP 进程无权读取该文件(尤其用 nginx/php-fpm 时,
www-data用户无法读/home/user/certs/)→ 放到/etc/ssl/certs/更稳妥 - 证书文件里混入空行、注释、非 PEM 文本(比如从网页复制时带了 HTML 标签)→ 用
head -n 5 company-ca-bundle.pem确认开头是标准 PEM 头 - 路径用了相对路径(如
./ca.pem)→ssl.cafile必须是绝对路径 - macOS 上 Homebrew 安装的 PHP 默认证书路径可能是
/opt/homebrew/etc/openssl@3/cert.pem,不是系统默认位置
真正卡住人的,往往不是“怎么生成证书”,而是“为什么明明指对了路径,它就是不认”。每次怀疑配置失效,优先用 ls -l 和 head 看文件本身,而不是重配一遍。











