Satis 不是开箱即用的服务,它生成静态文件,需搭配 Web 服务器、客户端显式声明私有源并禁用 packagist.org 才能真正走私有源;漏任一环节会导致 composer install 静默回退至官方源或报 404。

直接说结论:Satis 不是开箱即用的服务,它生成的是一堆静态文件,必须配对 Web 服务器 + 客户端显式声明 + 禁用 packagist.org 才能真正走私有源。漏掉任一环节,composer install 就会静默 fallback 到官方源或报 404。
为什么 packages.json 访问 404 或返回 text/plain?
Nginx 配置错位是最常见原因,Satis 本身不启动服务,全靠 Web 服务器正确暴露文件。
-
root必须精确指向satis.json中output-dir的绝对路径 +/web子目录(例如"output-dir": "/var/www/satis"→ Nginxroot /var/www/satis/web;),多一级或少一级都会 404 - 必须显式声明 JSON MIME 类型:
types { application/json json; },否则默认返回text/plain,Composer 拒绝解析并静默失败 - 镜像 URL 必须以
/结尾(如"url": "https://pkgs.internal/"),否则 Composer 会拼出https://pkgs.internalpackages.json - 用
curl -I https://pkgs.internal/packages.json检查响应头,确认Content-Type: application/json和HTTP/2 200
客户端 composer.json 怎么写才真正生效?
私有源声明不是可选配置,而是强制开关。写错位置、少字段、顺序不对,都等于没写。
- 必须写在你要装包的那个项目的
composer.json顶层repositories数组里,不是 Satis 自己的配置文件 - 必须包含
"packagist.org": false,且作为顶层字段(和repositories并列),不能嵌套在某个仓库对象内部 - 私有源必须放在
repositories数组第一位,Composer 按顺序查找,不会合并同名源 -
type必须是"composer",url是托管packages.json的根地址(含末尾/)
为什么 composer install 还在下载 GitHub ZIP?
因为 composer.lock 里硬编码了原始 dist.url,Satis 生成的新 ZIP 地址根本没被读取。
-
composer config -g repo.packagist对 Satis 无效——它只改元数据入口,不更新dist.url - 必须删掉
vendor/和composer.lock,再跑composer install(不是update),否则仍复用旧 lock 文件里的哈希与外网路径 - 验证是否接管成功:
composer show vendor/package --verbose,看输出中的dist.url是否指向你的内网地址(如https://pkgs.internal/dist/...) - dist ZIP 文件路径必须能被 HTTP 直连 GET,常见拦截点:SELinux 限制、Nginx
deny all、文件权限为600
satis build 后什么都没生成或包数量为 0?
构建失败往往不报红字,而是静默跳过,导致生成的 packages.json 为空或缺失关键包。
- 目标 Git 仓库根目录下必须有合法
composer.json,且name字段只能含小写字母和短横线(如"name": "myorg/utils"),不能有大写或下划线 -
version字段不要手动写"dev-main",应删除该字段,让 Satis 从 Git tag 自动推断 -
repositories列表不能是空数组,也不能写"*/*"—— Satis 不支持无限制抓取,必须明确列出 VCS 地址或用require精确指定包名 - 若用 GitHub,注意 API 限流:加
"github-protocols": ["https"],或设环境变量GITHUB_TOKEN
最易被忽略的是 dist ZIP 的可访问性:即使 packages.json 能正常返回,只要 ZIP 文件路径返回 403/404,composer install 就会在 Downloading 阶段卡死,且错误提示极不明显。











