composer config -g repo.packagist 无效,因其仅替换元数据入口(packages.json),而 zip 包仍从原始 dist.url(如 github)下载;公开镜像不托管 zip,局域网无法直连,导致安装卡在下载环节。

局域网内无法靠“改个配置”就实现离线镜像——必须用 Satis 构建静态文件 + Nginx 托管 + 项目级显式声明,三者缺一不可。
为什么 composer config -g repo.packagist 不起作用
这条命令只替换元数据入口(packages.json),但所有 ZIP 包仍从原始 dist.url 下载,比如 https://github.com/monolog/monolog/releases/download/2.10.0/monolog-2.10.0.zip。局域网打不开 GitHub,公开镜像也不托管 ZIP 文件,结果就是 composer install 卡在下载环节,报错却无明确提示。
验证方式:运行 composer show monolog/monolog --verbose,检查输出中 dist.url 是否已指向你内网地址(如 https://pkgs.internal/dist/monolog/monolog/2.10.0/xxx.zip)。
- 全局配置仅影响元数据,不影响 dist 下载路径
- 私有包(如
internal/auth-sdk)完全绕过镜像,直连你composer.json里写的 URL 或 Git 地址 - 若未显式声明私有源,Composer 根本不会查它,直接报
Could not find package
Satis 构建静态镜像的三个硬性条件
Satis 是唯一轻量、稳定、真正可用的局域网方案。它不跑服务、不依赖数据库,只生成静态文件(packages.json + dist/*.zip),扔到 Nginx 就能被所有机器访问。但以下三点漏掉任意一个,composer install 就会失败:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
-
"require-all": true—— 否则只同步项目composer.json中显式require的包,其他 tag、dev 分支、历史版本全丢 -
"archive"块必须完整:{"directory": "dist", "format": "zip", "skip-dev": true}—— 缺这个,CI 构建时只能走git clone,而内网往往禁用 git 协议 -
repositories必须是对象数组,每个私有仓库要单独声明类型,例如:{"type": "vcs", "url": "https://gitlab.internal/internal-sdk"}—— 写成字符串 URL 或漏掉type,Satis 构建时直接跳过
Nginx 配置常被忽略的关键项
Satis 生成完文件后,Nginx 暴露方式不对,照样 404。不是网络不通,是 Web 服务没对路:
-
root必须精确指向satis.json中output-dir的路径,例如:root /var/www/satis/web; - 必须显式声明 JSON MIME 类型:
types { application/json json; },否则返回text/plain,Composer 拒收 - 镜像 URL 必须以
/结尾:"url": "https://pkgs.internal/"✅;少斜杠会拼成https://pkgs.internalpackages.json→ 404 - 检查
dist/目录下 ZIP 路径是否可直连 GET,SELinux 或文件权限常锁死该路径(ls -Z和httpd_can_network_connect需确认开启)
项目级 composer.json 怎么写才真正生效
私有源必须写在你要装包的那个项目的根级 composer.json 里,不是 Satis 自己的配置文件,也不是包自己的 composer.json:
- 类型必须是
"type": "composer",URL 是托管packages.json的根地址(含末尾/) - 务必加上
"packagist": false(不是"packagist.org": false),且放在顶层,不是嵌套在某个仓库对象内部 - 私有源必须放在
repositories数组第一位,Composer 按顺序查找,同名包不会合并,后写的会被忽略 - 漏掉任意一项,
composer require acme/utils就会报Could not find package acme/utils
最常被忽略的一点:即使 Satis 已生成了所有包,客户端仍可能报 Could not find package,本质是项目级 composer.json 没声明源,或声明位置/格式错误——Composer 不会自动 fallback 到全局镜像。










