Satis 是静态包生成器,需配合 Git 仓库、composer.json 和定期构建才能支撑企业级离线源;离线指不依赖 packagist.org,所有包须提前拉取并固化为 dist 归档。

直接上结论:Satis 不是“配置好就能用”的现成仓库,它本质是一个静态包生成器,必须配合 Git 仓库、composer.json 清单和定期构建流程才能支撑企业级离线源;离线 ≠ 完全断网,而是指不依赖 packagist.org,所有包需提前拉取并固化为 dist 归档。
如何初始化 Satis 配置文件(satis.json)
Satis 的行为完全由 satis.json 驱动,它不是 Composer 的 config.json,也不能用 composer config 生成。必须手写,且关键字段不能遗漏:
-
name和homepage是必需的,否则生成的packages.json缺失元信息,下游composer install会报Could not parse version constraint -
repositories列表里每个仓库必须是完整 Git URL(如https://git.example.com/internal/lib-a.git),不支持本地路径或 SVN -
require-all设为true可自动抓取所有 tagged 版本;若只想要特定版本,改用require对象,例如:{"vendor/package": "1.2.*"} - 务必显式设置
archive:它决定是否生成.zip或.tar离线包,没有它,Satis 只输出packages.json,下游无法离线安装
构建时必须指定 dist 归档路径与格式
Satis 默认不下载任何代码,只生成元数据。要实现真正离线,必须让 Satis 把每个包的 dist 文件实际下载并存到本地目录。这靠 archive 配置驱动:
{
"name": "Internal Packagist",
"homepage": "https://satis.internal",
"repositories": [
{"type": "vcs", "url": "https://git.internal/lib-a.git"}
],
"require-all": true,
"archive": {
"directory": "dist",
"format": "zip",
"skip-dev": true
}
}
注意:directory 是相对于构建命令执行路径的子目录,不是绝对路径;format 只能是 zip 或 tar,不能用 tgz;skip-dev 必须设为 true,否则会尝试归档 dev-master 这类不稳定分支,导致构建失败或体积暴增。
为什么 composer install 仍报 “package not found”?检查这三点
即使 Satis 构建成功,客户端 composer install 仍可能找不到包,常见原因有:
- 客户端
composer.json中未正确声明私有源:"repositories": [{"type": "composer", "url": "https://satis.internal/"}],且url必须以/结尾,否则packages.json请求 404 - Satis 生成的
packages.json里包名大小写与客户端require不一致(如 Satis 抓到vendor/PackageA,但composer.json写了vendor/packagea),Composer 区分大小写 - Git 仓库 tag 命名不规范:Satis 只识别符合
semver的 tag(如v1.0.0、1.2.3),release-1.0或master不会被纳入require-all范围
离线环境部署的关键细节
所谓“离线”,是指客户端机器无法访问互联网,但 Satis 构建机必须能访问所有 Git 仓库和 GitHub/GitLab(用于下载 dist)。最终交付物只有两个部分:
- 整个 Satis 输出目录(含
packages.json、dist/子目录、include/等),需整体拷贝到内网 Web 服务器(如 Nginx)根目录 - 客户端机器的
composer.json中repositoriesURL 必须指向该内网地址,且确保该地址可被所有客户端 DNS 解析(不能写localhost或私有 IP 未配置 hosts) - 如果使用自签名 HTTPS 证书,客户端需提前在系统或 Composer 配置中信任该证书,否则
composer install会因 SSL 验证失败中断
最易忽略的是:Satis 不处理包依赖的递归解析——它只按你给的仓库列表或 require 列表拉取,不会自动补全这些包所依赖的第三方包(比如你的内部包依赖 monolog/monolog)。那些也得显式加进 repositories 或 require,否则离线时就缺货。










