satis不是开箱即用的镜像服务,必须显式配置客户端、托管静态文件、禁用packagist.org;构建前需确认satis.json repositories列表精准、packages.json可web访问且url末尾带/、项目composer.json中声明私有源并设"packagist.org": false。

Satis 不是开箱即用的镜像服务,团队协作中必须显式配置客户端、托管静态文件、禁用 packagist.org,否则 composer install 仍会卡在公网源。
构建前必须确认三件事
很多人跑完 php bin/satis build 就以为成了,结果项目里还是走外网——问题往往出在前置没对齐:
-
satis.json中"repositories"列表必须只包含你团队真正需要的 Git 仓库(如{"type": "vcs", "url": "https://git.internal/auth-lib"}),不能写空数组或"*/*";Satis 不支持无限制抓取 - 生成的
packages.json必须放在 Web 可访问路径下(比如 Nginx 的/var/www/satis),且该目录要能被直接GET到;URL 配置末尾必须带/(如"url": "https://packages.internal/"),否则 Composer 会拼成packages.json/packages.json - 团队每个项目的
composer.json都得加这段,且"packagist.org": false不能漏:{ "repositories": [ {"type": "composer", "url": "https://packages.internal/"} ], "packagist.org": false }
satis.json 最小可用结构
团队协作不追求全量镜像,而是精准控制内部包。以下是最小但可上线的配置(注意字段位置和类型):
-
"name"和"homepage"是必需字段,homepage必须是完整 URL(如"https://packages.internal/"),它决定所有 dist 文件的下载地址前缀 -
"repositories"是顶层数组,每个元素必须是对象,不能是字符串 URL;VCS 类型需确保 Git 仓库根目录有合法composer.json,且name字段为小写+短横线(如"company/auth-sdk") - 用
"require-all": true收录全部 tag/branch;若只要稳定版,改用"require": {"company/auth-sdk": "*"},二者不可共存 - 推荐加上
"archive": {"format": "zip", "skip-dev": true},避免把dev-main这类分支打包进 dist 目录,减少体积和权限风险
Web 服务必须正确返回 packages.json 和 ZIP
Satis 构建只生成静态文件,不启动任何服务。部署后必须验证两点:
- 浏览器或
curl -I https://packages.internal/packages.json返回 HTTP 200,且Content-Type: application/json;Nginx 需加types { application/json json; } - dist 文件路径形如
https://packages.internal/dist/company-auth-sdk/1.3.0-abc123.zip,必须能直接下载;Apache/Nginx 要允许.zip后缀被公开访问,且路径权限不限制(常见坑:Nginxlocation ~ \.zip$里误加了deny all) - 如果
composer update报Package company/auth-sdk is not available,先检查该包是否真在packages.json里出现,再确认其dist.url字段拼出来的 ZIP 地址是否可访问
团队维护的关键细节
没人会每天手动跑 build,但自动化也容易踩坑:
-
satis build不支持增量更新,每次都是全量扫描;建议用 CI 脚本触发(如 Git push 到某个配置仓库后自动构建),并保留上一版output-dir备份 - Git 仓库更新了
composer.json或打了新 tag,Satis 不会自动感知——必须重跑build,这点和真实镜像服务(如 Private Packagist)有本质区别 - 团队成员本地
composer clear-cache很重要,尤其改过repositories后;缓存里还存着旧的 packagist.org 元数据,会导致行为不一致











