cURL error 60因私有HTTPS仓库CA证书未正确配置导致,需提供完整PEM格式证书链(中间CA在前、根CA在后),通过composer config --global ssl.cafile指定路径,并确保auth.json权限为600且含有效Token。

私有HTTPS仓库报cURL error 60:CA证书没配对
直接写https://gitlab.internal.company/private/pkg.git会失败,不是URL错了,而是PHP+cURL默认不认你公司内网CA。错误里出现SSL certificate problem: unable to get local issuer certificate就说明证书链缺失。
必须让Composer加载完整的PEM格式证书链文件,且顺序是中间CA在前、根CA在后。不能用Windows双击导出的.cer,也不能手动拼接——换行符或BOM会导致静默忽略。
- 先确认证书格式:
openssl x509 -in company-ca.crt -text -noout,输出含-----BEGIN CERTIFICATE-----才是有效PEM - 如果是DER格式(比如
.cer二进制),转成PEM:openssl x509 -inform DER -in company-ca.cer -outform PEM -out company-ca.pem - 合并中间+根CA:
cat intermediate.pem root.pem > combined.pem(别用编辑器粘贴) - 全局配置生效范围最广:
composer config --global ssl.cafile /etc/ssl/certs/company-ca.pem - 验证是否读取成功:
composer config --global --list | grep ssl.cafile,输出路径必须存在且PHP进程可读(如php-fpm用www-data用户时,不能放在~/.ssh/下)
auth.json里填密码还是Token?HTTPS私有Git必须用Token
HTTPS协议下,Composer不支持交互式输入密码,也不接受git clone https://user:pass@...这种URL写法。硬编码密码到composer.json或URL里等于泄露凭证。
正确做法是把Token(GitHub PAT、GitLab Personal Access Token)和用户名写进auth.json,且该文件权限必须为600。否则Composer会跳过认证,直接报401 Unauthorized。
-
auth.json位置:全局在~/.composer/auth.json,项目级在项目根目录;优先级是项目级覆盖全局 - 内容格式必须是JSON对象,不能是数组:
{"http-basic": {"gitlab.internal.company": {"username": "token", "password": "glpat-xxx..."}}} - GitLab Token权限至少要勾选
read_api和read_repository;GitHub PAT需含reposcope - 别在CI中用
--no-interaction绕过认证——它不会触发凭据提示,只会失败
composer config --global repos.packagist不适用于私有仓库
很多人误以为改了repos.packagist就能让所有私有包走镜像,其实完全无效。这个配置只影响Packagist.org元数据请求,对vcs或composer类型私有源毫无作用。
私有仓库必须显式声明在项目级composer.json的repositories数组里,且每项必须是合法JSON对象,含"type"和"url"字段。
-
type只能是"vcs"(Git/SVN)、"composer"(Satis/Nexus)、"path"(本地路径),不能写"git"或"github" -
url必须指向Git仓库根目录(即含composer.json的那个地址),不能是网页URL,也不能带.git后缀(vcs类型下允许但非必须) - 多个私有源按数组顺序匹配,同名包以第一个为准;若想优先走私有源,把它放在
repositories最前面 - 改完
composer.json后必须运行composer clear-cache,否则旧缓存可能掩盖配置问题
为什么composer install卡在“Loading composer repositories”?
这不是网络慢,而是Composer根本没发出HTTPS请求——它在尝试解析repositories配置时就失败了。常见原因有三个:URL协议写错、type值非法、或auth.json权限不对。
尤其注意:Composer 2.5+ 对ssl.cafile加载更严格,如果路径错、格式错、权限不足,它不会报错,而是静默fallback到系统CA,然后继续报60错误。你看到的“卡住”,其实是TLS握手超时。
- 检查
composer.json里repositories是否为数组(不是对象),是否有拼写错误如repositorie或repsoitories - 运行
composer diagnose,重点看secure-http和signature verification是否都显示OK;只要一个不是,HTTPS请求就不可信 - 临时测试HTTPS连通性:
curl -v --cacert /etc/ssl/certs/company-ca.pem https://gitlab.internal.company/api/v4/projects,确认基础链路通 - 别依赖
HTTP_PROXY环境变量——Composer只认http-proxy和https-proxy两个配置项,且必须同时存在
实际最难调通的,往往是证书链顺序和auth.json权限这两处。它们不出错则一切正常,一出错就静默失败,没有明确提示指向根源。











