必须在composer.json的repositories中配置options.ssl.cafile字段并指定pem格式自签名证书的绝对路径,相对路径、波浪号、二进制证书、缺中间链、权限不足或系统时间偏差超2分钟均会导致ssl校验失败。

私有仓库用自签名证书时,composer install 报 SSL certificate problem
不是 Composer 不认你,是它根本没看到你的证书。必须在 composer.json 的 repositories 里显式告诉它“该信谁”。
-
options.ssl.cafile是唯一可靠字段,值必须是 PEM 格式证书的绝对路径(比如/etc/ssl/certs/internal-ca.pem),相对路径、波浪号(~/)或环境变量都会失败 - 证书文件不能是 PFX、DER 或 CRT 二进制格式,得是 Base64 编码的 PEM,且必须包含完整链:根 CA + 所有中间 CA;缺一级,OpenSSL 就会拒绝握手
- Windows 路径写成
C:/certs/internal-ca.pem或C:\certs\internal-ca.pem,单反斜杠(C:certsinternal-ca.pem)会被 PHP 解析为转义字符,导致路径无效 - 该配置只对当前仓库生效,不影响 packagist.org 或其他源;若项目里有多个私有源,每个都得单独配
options.ssl.cafile
composer config -g cafile 和 secure-http=false 为什么不管用
这两个命令解决的是不同层面的问题,混用反而容易掩盖真实故障点。
-
composer config -g cafile只影响 Composer 自己封装的 HTTP 客户端(基于 php-http),但 Git 克隆、插件调用、或某些 vendor 包的 post-install-cmd 脚本仍走原生 cURL/Stream,完全不走这个配置 -
secure-http=false实际作用是允许 Composer 接受 HTTP 协议的仓库地址,但它**不跳过证书校验**;而你的私有仓库仍是 HTTPS,所以设了也没用 - 更危险的是:如果全局
cafile指向一个损坏或过期的证书包,而项目级options.ssl.cafile因路径错/权限不足失效,Composer 会 fallback 到那个坏包,报错信息却一模一样,极难定位
Docker 构建中证书路径存在但依然报错的常见原因
容器里 ls -l /path/to/internal-ca.pem 看起来一切正常,composer install 还是失败——大概率是权限或依赖缺失。
- PHP 进程必须有读权限:Alpine 镜像默认用户是
www-data或nonroot,COPY 进去的证书默认属主是root,需加RUN chmod 644 /app/certs/internal-ca.pem - Alpine 必须先装系统级 CA 包:
apk add --no-cache ca-certificates要在composer config或composer install之前执行,否则openssl_get_cert_locations()返回的default_cert_file是空的 - 别用
VOLUME或tmpfs挂载证书路径:Composer 启动时就读取一次证书文件,挂载卷内容变化后不会自动 reload - 检查是否用了多阶段构建:证书文件只 COPY 到 builder 阶段,但 final 阶段没再 COPY,导致运行时路径存在但文件为空
Mac / Windows 下最容易被忽略的干扰项:系统时间偏差
看到 certificate has expired 别急着换证书,先看时间——偏差超 2 分钟就会触发 OpenSSL 拒绝连接,现象和证书错误一模一样。
- macOS:运行
sudo sntp -s time.apple.com(Catalina+)或sudo ntpdate -u time.apple.com(旧版),同步后立刻重试composer install - Windows:管理员运行
w32tm /resync;若失败,先net start w32time,再指定源:w32tm /config /syncfromflags:manual /manualpeerlist:"time.nist.gov" - 验证是否生效:
date输出与 time.is 对比,误差必须控制在 ±90 秒内
options.ssl.cafile 就形同虚设。尤其在 CI/CD 流水线里,不同节点时间不同步、Docker 镜像基础层不一致,问题往往只在某个环境复现,查起来特别费时间。











