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

Docker容器中React+Nginx部署问题:自定义路径无法访问

React应用Docker部署后Nginx子路径访问404问题

配置与操作步骤

Dockerfile

FROM node:16 AS builder
WORKDIR /app
COPY . /app
RUN npm ci
RUN npm run build

FROM nginx:1.23.2-alpine
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /app/dist /usr/share/nginx/html
RUN touch /var/run/nginx.pid
RUN chown -R nginx:nginx /var/run/nginx.pid /usr/share/nginx/html /var/cache/nginx /var/log/nginx /etc/nginx/conf.d
USER nginx
EXPOSE 8000
CMD ["nginx", "-g", "daemon off;"]

Nginx配置(nginx.conf)

server_tokens off;
server {
    listen       8000;
    server_name  localhost;
    location /todofastapi {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        try_files $uri /index.html;
    }
}

构建与运行命令

docker build -t react-app .
docker run --name kotek -d -p 8000:8000 react-app

问题现象

Nginx启动正常,但访问localhost:8000/todofastapi或localhost:8000/todofastapi/时显示Nginx默认404错误页面。

相关日志

/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: /etc/nginx/conf.d/default.conf differs from the packaged version
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2023/09/19 19:04:54 [warn] 1#1: the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:2
nginx: [warn] the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:2
2023/09/19 19:04:54 [notice] 1#1: using the "epoll" event method
2023/09/19 19:04:54 [notice] 1#1: nginx/1.23.2
2023/09/19 19:04:54 [notice] 1#1: built by gcc 11.2.1 20220219 (Alpine 11.2.1_git20220219) 
2023/09/19 19:04:54 [notice] 1#1: OS: Linux 5.15.49-linuxkit-pr
2023/09/19 19:04:54 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2023/09/19 19:04:54 [notice] 1#1: start worker processes
2023/09/19 19:04:54 [notice] 1#1: start worker process 29
2023/09/19 19:04:54 [notice] 1#1: start worker process 30
2023/09/19 19:04:54 [notice] 1#1: start worker process 31
2023/09/19 19:04:54 [notice] 1#1: start worker process 32
2023/09/19 19:04:54 [notice] 1#1: start worker process 33
172.17.0.1 - - [19/Sep/2023:19:04:58 +0000] "GET / HTTP/1.1" 404 548 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" "-"
2023/09/19 19:04:58 [error] 30#30: *2 "/etc/nginx/html/index.html" is not found (2: No such file or directory), client: 172.17.0.1, server: localhost, request: "GET / HTTP/1.1", host: "localhost:8000"
2023/09/19 19:04:59 [error] 30#30: *2 "/etc/nginx/html/index.html" is not found (2: No such file or directory), client: 172.17.0.1, server: localhost, request: "GET / HTTP/1.1", host: "localhost:8000"
172.17.0.1 - - [19/Sep/2023:19:04:59 +0000] "GET / HTTP/1.1" 404 548 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" "-"
172.17.0.1 - - [19/Sep/2023:19:05:03 +0000] "GET /todofastapi HTTP/1.1" 404 548 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" "-"
2023/09/19 19:05:03 [error] 30#30: *2 open() "/etc/nginx/html/index.html" failed (2: No such file or directory), client: 172.17.0.1, server: localhost, request: "GET /todofastapi HTTP/1.1", host: "localhost:8000"
2023/09/19 19:05:51 [error] 30#30: *2 open() "/etc/nginx/html/index.html" failed (2: No such file or directory), client: 172.17.0.1, server: localhost, request: "GET /todofastapi HTTP/1.1", host: "localhost:8000"
172.17.0.1 - - [19/Sep/2023:19:05:51 +0000] "GET /todofastapi HTTP/1.1" 404 548 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" "-"
2023/09/19 19:06:27 [error] 30#30: *2 open() "/etc/nginx/html/index.html" failed (2: No such file or directory), client: 172.17.0.1, server: localhost, request: "GET /todofastapi HTTP/1.1", host: "localhost:8000"
172.17.0.1 - - [19/Sep/2023:19:06:27 +0000] "GET /todofastapi HTTP/1.1" 404 548 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" "-"
172.17.0.1 - - [19/Sep/2023:19:06:27 +0000] "GET /favicon.ico HTTP/1.1" 404 548 "http://localhost:8000/todofastapi" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" "-"
2023/09/19 19:06:27 [error] 30#30: *2 open() "/etc/nginx/html/favicon.ico" failed (2: No such file or directory), client: 172.17.0.1, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "localhost:8000", referrer: "http://localhost:8000/todofastapi"
2023/09/19 19:06:29 [error] 30#30: *2 open() "/etc/nginx/html/index.html" failed (2: No such file or directory), client: 172.17.0.1, server: localhost, request: "GET /todofastapi/ HTTP/1.1", host: "localhost:8000"
172.17.0.1 - - [19/Sep/2023:19:06:29 +0000] "GET /todofastapi/ HTTP/1.1" 404 548 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" "-"

问题分析

从日志可见,Nginx尝试访问/etc/nginx/html/index.html,但静态文件实际存放在/usr/share/nginx/html,核心原因有两点:

  1. Nginx配置中try_files $uri /index.html的/index.html是绝对路径,触发Nginx使用默认根目录查找文件,而非指定的/usr/share/nginx/html。
  2. React构建未设置子路径公共路径,导致静态资源请求根路径,引发额外404。

解决方案

1. 修正Nginx配置

修改nginx.conf,确保路径匹配正确:

server_tokens off;
server {
    listen       8000;
    server_name  localhost;

    location ^~ /todofastapi {
        root   /usr/share/nginx/html;
        # 移除请求路径中的/todofastapi前缀,匹配实际文件路径
        rewrite ^/todofastapi(.*)$ $1 break;
        index  index.html index.htm;
        # 优先查找文件,找不到则返回index.html(适配React单页路由)
        try_files $uri $uri/ /index.html;
    }

    # 可选:将根路径请求重定向到子路径
    location / {
        return 302 /todofastapi/;
    }
}

或使用alias指令替换路径(效果一致):

server_tokens off;
server {
    listen       8000;
    server_name  localhost;

    location /todofastapi {
        alias   /usr/share/nginx/html;
        index  index.html index.htm;
        try_files $uri $uri/ /todofastapi/index.html;
    }
}

2. 配置React构建公共路径

根据项目构建工具设置子路径:

  • Create React App:在package.json添加homepage字段:
    "homepage": "/todofastapi/"
    
  • Vite:在vite.config.js设置base属性:
    export default defineConfig({
      base: '/todofastapi/'
    })
    

3. 重新构建运行

执行命令重新构建镜像并启动容器:

docker build -t react-app .
docker run --name kotek -d -p 8000:8000 react-app

内容的提问来源于stack exchange,提问作者Marek Kamiński

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 17:45:54