satis是最可控轻量的私有源方案,但satis.json结构错误、repositories漏配或未禁用packagist.org任一失误,均导致composer静默走外网;它仅生成静态文件,需web服务器托管并客户端显式声明源且禁用packagist.org。

直接搭 Satis 是最可控、最轻量的私有源方案,但satis.json写错、repositories配漏、packagist.org没关——三者任一出错,Composer 都会静默走外网,你根本收不到报错。
用 Satis 生成静态 packages.json
Satis 不是服务进程,它只是一次性生成静态 JSON 文件的工具,部署到 Nginx/Apache 就能当 Composer 源用。
-
composer global require composer/satis安装(确保全局 bin 可执行) - 写
satis.json:必须用顶层数组声明"repositories",每个元素是完整对象,例如{"type": "vcs", "url": "https://git.internal/utils.git"};不能写成字符串数组 -
"require-all": true和"require": {}不能共存;前者拉所有 tag/branch,后者只拉指定包名+版本约束 -
"output-dir"强烈建议用绝对路径(如/var/www/satis),相对路径在不同工作目录下易解析失败 - 运行
php bin/satis build satis.json web/,检查输出是否含Writing packages.json,且web/packages.json能被curl -I https://satis.example.com/packages.json返回 HTTP 200
客户端 composer.json 必须显式接管
哪怕 Satis 已跑通,客户端不改配置,Composer 仍 100% 先连 packagist.org。
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
-
"repositories"数组第一项必须是:{"type": "composer", "url": "https://satis.example.com/"}(注意结尾/) - 必须和
"repositories"同级写:"packagist.org": false;写成"packagist"、"repositories.packagist"或塞进"config"里都无效 - 不要动全局
~/.composer/config.json里的"packagist.org": false——它不作用于项目级composer install - 验证是否生效:
composer config repositories应只显示你的私有地址,且不含https://repo.packagist.org
Git 仓库本身要合规才能被 Satis 收录
Satis 不校验内容,只按规则扫描;包名不合法、composer.json 缺字段,它就直接跳过,还不报错。
- Git 仓库根目录必须有合法
composer.json,其中"name"字段必须全小写、仅含字母/数字/短横线(如acme/utils),不能是MyUtils或acme_utils - 若用
"require-all": true,仓库至少得打一个 Git tag(如v1.0.0)或有main分支;否则 Satis 认为“无可用版本”,不写入packages.json - 如果要用分支名安装(如
"acme/utils": "dev-main"),composer.json中"version"字段可省略,但分支必须存在且含有效代码 - Web 服务器需正确配置 MIME 类型:
application/json对应.json,application/zip对应.zip;Nginx 需加types { application/json json; application/zip zip; }
发布私有包只需 push + tag,无需手动上传
私有包不是“上传”到 Satis,而是 Satis 定期从 Git 拉取;你只要保证 Git 仓库可访问、有合规 composer.json、打了 tag 就行。
- 开发完后,在 Git 仓库执行:
git tag v1.2.0 && git push --tags - 下次运行
satis build,该 tag 就会出现在packages.json里 - 项目中
require时写"acme/utils": "^1.2"即可,Composer 会自动匹配到 Satis 生成的 dist ZIP - 如果 ZIP 下载失败,先检查
"archive": {"prefix-url": "https://satis.example.com"}是否与实际部署地址完全一致(协议、端口、大小写、斜杠)
最容易被忽略的是:Satis 构建成功 ≠ 客户端能用;packages.json 返回 200 ≠ Composer 会读它——必须三要素齐备:type 为 composer、URL 末尾带 /、packagist.org 显式关掉。少一个,就等于没配。










