根本原因是SSH密钥未被系统Git识别,需先确保ssh -T git@host成功返回认证欢迎信息;再检查ssh-add -l是否列出密钥、~/.ssh/config中Host与URL域名完全一致且含User git、composer.json中repositories必须为type:"vcs"及完整SSH URL格式。

Composer 无法加载私有 Git 仓库,90% 的情况不是 composer.json 写错了,而是 SSH 密钥根本没被系统 Git 识别——它连尝试认证的机会都没有。
ssh -T git@host 必须成功,否则一切免谈
Composer 不处理密钥,它只调用 git clone。而 git clone 是否走 SSH、用哪把密钥、连哪个端口,全由你本地的 SSH 配置决定。所以第一步永远是手动验证底层通道:
- 运行
ssh -T git@github.com(或你的实际域名,如git@gitlab.example.com),必须看到类似Hi username! You've successfully authenticated. - 如果报
Permission denied (publickey),立刻检查:ssh-add -l是否列出密钥;没列出就执行ssh-add ~/.ssh/id_ed25519(路径按实际调整) - Windows 用户注意:
cmd和PowerShell默认不共享 SSH agent,优先用 Git Bash 执行所有命令 - CI 环境(如 GitHub Actions)需显式启动 agent 并注入密钥:
eval "$(ssh-agent -s)"+ssh-add -k ~/.ssh/id_rsa(注意权限和路径)
~/.ssh/config 必须严格匹配 URL 中的主机名
Composer 调用 git clone git@github.com:org/repo.git 时,Git 会提取 github.com 作为 Host 名去查 ~/.ssh/config。任何别名、通配符、大小写差异都会导致配置失效:
-
Host行必须和 URL 中的域名完全一致(github.com✅,gh❌,GITHUB.COM❌) - 必须包含
User git(所有主流 Git 平台 SSH 入口用户都是git) - 若用非默认密钥,必须写绝对路径的
IdentityFile,且权限为600:chmod 600 ~/.ssh/id_rsa_private - 自建 Git 服务若用非标端口(如
2222),必须加Port 2222,不能指望默认 22
composer.json 中 repositories 必须是 vcs 类型 + 完整 SSH URL
Composer 不会自动把 git@ 地址识别为可用源。它只在明确声明 "type": "vcs" 且 URL 符合 Git SSH 格式时,才触发 git clone 流程:
-
url必须是git@host:path/repo.git形式(冒号分隔,以.git结尾);git@host/path/repo.git(斜杠)会直接失败 -
type只能是"vcs",不是"git"、"package"或留空 - require 中的包名(如
"myorg/utils")必须和私有库根目录下composer.json里的"name"字段**逐字节一致**(含大小写、斜杠方向) - 版本必须显式指定分支或 tag:
"dev-main"、"dev-develop"或"1.2.0";不能用"*"或"^1.0"(Composer 无法自动解析私有库的版本约束)
缓存污染会导致“明明配好了却还是 Permission denied”
Composer 会把 VCS 包的元数据(比如 commit hash、协议类型)缓存在 composer.lock 和本地 Composer cache 里。一旦改过密钥、~/.ssh/config 或换了 Git 域名,旧缓存会让后续操作卡在 Cloning into '/tmp/xxx' 或复现老错误:
- 删掉
vendor/和composer.lock - 运行
composer clear-cache - 再执行
composer install,从头开始拉取 - 如果还失败,临时加
-vvv查看真实执行的git clone命令,确认它是否真的用了你预期的 SSH URL
最常被忽略的点:SSH 配置生效 ≠ Composer 生效。中间隔着 Git 的行为、~/.ssh/config 的精确匹配、composer.json 的类型与格式三道关卡。跳过任意一环,都会表现为“静默失败”。











