composer config -g repo.packagist 在宝塔/docker中不生效,是因为它仅写入当前用户(如root)的~/.composer/config.json,而宝塔以www用户、docker以runner等用户运行,读不到该配置;须用sudo -u www composer config -g ...或在对应用户上下文中执行,且键名、type、url末尾斜杠三者缺一不可,否则静默回退官方源。

局域网配置自定义 Composer 仓库,核心不是“加一个源”,而是让所有请求都落在内网地址上、且不 fallback 到 packagist.org——漏掉任一环节,composer install 仍会连外网。
为什么 composer config -g repo.packagist 在宝塔/Docker 里不生效
这条命令只写进当前用户的 ~/.composer/config.json,但宝塔用 www 用户跑 PHP,Docker 构建常以 www 或 runner 用户执行,root 下配的全局配置它根本读不到。
- 验证方式:在实际运行环境里执行
composer config -g repo.packagist,输出必须是完整 JSON,形如{"type": "composer", "url": "https://your-mirror.internal/"};空、null或还是官方地址,说明没生效 - 宝塔用户要切过去配:
sudo -u www composer config -g repo.packagist composer https://your-mirror.internal/ - Docker 中必须在对应用户上下文里执行,比如先
USER www再RUN composer config -g ... - 键名必须是
repo.packagist(不是repos.packagist),值必须含"type": "composer",URL 必须以/结尾,否则拼出的packages.json地址 404
项目级 composer.json 怎么写才真正走内网镜像
项目级配置优先级高于全局,且随代码交付,是私有化部署唯一靠谱的方式。但手写容易漏关键项,导致静默回退到外网。
- 别手动编辑
repositories数组;用命令追加:composer config repo.packagist composer https://your-mirror.internal/,它会自动 merge 进去 -
"packagist.org": false必须写在composer.json根节点(和require同级),不能嵌在repositories里 - 如果原
repositories是空数组[],命令会失败;需先手动改成对象{}再执行 - 改完立刻删掉
vendor/和composer.lock,否则旧 lock 文件里的哈希仍指向原始源,校验失败直接报错
artifact 仓库类型怎么用才不报 Could not find package
artifact 是最硬核的离线方案:完全跳过元数据请求,只按文件名查本地 .zip 或 .tar.gz。但它对命名和结构有硬性要求,错一个字符就失败。
- 包文件名必须为
vendor-name-package-name-version.zip(全小写、中划线分隔、版本号不含v前缀),例如monolog-monolog-2.13.0.zip - 压缩包内根目录下必须有
composer.json,且其中"name"和"version"字段必须与文件名完全一致 - 推荐用
composer archive --format=zip --dir=./packages/生成,它自动处理命名和结构 - 仓库配置写在
composer.json的repositories里:{"type": "artifact", "url": "./packages/"},同时顶层加"packagist.org": false - 运行前清缓存:
composer install --no-cache,否则可能从旧缓存里取错路径
离线环境下最常被忽略的三件事
不是配完就完事。最容易翻车的地方往往藏在细节里:
-
COMPOSER_DISABLE_NETWORK=1对create-project无效——这个命令设计上就强制联网,离线机上绝对不要用 - 即使禁用了 packagist.org,
composer install -v仍可能看到Downloading https://repo.packagist.org/packages.json,说明某处配置没生效(常见于项目级composer.json里残留了官方源) - 用
file://或artifact时,composer.lock里的dist.shasum必须和你本地 ZIP 文件内容完全一致,否则校验失败直接退出,不 fallback











