Satis仅生成静态文件,必须用Nginx/Apache托管packages.json和ZIP;否则composer install必报404或“Invalid repository type”。

直接说结论: Satis 不是“服务”,它只生成静态文件;你必须用 Nginx/Apache 托管 packages.json 和 ZIP,否则 composer install 一定报 404 或 “Invalid repository type”。
为什么 composer update 报 Could not fetch packages.json,但 curl 能通
这不是网络问题,而是路径或 Web 服务器配置错位。常见原因有三个:
-
satis.json中的output-dir是绝对路径(如/var/www/satis),但 Nginx 的root没指向它,导致https://satis.example.com/packages.json实际返回 404 - Web 服务器没把
packages.json设为默认索引文件,而你访问的是根 URL(如https://satis.example.com/),它试图找index.html,但 Satis 默认不生成这个(除非你加了"archive"配置并启用了页面) -
satis.json里homepage值是https://satis.example.com,但你实际部署在子路径(如https://example.com/satis),所有 dist URL 和包元数据都会错乱
repositories 字段写在哪、怎么写才生效
它必须出现在你要装私有包的那个项目的 composer.json 里,不是 Satis 自己的配置文件。漏掉这步,composer require 就永远找不到包。
- 类型必须是
"type": "composer",URL 指向托管packages.json的根地址(例如"https://satis.example.com") - 务必加上
"packagist.org": false,否则同名包可能从官方源拉取,覆盖你的私有版本 - 顺序很重要:私有源要放在
repositories数组第一位,Composer 按顺序查找,不会合并同名包 - 别把
require写进repositories里——那是顶层字段,放错位置整个配置会被忽略
satis build 什么都没生成,或 skipping package
不是 JSON 构建失败,而是 Git 拉取或版本解析卡住了。Satis 不处理凭据,也不自动 fallback。
- HTTPS 私有仓库:运行
satis build的用户得提前执行git config --global credential.helper store并输一次密码;或者改用 token,写进satis.json的config.github-oauth - SSH 私有仓库:确保运行用户能用
ssh -T git@gitlab.com连通,且~/.ssh/config里配好了 Host 别名和 key 路径 - 包被 skip:检查目标仓库根目录下是否有合法的
composer.json;再确认是否打了符合语义化格式的 tag(v1.2.0或1.2.0),dev-main不算正式版,require-all: true也不会收录它,除非你加了"minimum-stability": "dev" -
packages.json为空:大概率是repositories里的 URL 拼错了,或对应 Git 仓库不可达(比如内网地址在构建机上 DNS 不通)
dist 下载失败,回退到 source,但 ZIP 明明生成了
Satis 生成的 ZIP 文件本身没问题,但客户端下载时失败,通常卡在 HTTP 层。
- Nginx/Apache 没配对 MIME 类型:
.zip必须返回application/zip,否则 Composer 拒绝解压 - 域名证书不被信任(尤其自签名或内网 CA):PHP cURL 默认校验证书,需在项目级加
"secure-http": false(仅限内网),或把 CA 证书加进系统信任链 -
archive.prefix-url没配对:Satis 生成的packages.json里每个包的dist.url是拼出来的,如果prefix-url少了末尾/(比如写成"https://satis.example.com/dist"而不是"https://satis.example.com/dist/"),ZIP 地址就会变成https://satis.example.com/distacme/utils-1.0.0.zip—— 缺斜杠导致路径粘连
最常被忽略的点:Satis 不支持增量更新,每次 build 都是全量重刷;如果你靠 CI 触发构建,记得清理旧 ZIP,否则磁盘会悄悄涨满。还有,auth.json 权限必须是 600,哪怕只差一位,Composer 就当它不存在。











