离线Linux下composer install必须零网络请求,核心是重建信任链:联网机用官方脚本下载校验composer.phar并拷贝;禁用所有远程仓库与插件;优先复制已验证的vendor和lock文件;PHP版本及扩展须严格一致。

离线 Linux 环境下不能“配置”Composer,只能“重建它的信任链”——核心是让 composer install 在不发任何 HTTP 请求的前提下完成依赖解析、校验和 autoload 生成。
离线前必须在联网机上准备好 composer.phar
别在离线机上尝试 curl https://getcomposer.org/installer,它会直接失败。正确做法是:在一台 PHP 版本、架构(x86_64/aarch64)、扩展(openssl、zlib、mbstring)完全一致的联网 Linux 机器上执行:
- 用官方脚本下载并校验:
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"→ 核对 SHA384 哈希(官网实时提供,2026 年最新值类似e0012edf3e80...)→php composer-setup.php→php -r "unlink('composer-setup.php');" - 生成的
composer.phar直接拷贝到离线机,建议放/usr/local/bin/composer并加执行权限:chmod +x /usr/local/bin/composer - 验证:
composer --version能输出版本号,且php -m | grep -E "(openssl|zlib|mbstring)"全部存在
禁用所有远程仓库和插件行为
离线机上任何残留的 repo.packagist 配置都会导致 composer install 卡死或报 Could not fetch packages.json。必须彻底清除:
- 全局禁用 Packagist:
composer config --global repo.packagist false - 确认无其他干扰源:
composer config --global --list | grep -i repo应只返回你手动加的本地源(如有),否则删掉:composer config --global --unset repos.xxx - 临时禁用插件与脚本(非配置项,而是命令参数):
--no-plugins --no-scripts必须出现在每次install或update中;否则某些插件(如composer/installers)会在初始化时尝试联网
vendor 目录复制是最简稳方案
只要源机和目标机环境一致,直接复制 vendor/ 和 composer.lock 是最快最可靠的方式,绕过所有网络触发点:
- 源机打包前务必执行:
composer install --no-dev --optimize-autoloader,再用php -r "require 'vendor/autoload.php'; echo class_exists('Monolog\Logger') ? 'ok' : 'fail';"验证 - 离线机解压后,
vendor/必须可写(尤其vendor/composer/autoload_classmap.php),否则dump-autoload会失败 - 立即补一记:
composer dump-autoload -o—— 这不是可选步骤,是修复 symlink 权限、类映射缺失的必要操作 - 如果
composer.json里有"repositories": [{"type": "path", "url": "./my-local-pkg"}],确保该路径真实存在且含合法composer.json(含name和version)
不要依赖系统代理或 hosts 重定向
把 packagist.org 指向 127.0.0.1 或设 http_proxy 环境变量,对 Composer 完全无效:
- Composer 使用 PHP cURL 扩展直连,不走系统代理设置
-
hosts方式只会让请求返回Connection refused,而 Composer 期望的是一个能返回packages.json的 HTTP 服务 - 真正有效的“代理”是 Satis 静态镜像或
file://仓库,但它们的前提是:你已提前生成好完整元数据 + ZIP 包,且路径在离线机上可访问
最容易被忽略的一点:即使 vendor/ 和 composer.lock 都齐全,只要 PHP 小版本不一致(比如源机是 8.2.12,离线机是 8.2.10),autoload.php 中的 require 可能因扩展行为差异而静默失败——这类问题不会报错,只会在运行时抛 Class not found。


















