You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解决Docker Compose中Next.js、Payload CMS与MongoDB的ECONNREFUSED错误

多容器Docker Compose环境通信问题排查与解决

问题背景

使用Docker Compose搭建Next.js(blueastowel)、Payload CMS(payload)、MongoDB(mongo)多容器环境时,遇到两个核心问题:

  1. 初始配置下,blueastowel连接payload时出现ECONNREFUSED ::1:3001错误
  2. 修改环境变量后文本可加载,但前端无法获取媒体资源,提示ERR_NAME_NOT_RESOLVED(无法解析payload:3000地址)

初始错误日志

blueastowel-1  | TypeError: fetch failed
blueastowel-1  |     at node:internal/deps/undici/undici:12618:11
blueastowel-1  |     at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
blueastowel-1  |     at async u (/app/.next/server/pages/api/about-us.js:1:605) {
blueastowel-1  |   cause: Error: connect ECONNREFUSED ::1:3001
blueastowel-1  |       at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1555:16)
blueastowel-1  |       at TCPConnectWrap.callbackTrampoline (node:internal/async_hooks:128:17) {
blueastowel-1  |     errno: -111,
blueastowel-1  |     code: 'ECONNREFUSED',
blueastowel-1  |     syscall: 'connect',
blueastowel-1  |     address: '::1',
blueastowel-1  |     port: 3001
blueastowel-1  |   }
blueastowel-1  | }

修改后媒体资源错误日志

payload:3000/media/W…at%2016.20.20.jpg:1 
 GET http://payload:3000/media/WhatsApp%20Image%202024-04-24%20at%2016.20.20.jpg net::ERR_NAME_NOT_RESOLVED

问题分析与解决方案

1. 容器端口映射混淆问题

payload容器的端口配置为3001:3000,其中:

  • 3000是容器内部服务监听的端口
  • 3001是宿主机映射的外部端口

容器间通信必须使用容器内部端口,初始配置中NEXT_PUBLIC_PAYLOAD_APP_URL=http://payload:3001错误使用了外部映射端口,导致连接失败。

2. 区分服务端与客户端环境变量

Next.js中,带NEXT_PUBLIC_前缀的环境变量会被暴露给浏览器,而浏览器无法解析Docker内部的服务名(如payload),这是媒体资源加载失败的核心原因。

修改blueastowel的环境变量,分离服务端内部通信与客户端外部访问地址:

blueastowel:
  # ...其他配置
  environment:
    - PAYLOAD_APP_URL=http://payload:3000  # 服务端内部调用Payload API用
    - NEXT_PUBLIC_PAYLOAD_PUBLIC_URL=http://localhost:3001  # 客户端浏览器访问媒体资源用
    - PAYLOAD_API_KEY=50ab8231-770c-4fb9-9ec5-e1ce67650270
    - PAYLOAD_API_SLUG=users
    - URL=http://localhost:3000
    - NODE_ENV=production

3. 确保Payload服务就绪后启动Next.js

depends_on仅保证容器启动顺序,不确保服务已就绪。添加健康检查,让blueastowel在Payload完全启动后再启动:

给payload服务添加健康检查:

payload:
  # ...其他配置
  healthcheck:
    test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
    interval: 10s
    timeout: 5s
    retries: 5

修改blueastowel的depends_on配置:

blueastowel:
  # ...其他配置
  depends_on:
    payload:
      condition: service_healthy

4. 配置Payload的外部访问地址

确保Payload返回的媒体资源URL是浏览器可访问的外部地址,在Payload的payload.config.ts中配置serverURL:

export default buildConfig({
  serverURL: process.env.PAYLOAD_PUBLIC_SERVER_URL || 'http://localhost:3001',
  // ...其他配置项
});

同时给payload容器添加对应环境变量:

payload:
  # ...其他配置
  environment:
    # ...已有变量
    - PAYLOAD_PUBLIC_SERVER_URL=http://localhost:3001

内容的提问来源于stack exchange,提问作者sayinmehmet47

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 18:13:18