Composer私有镜像库必须解决包元数据同步、签名验证、权限隔离和HTTP缓存穿透四大问题;单纯镜像packagist.org无法支持企业私有包和定制版开源包,易导致找不到包、拉取失败、签名无效等问题;推荐Satis+Nginx+Git Hook方案。

Composer 私有镜像库不能只靠 composer create-project 或简单改 repositories 就完事——它必须解决包元数据同步、签名验证、权限隔离和 HTTP 缓存穿透这四个硬问题。
为什么直接用 packagist.org 镜像不行?
企业内部 PHP 项目常含私有包(如 internal/utils)、定制版开源包(如打过 patch 的 monolog/monolog),这些不会出现在 packagist.org。单纯镜像官方源,composer install 会报 Could not find package xxx at version yyy。
常见错误现象:
- 客户端配置了镜像地址,但拉取私有包时仍走外网(因未启用
allow-plugins或未注册自定义仓库) - 私有包更新后,其他开发者
composer update拉不到最新版(因镜像未触发元数据重建) - CI 流水线偶发失败,日志显示
Invalid signature(因未配置signing-key或密钥未分发)
推荐方案:Satis + Nginx + Git Hook
Satis 是 Packagist 官方维护的静态镜像生成器,适合中小规模企业(
关键配置点:
- 在
satis.json中显式声明所有私有仓库类型:"type": "vcs"(GitLab/GitHub)或"type": "package"(本地 ZIP 包) - 必须设置
"archive": {"directory": "dist", "format": "zip", "skip-dev": true},否则 CI 构建时无法下载 dist 包 - 运行
php bin/satis build satis.json web/后,确保 Nginx 的root指向web/目录,且开启index.php和.json的 MIME 支持
示例最小 satis.json:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
{
"name": "internal-mirror",
"homepage": "https://packagist.internal",
"repositories": [
{"type": "vcs", "url": "https://gitlab.internal/utils"},
{"type": "vcs", "url": "https://gitlab.internal/api-sdk"}
],
"require-all": true,
"archive": {
"directory": "dist",
"format": "zip",
"skip-dev": true
}
}
权限与安全绕不开的三件事
PHP 生态对认证极其松散,但企业环境必须堵住漏洞:
-
auth.json不能写死在项目根目录——应通过 CI 环境变量注入,或挂载为 Docker secret;否则私有仓库凭据会随代码泄露 - Git 仓库必须禁用
http.receivepack(即关闭匿名 push),仅允许 SSH key 或 OAuth token 推送 - 所有私有包的
composer.json必须含"type": "library"和明确"license",否则 Satis 会跳过该包(默认过滤无 license 项)
客户端强制使用私有源的最简方式是全局配置:
composer config -g repos.packagist composer https://packagist.internal
注意:此命令会覆盖默认 packagist.org 源,若需保留双源,改用 composer config -g repos.0 composer https://packagist.internal 并设 "packagist.org": false。
同步延迟与缓存失效怎么破?
Satis 本身不提供实时同步,必须靠外部触发。推荐 Git Hook 方案:
- 在私有 Git 仓库的
hooks/post-receive中加入:curl -X POST https://ci.internal/webhook/satis?repo=utils - Webhook 服务收到请求后,执行
git pull && php /opt/satis/bin/satis build /opt/satis/satis.json /var/www/packagist.internal/ - Nginx 配置中添加
add_header Cache-Control "no-cache, no-store, must-revalidate";到.jsonlocation 块,防止 CDN 或浏览器缓存旧元数据
容易被忽略的是 Composer 客户端缓存:开发机上执行 composer clear-cache 后,首次 install 仍可能读到旧 packages.json,因为 Composer 默认缓存 15 分钟。临时解决可加 --no-cache,长期应统一管理 COMPOSER_CACHE_DIR 指向 NFS 共享路径并设 TTL 为 60 秒。

















