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,核心原因有两点:
- Nginx配置中
try_files $uri /index.html的/index.html是绝对路径,触发Nginx使用默认根目录查找文件,而非指定的/usr/share/nginx/html。 - 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
相关产品推荐
相关产品推荐

