私有包源代理不是配HTTP代理,而是通过Artifactory、Satis等可控中间服务提供标准Composer API;必须禁用packagist.org、显式声明type为composer的私有源URL(末尾斜杠不可少),凭据仅能通过权限600的auth.json配置。

私有包源代理 ≠ 给 Composer 加 HTTP 代理,而是让 Composer 从你可控的中间服务拉包——比如 Artifactory、Satis 或自建 Packagist 镜像。直接配 http-proxy 对私有 Git 包无效,对私有 Composer 源也只起辅助作用。
私有 Git 包必须走 vcs 类型仓库,不能靠代理“透传”
如果你的私有包托管在内网 GitLab/GitHub Enterprise,Composer 不会用 https-proxy 去连它;它走的是 Git 协议(git clone),而 Git 自己要单独配代理:
git config --global http.proxy http://127.0.0.1:3128git config --global https.proxy http://127.0.0.1:3128- Git 的 proxy 值也必须是
http://开头,即使目标是 HTTPS 地址 - 若 Git 服务器要求 NTLM 认证,同样得用
cntlm或px中转,Composer 本身不参与这层认证
私有 Composer 源(如 Artifactory/Satis)要禁用 packagist.org 并显式声明
Artifactory 或 Satis 这类服务对外暴露的是标准 Composer API(packages.json),但 Composer 默认仍会先查 packagist.org。不关掉它,私有源就形同虚设:
- 在项目
composer.json的repositories数组里,必须包含一个{"packagist.org": false}对象,且独立成项 - 私有源要写成
{"type": "composer", "url": "https://your-artifactory/artifactory/composer-remote/"}—— 注意末尾斜杠不能少 - URL 必须可被 PHP cURL 直接访问;如果 Artifactory 在内网且需代理,才轮到配 Composer 的
https-proxy(但此时代理是给 Composer 自身连 Artifactory 用的,不是给私有包用的) - 别把私有源 URL 写成网页地址(如
https://your-artifactory/webapp/#/artifacts/browse/tree/General/composer-remote),那会 404
auth.json 是唯一合法凭据入口,且权限必须为 600
私有源需要 token 或 basic auth 时,composer.json 里绝不能出现密码或 token 字符串:
- 凭据只能写进
auth.json,路径默认是~/.composer/auth.json(全局)或项目根目录下(项目级) - 文件权限必须是
600(Linux/macOS):否则 Composer 直接忽略该文件,报错提示模糊(如 “Could not parse version constraint”) - 格式必须是标准 JSON:
{"http-basic": {"your-artifactory-domain": {"username": "api-token", "password": ""}}}—— password 字段即使为空也不能省略 - Git 私有仓库的凭据也走这里,但 key 是
github-oauth或gitlab-token,不是http-basic
CI/CD 环境中 path 类型仓库最危险,别让它混进生产配置
"type": "path" 看似方便本地调试,但在 CI 构建时极易出问题:
- 路径是相对的,CI 工作目录和开发者本地不一致,
../my-private-lib很可能 404 - symlink 依赖本地文件系统权限,Docker 容器里常失效
- Composer 2.2+ 默认禁用 path 包的自动加载,除非你在该包自己的
composer.json里加"options": {"symlink": true} - 上线前务必用
composer config --unset repositories.my-path-repo清掉,再切回稳定版本的 vcs 或 composer 源
最容易被忽略的一点:私有源是否生效,不能只看 composer install 是否成功;要检查 vendor/composer/installed.json 里对应包的 dist.url 是否指向你的私有地址,而不是 https://api.github.com/... —— 否则你以为走的是私有源,实际还是直连 GitHub。











