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

Docker与Nginx模板配置下Proxy pass出现404错误求助

Nginx反向代理/api路径返回404(Docker容器环境,Vite dev模式正常)

问题核心

本地通过docker-compose up --build -d启动前端容器后,访问localhost:3000/api/health返回404 Not Found,但使用npm run dev(Vite开发模式)启动前端时,该接口可正常访问;相同配置在staging环境能正常运行,已尝试多种斜杠组合调整仍无效。

环境配置

nginx.conf.template配置

upstream backend {
    server localhost:5003;
}

server {
    listen       3000;
    server_name  localhost;

    root /usr/share/nginx/html;

    index index.html;

    location /api/ {
        proxy_pass http://localhost:5003/;
    }

    location / {
        try_files $uri $uri/ /index.html;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }
}

注:已添加末尾斜杠,也尝试过多种斜杠组合均无效,该文件原为模板配置,现已硬编码部分内容。

Dockerfile配置

# Use the official Node.js runtime as the base image
FROM node:18.19 AS build

# Set the working directory in the container
WORKDIR /usr/src/app

# Copy package.json and package-lock.json to the working directory
COPY package*.json ./

# Install dependencies
RUN npm ci

# Copy the entire application code to the container
COPY . .

# Build the React app for production
RUN npm run build

FROM nginx:1.25.3-alpine

# Copy the built React app to Nginx's web server directory
COPY --from=build /usr/src/app/dist /usr/share/nginx/html

COPY nginx.conf.template /etc/nginx/templates/default.conf.template

# Start Nginx when the container runs
CMD ["nginx", "-g", "daemon off;"]

Docker Compose文件

services:
  frontend:
    container_name: frontend
    env_file: .env
    restart: always
    ports:
      - 3000:3000

vite.config.js配置

import { defineConfig, loadEnv } from "vite";
import react from "@vitejs/plugin-react-swc";
import svgr from "vite-plugin-svgr";

// https://vitejs.dev/config/
export default ({ mode }) => {
  const env = loadEnv(mode, process.cwd(), "");

  return defineConfig({
    plugins: [
      react(),
      svgr({
        svgrOptions: {
          // svgr options
        },
      }),
    ],
    optimizeDeps: {
      exclude: ["js-big-decimal"],
    },
    test: {
      globals: true,
      environment: "jsdom",
    },
    server: {
      watch: {
        usePolling: true,
      },
      host: true,
      strictPort: true,
      port: env.FRONTEND_HTTP_PORT,
      proxy: {
        "/api": {
          target: env.BACKEND_SERVICE_URL,
          changeOrigin: true,
        },
      },
    },
  });
};

关键排查点与解决方案

1. Docker容器网络隔离问题(核心原因)

Vite开发模式运行在宿主机,此时localhost:5003指向宿主机上的后端服务;但前端Docker容器内的localhost指向容器自身,而非宿主机,因此Nginx无法访问到宿主机的后端服务,返回404。

针对不同后端部署场景的修复:

  • 后端运行在宿主机:
    修改Nginx配置中的proxy_pass目标,替换为宿主机的可访问IP,或者使用Docker提供的特殊域名:

    • Windows/macOS:直接用host.docker.internal代替localhost
      location /api/ {
          proxy_pass http://host.docker.internal:5003/;
      }
      
    • Linux:需要在docker-compose.yml中添加宿主机映射,再使用host.docker.internal
      services:
        frontend:
          container_name: frontend
          env_file: .env
          restart: always
          ports:
            - 3000:3000
          extra_hosts:
            - "host.docker.internal:host-gateway"
      
      同时修改Nginx的proxy_pass为http://host.docker.internal:5003/
  • 后端运行在另一个Docker容器:
    确保前端和后端容器处于同一个Docker网络,然后用后端容器的服务名/容器名代替localhost。比如后端服务名为backend,则修改Nginx配置:

    upstream backend {
        server backend:5003; # 这里用后端服务名
    }
    
    location /api/ {
        proxy_pass http://backend/; # 或者直接用http://backend:5003/
    }
    

    并在docker-compose.yml中添加网络配置,将前后端加入同一网络:

    networks:
      app-network:
        driver: bridge
    
    services:
      frontend:
        container_name: frontend
        env_file: .env
        restart: always
        ports:
          - 3000:3000
        networks:
          - app-network
      backend:
        # 后端的配置
        networks:
          - app-network
    

2. 验证配置有效性

修改配置后,重新构建并启动容器:

docker-compose down && docker-compose up --build -d

进入前端容器,测试后端连通性:

docker exec -it frontend curl http://host.docker.internal:5003/health # 对应宿主机后端
# 或
docker exec -it frontend curl http://backend:5003/health # 对应容器后端

如果curl能返回正常响应,说明网络连通,此时访问localhost:3000/api/health即可正常返回。

3. 其他可能的优化

  • 既然配置了upstream backend,建议直接使用http://backend/作为proxy_pass目标,而非重复写localhost:5003,便于后续维护。
  • 检查后端服务是否正常监听5003端口,且防火墙未限制该端口的访问。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 05:01:02