私有源配置不生效90%因repositories未写在项目根目录composer.json顶层或auth.json路径/权限/字段名错误;必须为顶层JSON数组,auth.json需严格匹配路径、600权限及http-basic域名键。

私有源配置不生效,90% 是因为 repositories 没写在项目根目录的 composer.json 顶层,或 auth.json 权限/位置/字段名错了一处——Composer 全程静默忽略,不报错也不提示。
repositories 必须写在项目级 composer.json 顶层
Composer 只读取你当前运行 composer require 或 composer install 的那个项目的根目录下的 composer.json,且 repositories 字段必须是 JSON 数组,直接放在最外层:
- ❌ 错误:写在私有包自己的
composer.json里(完全无效) - ❌ 错误:嵌套在
config、extra或scripts下(Composer 静默跳过) - ❌ 错误:写成对象
{"my-repo": {...}}(必须是数组[{...}, {...}]) - ✅ 正确示例:
{ "repositories": [ { "type": "composer", "url": "https://pkgs.internal/" } ], "require": { "acme/utils": "^1.0" } }
auth.json 位置、权限、字段名三者必须全对
HTTP Basic 认证失败(如 401 Unauthorized 或 Access denied)几乎从不是 token 本身失效,而是 auth.json 没被 Composer 读到:
- Linux/macOS 路径必须是:
~/.composer/auth.json(全局)或项目根目录(项目级) - Windows 路径必须是:
%APPDATA%\Composer\auth.json - 权限必须为 600:
chmod 600 ~/.composer/auth.json,否则静默忽略 - 字段名必须严格为:
http-basic,域名 key 必须和仓库 URL 的 host 完全一致(不含端口、协议、路径) - 示例(GitLab):
{ "http-basic": { "gitlab.example.com": { "username": "oauth2", "password": "glpat-xxx" } } }
vcs 类型私有仓库的 url 和 name 必须精确匹配
vcs 类型只在明确 require 同名包时触发,不参与全局搜索,且校验极严:
- URL 必须是可
git clone的地址,HTTPS 格式需带.git后缀:https://gitlab.example.com/acme/utils.git - 不能是网页地址(如
https://gitlab.example.com/acme/utils/-/tree/main) - 包名必须和私有库自身
composer.json中的name字段**逐字符一致**(包括大小写、vendor 段) - 分支版本必须加
dev-前缀:"acme/utils": "dev-main",写"main"或"*"会被当模糊匹配而失败 - 多个 vcs 仓库含同名包时,以
repositories数组中靠前的为准,后面的完全被忽略
私有源优先级 ≠ 请求转发顺序
把私有源放 repositories 第一位,并不能让 Composer “先试它再试官方源”。实际逻辑是:
- Composer 先合并所有仓库的
packages.json元数据,按数组顺序“上层覆盖下层” - 若私有源的
packages.json里没声明monolog/monolog,Composer 就不会从它下载,哪怕它排第一 - 要强制走私有源,必须:
"packagist.org": false显式禁用默认源 + 私有源能提供完整元数据(如 Satis 或 Private Packagist) - 常见误判:看到
Could not find package就以为是网络问题,其实是私有源的packages.json根本没包含该包,或dist.url指向的 ZIP 地址不可直连 GET
真正容易被忽略的是:Satis 生成的静态仓库,Nginx 必须声明 application/json MIME 类型,且镜像 URL 必须以 / 结尾;少一个斜杠,packages.json 请求会拼成 https://pkgs.internalpackages.json —— 这种错误连 curl -I 都不一定立刻暴露。











