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

同网跨设备访问Docker部署前后端应用的配置问题

Docker容器化Vite+TS前端+Flask后端:同网设备无法访问后端解决方案

应用说明

这是一个简单的时间展示应用,后端将日期时间数据发送至前端展示,能正常显示日期即为运行正常。

问题详情

Docker Compose构建容器后,本地访问正常,但同网手机访问时仅前端能加载,后端无法响应。原因是前端fetch代码中生产环境的host硬编码为localhost:8000:

export const host =
  import.meta.env.MODE !== 'production'
    ? 'http://localhost:5001'
    : 'http://localhost:8000'

export const get = (
  route: string,
  callback: (response: object) => void,
  errorCallback?: (response: object) => void,
) => {
  fetch(`${host}/${route}`)
    .then((response) => response.json())
    .then(callback)
    .catch((error) =>
      errorCallback ? errorCallback(error as Error) : console.error(error),
    )
}

当手机访问时,localhost指向手机自身而非运行Docker的电脑,导致请求失败。手动将host改为电脑IP后,手机可正常访问,但这种硬编码方式不灵活。

核心问题

如何无需指定电脑IP,通过配置host变量或docker-compose.yaml,实现同网设备正常访问后端?

相关Docker文件

compose.yaml

services:
  frontend:
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      NODE_ENV: production
      TZ: America/New_York
    ports:
      - 7023:7023
    networks:
      - backend
    depends_on:
      - backend
  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile
    environment:
      NODE_ENV: production
      TZ: America/New_York
    ports:
      - 8000:8000
    networks:
      - frontend

networks:
  frontend:
  backend:

./Dockerfile(前端)

# syntax=docker/dockerfile:1

ARG NODE_VERSION=18.18.0

FROM node:${NODE_VERSION}-alpine as base
WORKDIR /usr/src/app

FROM base as deps
RUN --mount=type=bind,source=package.json,target=package.json \
    --mount=type=bind,source=package-lock.json,target=package-lock.json \
    --mount=type=cache,target=/root/.npm \
    npm ci --omit=dev

FROM deps as build
RUN --mount=type=bind,source=package.json,target=package.json \
    --mount=type=bind,source=package-lock.json,target=package-lock.json \
    --mount=type=cache,target=/root/.npm \
    npm ci
COPY . .
RUN npm run build

FROM base as final
ENV NODE_ENV production
USER node
COPY package.json .
COPY --from=deps /usr/src/app/node_modules ./node_modules
COPY --from=build /usr/src/app/dist ./dist
EXPOSE 7023
CMD npx http-server ./dist -p 7023

./backend/Dockerfile(后端)

# syntax=docker/dockerfile:1

ARG PYTHON_VERSION=3.11.4
FROM python:${PYTHON_VERSION}-slim as base

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV FLASK_ENV production
WORKDIR /app

ARG UID=10001
RUN adduser \
    --disabled-password \
    --gecos "" \
    --home "/nonexistent" \
    --shell "/sbin/nologin" \
    --no-create-home \
    --uid "${UID}" \
    appuser

RUN --mount=type=cache,target=/root/.cache/pip \
    --mount=type=bind,source=requirements.txt,target=requirements.txt \
    python -m pip install -r requirements.txt

USER appuser
COPY . .
EXPOSE 8000
CMD gunicorn 'app:app' --bind=0.0.0.0:8000

解决方案

方案1:Nginx反向代理(推荐)

通过Nginx统一对外端口,前端用相对路径请求后端,无需硬编码IP或域名,适配所有访问场景。

步骤1:修改前端代码,使用相对路径

去掉硬编码的host,直接用相对路径请求后端API:

export const get = (
  route: string,
  callback: (response: object) => void,
  errorCallback?: (response: object) => void,
) => {
  // 用相对路径,Nginx会自动转发到后端
  fetch(`/api/${route}`)
    .then((response) => response.json())
    .then(callback)
    .catch((error) =>
      errorCallback ? errorCallback(error as Error) : console.error(error),
    )
}

步骤2:更新docker-compose.yaml,添加Nginx服务

统一对外端口为80,将前端和后端的请求通过Nginx转发:

services:
  frontend:
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      NODE_ENV: production
      TZ: America/New_York
    networks:
      - app-network
    depends_on:
      - backend

  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile
    environment:
      NODE_ENV: production
      TZ: America/New_York
    networks:
      - app-network

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
    networks:
      - app-network
    depends_on:
      - frontend
      - backend

networks:
  app-network:
    driver: bridge

步骤3:创建Nginx配置文件(nginx.conf)

配置前端静态资源和后端API的转发规则:

server {
    listen 80;
    server_name _;

    # 转发前端静态资源请求到前端容器
    location / {
        proxy_pass http://frontend:7023;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # 转发/api开头的请求到后端容器
    location /api/ {
        proxy_pass http://backend:8000/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

使用方式

启动容器后,本地访问http://localhost,同网设备访问http://[电脑IP]即可正常使用,无需任何IP配置。

方案2:环境变量动态配置后端地址

通过Vite环境变量传递后端地址,启动时自动获取电脑IP,避免硬编码。

步骤1:修改前端代码,读取环境变量

export const host = import.meta.env.MODE !== 'production'
  ? 'http://localhost:5001'
  : import.meta.env.VITE_BACKEND_URL || 'http://localhost:8000'

export const get = (
  route: string,
  callback: (response: object) => void,
  errorCallback?: (response: object) => void,
) => {
  fetch(`${host}/${route}`)
    .then((response) => response.json())
    .then(callback)
    .catch((error) =>
      errorCallback ? errorCallback(error as Error) : console.error(error),
    )
}

步骤2:启动容器时传递电脑IP

在启动Docker Compose时,自动获取并传递电脑IP:

# Linux/macOS
HOST_IP=$(hostname -I | awk '{print $1}') docker-compose up -d

# Windows(PowerShell)
$env:HOST_IP=(Get-NetIPAddress -AddressFamily IPv4 | Where-Object {$_.InterfaceAlias -notlike "Loopback*"} | Select-Object -First 1).IPAddress; docker-compose up -d

步骤3:更新compose.yaml中的前端环境变量

frontend:
  build:
    context: .
    dockerfile: Dockerfile
  environment:
    NODE_ENV: production
    TZ: America/New_York
    VITE_BACKEND_URL: "http://${HOST_IP}:8000"
  ports:
    - 7023:7023
  networks:
    - app-network
  depends_on:
    - backend

原理说明

  • 方案1通过Nginx统一入口,前端请求无需关心后端地址,所有请求都通过同一个IP/域名转发,彻底解决跨设备IP问题。
  • 方案2通过环境变量动态注入电脑IP,避免硬编码,但需要启动时传递IP,灵活性不如反向代理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 21:07:02