根本原因是git底层ssh认证失败导致静默挂起,而非composer问题;必须验证ssh-t、ssh-add-l和手动git clone三步,且composer.json中url须为git@host:path.git格式并设type为"vcs"。

Composer 安装私有包卡在 Cloning into 时,根本不是 Composer 的问题
它只是调用 git clone,而 git clone 静默失败后,Composer 不会报错“SSH 密钥无效”,只会卡住、超时或降级到 HTTPS 后报一堆模糊错误(比如 Could not fetch 或 Permission denied (publickey))。真正要修的,是 Git + SSH 这一层。
必须验证三件事,缺一不可:
-
ssh -T git@your-git-host.com要输出类似Hi username! You've successfully authenticated,否则说明密钥没加载或公钥没配对 -
ssh-add -l要列出你的私钥;如果为空,运行ssh-add ~/.ssh/id_ed25519(路径按实际调整) -
git clone git@your-git-host.com:org/repo.git必须能完整拉下代码,不输密码、不中断、不报错
注意:~/.ssh/id_ed25519 权限必须是 600(chmod 600 ~/.ssh/id_ed25519),否则 ssh-add 会静默拒绝。
composer.json 中写错 URL 格式,会导致 SSH 认证完全失效
Composer 只在 url 字段值为 git@host:path.git 形式时才走 SSH 协议。任何偏差都会让 Git 自动 fallback 到 HTTPS,然后因无 token 或密码失败。
常见错误写法:
-
"url": "https://gitlab.example.com/org/repo.git"—— HTTPS 地址,SSH 密钥无效 -
"url": "git@gitlab.example.com/org/repo.git"—— 用了/,Git 会当成 HTTPS 解析 -
"url": "ssh://git@gitlab.example.com/org/repo.git"—— 多数 Git 服务不支持该格式,连接失败 -
"url": "git@gitlab.example.com:org/repo"—— 缺少.git后缀,某些 Git 版本无法识别
正确写法只有一种:"url": "git@gitlab.example.com:org/repo.git",且 "type" 必须显式设为 "vcs"。
多私有仓库共存时,靠 ~/.ssh/config 分流,别指望默认密钥
如果你同时用 GitHub、GitLab 和自建 Gitea,不能只靠 ~/.ssh/id_ed25519。必须用 ~/.ssh/config 显式指定每台主机用哪把密钥:
Host github.com User git IdentityFile ~/.ssh/github_id_ed25519 Host gitlab.example.com User git IdentityFile ~/.ssh/gitlab_id_ed25519 Host gitea.internal User git IdentityFile ~/.ssh/gitea_id_ed25519 StrictHostKeyChecking no UserKnownHostsFile /dev/null
关键点:
-
Host值必须和composer.json中 URL 的域名**逐字符一致**(gitlab.example.com≠gitlab) - 内网地址如
gitea.internal首次连接会卡在 host key 验证,加StrictHostKeyChecking no是临时解法,生产环境应预置known_hosts -
IdentityFile路径必须绝对,不能用~,得写成/home/user/.ssh/xxx
CI/CD 环境里,ssh-agent 和 known_hosts 是两个高频断点
本地能跑 ≠ CI 能跑。GitHub Actions、GitLab CI 或 Jenkins 上常因以下两点失败:
-
Could not open a connection to your authentication agent:没启动ssh-agent,需在 job 开头加eval "$(ssh-agent -s)",再ssh-add注入密钥 -
Host key verification failed:首次连接目标主机时,ssh拒绝未知 host,需提前运行ssh-keyscan your-git-host.com >> ~/.ssh/known_hosts
另外,CI 中的 PHP 进程往往以 www-data 或 runner 用户运行,和你本地用户不同——~/.ssh 目录必须属于该用户,且权限严格(700 for dir, 600 for keys)。
最易被忽略的是:SSH 密钥注入后,必须确认 ssh-add -l 在 composer install 执行前已生效;很多 CI 脚本把 ssh-add 放在单独 step,但后续 step 并不继承 agent socket,导致密钥丢失。











