composer的repositories配置仅指定元数据源,不接管dist.url下载路径,故无法实现反向代理;必须用nginx/caddy反代并实时重写packages.json中的dist.url字段,确保所有zip请求指向代理地址。

不能靠 Composer 自身实现“反向代理”,必须用 Nginx/Caddy 在海外或内网边缘节点上做 HTTP 层反代,并重写 dist.url 字段。
为什么 composer config repositories 不是反向代理
Composer 的 repositories 配置只定义元数据(packages.json)来源,不接管包文件(ZIP)的实际下载路径。它不支持把 A 源的包“自动同步”到 B 地址供下游拉取——所谓“反向镜像”是运维层概念,不是 Composer 协议能力。
常见误解:在 composer.json 里加一条 {"type": "composer", "url": "https://pkg-proxy-us.example.com"} 就算完成反向代理。错。这只是告诉 Composer 去那个地址读元数据,而元数据里的 dist.url 仍指向原始国内私有仓库(如 https://oss-cn-hangzhou.aliyuncs.com/xxx.zip),海外机器照样连不通。
- Composer 官方 repo 类型只有
composer、package、artifact、path,没有reverse-proxy或mirror类型 -
dist.url字段由上游仓库生成并固化在composer.lock中,Composer 不会动态改写它 - 哪怕你用
composer config切换源,只要lock里dist.url是国内地址,安装时就会直连该地址
Nginx 反代必须重写 dist.url 字段
真正起作用的是反代服务对响应体的实时改写:拿到上游返回的 packages.json 后,把其中所有 dist.url 的值从 https://oss-cn-hangzhou.aliyuncs.com/... 替换成 https://pkg-proxy-us.example.com/dist/...,再吐给 Composer。
示例 Nginx 配置片段(需启用 ngx_http_sub_module):
location /packages.json {
proxy_pass https://pkg.internal/;
sub_filter 'https://oss-cn-hangzhou.aliyuncs.com/' 'https://pkg-proxy-us.example.com/dist/';
sub_filter_once off;
sub_filter_types application/json;
}
- 必须用
sub_filter_once off,否则只替换第一个匹配项 -
sub_filter_types要显式包含application/json,否则不处理 JSON 响应 - 如果上游
dist.url是相对路径或含多个 CDN 域名,需对应加多条sub_filter - 不能只代理
/packages.json,还要代理所有被重写后的/dist/xxx.zip路径,且后端要能透传Authorization头(私有包通常需要)
dist.url 重写失败的典型报错
一旦反代没改对 dist.url,Composer 安装阶段就会直接请求原始地址,报错形式为:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
Could not fetch https://oss-cn-hangzhou.aliyuncs.com/pkg-1.2.3.zip
或更隐蔽的:
Failed to decode response: file_get_contents(): SSL operation failed(因证书不信任或域名不可解析)
- 验证方法:用
curl -v https://pkg-proxy-us.example.com/packages.json | grep dist.url,确认输出中所有 URL 都已变成代理地址 - 若
composer install -v输出里出现Downloading https://oss-cn-hangzhou.aliyuncs.com/...,说明重写未生效 - 注意:某些私有仓库返回的
packages.json是压缩过的(gzip),Nginx 需配gzip off或启用gunzip on才能正确sub_filter
CI 流水线里避免硬编码私有源 URL
GitHub Actions/GitLab CI 运行在海外,但 composer.lock 里固化了国内 dist.url,会导致构建不可靠。不能靠改 composer.json 动态注入源——那只是改元数据地址,不解决 ZIP 下载路径问题。
- 最稳做法:让 CI 使用反代后的统一域名(如
https://pkg-proxy-us.example.com),并在该域名下部署完整反代服务(含packages.json+/dist/路径) - 禁用
COMPOSER_DISABLE_NETWORK=1——它会让 Composer 直接退出,无法走反代 - 别用
file://或path类型仓库:CI 容器里没有本地路径,且不支持认证 - 敏感 Token 必须通过反代层透传,不要塞进
composer.json或环境变量暴露在日志里
真正麻烦的从来不是配置几行命令,而是确保 dist.url 在整个链路里被一致重写——漏掉一个 ZIP 地址,整个安装就卡死。这一步没法靠 Composer 自动完成,必须自己盯住响应体内容。










