Laravel与双React应用Docker部署后Nginx刷新404问题求助
问题
将Laravel应用与两个React应用放在同一项目的不同目录,通过docker-compose编排部署。当前Nginx配置下,访问example.com会正常跳转到example.com/auth/login,但刷新该页面时出现Nginx 404错误,子域名admin.example.com也存在相同问题。
以下是docker-compose配置:
version: '3.3' services: ex-mysql: image: mysql:latest container_name: ex-mysql restart: always ports: - "3307:3306" env_file: - ./mysql/dev/mysql.env networks: - ex-net ex-app: build: context: . dockerfile: ./be/be-app.dockerfile container_name: ex-app tty: true restart: unless-stopped working_dir: /var/www/html env_file: './be/.env.dev' environment: CONTAINER_ROLE: app volumes: - ./be:/var/www/html - ./php/local/local.ini:/usr/local/etc/php/conf.d/local.ini - ./be/start.sh:/usr/local/bin/start depends_on: - ex-mysql networks: - ex-net ex-queue: build: context: ./ dockerfile: ./be/be-app.dockerfile container_name: ex-queue restart: always environment: CONTAINER_ROLE: queue working_dir: /var/www/html env_file: './be/.env.dev' volumes: - ./be:/var/www/html - ./php/dev/dev.ini:/usr/local/etc/php/conf.d/local.ini - ./be/start.sh:/usr/local/bin/start depends_on: - ex-app networks: - ex-net ex-server: image: 'nginx:stable-alpine' container_name: ex-server tty: true ports: - "80:80" - "443:443" volumes: - ./nginx/dev/nginx.conf:/etc/nginx/conf.d/default.conf:ro - ./be:/var/www/html - ./fe-admin/build:/var/www/fe-admin - ./fe-dashboard/build:/var/www/fe-dashboard - ./nginx/dev/certificates/certificate.crt:/etc/nginx/certificate.crt - ./nginx/dev/certificates/private.key:/etc/nginx/private.key depends_on: - ex-app networks: - ex-net ex-js-report: build: context: ./report/ dockerfile: report.dockerfile container_name: ex-js-report tty: true restart: always ports: - "5488:5488" volumes: - ./report/config/jsreport.config.json:/app/jsreport.config.json - ./report/data:/app/data depends_on: - ex-app networks: - ex-net ex-fe-dashboard: build: context: ./fe-dashboard/ dockerfile: fe-dashboard.dockerfile container_name: ex-fe-dashboard restart: "no" tty: true volumes: - /app/node_modules/ - ./fe-dashboard/build:/app/build - ./fe-dashboard/start.sh:/app/start.sh networks: - ex-net ex-fe-admin: build: context: ./fe-admin/ dockerfile: fe-admin.dockerfile container_name: ex-fe-admin restart: "no" tty: true volumes: - /app/node_modules/ - ./fe-admin/build:/app/build - ./fe-admin/start.sh:/app/start.sh networks: - ex-net networks: ex-net: driver: bridge
引发问题的Nginx配置:
server { client_max_body_size 250M; listen 80 default_server; server_name exmple.com; root /var/www/html/public; index index.php index.html; error_log /var/log/nginx/error.log; access_log /var/log/nginx/access.log; location ~ \.php$ { client_max_body_size 8000000M; try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass ex-app:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_connect_timeout 1200; fastcgi_send_timeout 1200; fastcgi_read_timeout 90; } location /api { try_files $uri $uri/ /index.php?$query_string; gzip_static on; } location ~ ^/ { root /var/www/fe-dashboard/; index index.html; try_files $uri $uri/ /index.html?$query_string =404; } } server { client_max_body_size 250M; listen 80; server_name admin.example.com; root /var/www/html/public; index index.php index.html; error_log /var/log/nginx/error.log; access_log /var/log/nginx/access.log; location ~ \.php$ { client_max_body_size 8000000M; try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass ex-app:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_connect_timeout 1200; fastcgi_send_timeout 1200; fastcgi_read_timeout 90; } location /api { try_files $uri $uri/ /index.php?$query_string; gzip_static on; } location ~ ^/ { root /var/www/fe-admin/; index index.html; try_files $uri $uri/ /index.html?$query_string =404; } }
解决方案
问题根源
- server_name拼写错误:第一个server块里的
exmple.com少了字母a,导致域名匹配异常。 - Nginx location匹配顺序问题:正则表达式
location ~ ^/优先级高于前缀匹配(如/api),会拦截所有请求,包括API和PHP文件请求,导致后端服务无法正常响应。 - 前端路由转发逻辑错误:React是单页应用(SPA),前端路由在浏览器端处理,刷新页面时Nginx会尝试寻找对应物理文件,找不到就返回404,需要将所有非静态资源的前端路由请求转发到
index.html。
修改后的Nginx配置
# 主域名配置(example.com) server { client_max_body_size 250M; listen 80 default_server; server_name example.com; # 修复拼写错误 error_log /var/log/nginx/error.log; access_log /var/log/nginx/access.log; # 处理API请求,转发到Laravel location /api { root /var/www/html/public; try_files $uri $uri/ /index.php?$query_string; gzip_static on; } # 处理PHP文件请求 location ~ \.php$ { root /var/www/html/public; client_max_body_size 8000000M; try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass ex-app:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_connect_timeout 1200; fastcgi_send_timeout 1200; fastcgi_read_timeout 90; } # 处理React前端静态资源 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { root /var/www/fe-dashboard/; expires 1y; add_header Cache-Control "public, immutable"; } # 处理前端路由,所有非API/PHP/静态资源的请求转发到index.html location / { root /var/www/fe-dashboard/; index index.html; try_files $uri $uri/ /index.html; # 移除=404,确保所有路由都指向index.html } } # 子域名配置(admin.example.com) server { client_max_body_size 250M; listen 80; server_name admin.example.com; error_log /var/log/nginx/error.log; access_log /var/log/nginx/access.log; # 处理API请求,转发到Laravel location /api { root /var/www/html/public; try_files $uri $uri/ /index.php?$query_string; gzip_static on; } # 处理PHP文件请求 location ~ \.php$ { root /var/www/html/public; client_max_body_size 8000000M; try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass ex-app:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_connect_timeout 1200; fastcgi_send_timeout 1200; fastcgi_read_timeout 90; } # 处理React前端静态资源 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { root /var/www/fe-admin/; expires 1y; add_header Cache-Control "public, immutable"; } # 处理前端路由,所有非API/PHP/静态资源的请求转发到index.html location / { root /var/www/fe-admin/; index index.html; try_files $uri $uri/ /index.html; # 移除=404,确保所有路由都指向index.html } }
关键修改点说明
- 修复了
server_name的拼写错误,确保域名匹配正确。 - 调整了location的顺序:将API、PHP请求的location放在前端路由的location之前,避免高优先级的前端路由规则拦截后端请求。
- 单独配置了静态资源的location,设置缓存策略提升性能,同时避免静态资源被前端路由规则拦截。
- 修改了前端路由的
try_files规则,移除=404,确保所有前端路由请求(包括刷新页面时的请求)都转发到index.html,由React路由处理。 - 每个location块明确指定对应的root路径,避免继承全局root导致路径错误。
内容的提问来源于stack exchange,提问作者Mojtaba Michael
相关产品推荐
相关产品推荐

