composer install 报“permission denied (publickey)”是因为 git 通过 ssh 拉取私有仓库失败,需确保 ssh-agent 已加载密钥、~/.ssh/config 配置正确、composer.json 中 url 使用 git@ 格式,且私有包仓库已在根项目 repositories 中显式声明。

为什么 composer install 报错 “Permission denied (publickey)”
私有 Git 仓库(如 GitHub/GitLab 私有项目)作为 Composer 包源时,Composer 默认走 SSH 协议拉取,但本地没配好 SSH 密钥或代理就会卡在这一步。错误通常长这样:
Cloning into '/path/to/vendor/vendorname/pkg'... Permission denied (publickey). fatal: Could not read from remote repository.</p> <p>关键不是 Composer 本身的问题,而是 Git 在后台执行 <code>git clone时失败了。Composer 不会帮你管理 SSH 凭据,它只负责调用 Git。
- 确认你手动执行
git clone git@github.com:user/private-pkg.git能成功 —— 这是第一道验证 - 检查
ssh -T git@github.com是否返回 “Hi user! You've successfully authenticated…” - 如果用的是 GitLab 或自建 Gitea,把域名换成对应地址,比如
git@gitlab.example.com - 别指望
composer config --global github-oauth.github.com token能解决 SSH 场景 —— 那只对 HTTPS + OAuth 有效
如何让 Composer 正确走 SSH 并复用已有密钥
Composer 本身不处理密钥加载逻辑,它完全依赖系统级的 SSH 配置。只要 git 命令能走 SSH 拉代码,Composer 就能跟着走。
- 确保密钥已添加进 ssh-agent:
ssh-add -l能列出密钥才算生效;如果没列出来,运行ssh-add ~/.ssh/id_rsa(路径按你实际密钥位置调整) - 检查
~/.ssh/config是否存在冲突配置,比如某段写了IdentitiesOnly yes但没配IdentityFile,会导致认证跳过 - 如果公司强制走跳板机或非标准端口,必须在
~/.ssh/config中为对应 Host 显式声明Port和ProxyJump,否则 Composer 启动的子进程看不到这些 - Windows 用户注意:Git for Windows 自带的 OpenSSH 和 PowerShell 的 OpenSSH 可能不是同一套,
ssh-add加的密钥不一定被 Git Bash 识别 —— 建议统一用 Git Bash 环境操作
composer.json 里怎么写私有包才不会绕到 HTTPS
很多人误以为改 repositories 类型就能控制协议,其实真正起作用的是 url 字段的协议前缀。Composer 会原样传给 Git。
- 写成
"url": "git@github.com:user/private-pkg.git"→ 走 SSH - 写成
"url": "https://github.com/user/private-pkg.git"→ 走 HTTPS,此时需要另配git config --global credential.helper store或用 token - 别写成
"url": "github.com:user/private-pkg.git"(漏了git@)—— Git 会当成本地路径处理,报错fatal: repository 'github.com:user/private-pkg.git' does not exist - 如果私有包用了子模块,且子模块 URL 也是 SSH,记得在父仓库的
.gitmodules里也用git@格式,否则composer install后git submodule update仍会失败
CI/CD 环境下 SSH 密钥怎么安全注入
本地能跑不代表 CI 能跑。CI 环境没有交互式终端、没有持久 ssh-agent、甚至默认禁用 SSH Agent Forwarding,得手动“喂”密钥。
- GitHub Actions:用
webfactory/ssh-agentAction 注入密钥,再确保后续步骤的shell: bash继承环境变量(尤其是SSH_AUTH_SOCK) - GitLab CI:把密钥存为
CI/CD Variables(类型选 File),然后在 job 中用mkdir -p ~/.ssh && cp "$SSH_PRIVATE_KEY" ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa - 避免在
composer.json里硬编码 token 或密码 —— 不仅不安全,还会让 Composer 缓存污染,不同环境拉错版本 - 测试时加个
before_script:运行ssh -o ConnectTimeout=5 -T git@github.com || echo "SSH failed",比等composer install卡住再排查快得多
最常被忽略的一点:私有包的 composer.json 里如果写了 "type": "vcs",但没在根项目的 repositories 中显式注册该仓库,Composer 会直接跳过解析,连 SSH 连接机会都没有 —— 它根本不知道该去哪找这个包。










