Nexus支持Composer仓库但需手动启用v2格式并配置content-type,Harbor原生不支持Composer协议;Satis和Private Packagist才是开箱即用的PHP私有包托管方案。

私有 Composer 仓库不是“能用就行”,而是要扛住 CI/CD 高频拉取、跨团队并发安装、镜像同步中断、权限突变等真实生产压力。选错方案,轻则 composer install 卡在 404,重则私有包被意外覆盖或泄露。
Harbor vs Nexus:谁更适合 PHP 私有包托管?
Harbor 原生不支持 Composer 协议——它本质是容器镜像仓库,哪怕你硬塞进 packages.json,也缺 /packages.json 接口、版本索引、依赖解析等关键能力,composer require 会直接失败。Nexus Repository Manager(OSS 版)虽支持 Composer 类型仓库,但默认关闭,需手动启用 Composer (v2) 格式仓库,并配置 content-type 为 application/vnd.composer.v2+json,否则返回 406 错误。
真正开箱即用的只有两类:
-
Satis:静态生成packages.json,适合包少、更新频次低(如每月一次)的场景;但不支持按需索引,新包上线必须手动php bin/satis build -
Private Packagist(商业版)或自建packagist.org克隆(如packagist/private):动态响应请求,支持 Webhook 自动同步 Git Tag,可配细粒度权限(如只读/发布/删除)、IP 白名单、漏洞扫描集成
多个私有源共存时,怎么避免 composer require 拉错包?
根本不是网络快慢的问题,是 Composer 的匹配逻辑太“刚”:它从 repositories 数组第一个开始发 HTTP GET 请求到 /packages.json,只要返回 200 + JSON 且含 {"packages":{}},就立刻锁定该源,后面所有源全跳过。
所以必须满足三个硬条件:
- 所有私有
type: "composer"源必须放在repositories数组最前面,顺序即优先级 -
{"packagist.org": false}必须作为独立对象写在数组末尾,不能合并进前一个对象里 - 每个私有源的
url必须可访问,且/packages.json路径返回的 JSON 顶层必须有packages字段(空对象{"packages":{}}也合法)
验证方式:运行 composer config repositories,输出中不能出现 https://repo.packagist.org,且应明确看到 "packagist.org": false。
vcs 类型仓库能不能当主力私有源?
不能。Git 地址(type: "vcs")只对显式声明的包生效:composer require acme/utils 会去你配的 Git 地址找这个包,但它不会参与全局元数据匹配——也就是说,laravel/framework、monolog/monolog 这类基础包,哪怕你在 vcs 里也放了一份,Composer 也不会自动切过去,除非你用 package 类型手动声明每一个。
所以 vcs 只适合临时调试、单包快速迭代,不适合做企业级统一源。常见错误是把 GitLab 地址往 repositories 里一贴,就以为全包都走内网了,结果 composer update 一半卡在 Docker Hub 上下载 phpunit。
最易被忽略的一点:私有源的健康检查不能只看 curl -I /packages.json 返回 200。得实际跑一次 composer show acme/utils,确认它能解析出 version、dist、autoload 等字段——很多私有部署漏配了 dist 下载路径或签名密钥,导致 install 阶段才爆 Failed to download acme/utils。


















