fix: nginx 根路径 301 重定向到 /emotion-museum/(修复首页 404)

This commit is contained in:
2026-06-28 23:21:03 +08:00
parent 19337b9371
commit 808a590b8d
2 changed files with 139 additions and 113 deletions
+33 -113
View File
@@ -1,26 +1,12 @@
# Emotion Museum HTTPS Nginx 配置
# 配置路径:/www/server/panel/vhost/nginx/emotion-museum.conf
# 域名:lifescript.happylifeos.com
# HTTP 服务器 - 强制跳转 HTTPS
server {
listen 80;
server_name lifescript.happylifeos.com;
# 强制跳转 HTTPS
return 301 https://$server_name$request_uri;
}
# HTTPS 服务器
server {
listen 443 ssl;
server_name lifescript.happylifeos.com;
# SSL 证书配置
ssl_certificate /etc/letsencrypt/live/lifescript.happylifeos.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/lifescript.happylifeos.com/privkey.pem;
# SSL 优化配置
ssl_protocols TLSv1.2 TLSv1.3;
# WeChat mini program/Cronet compatibility: keep TLS 1.2 enabled with broad modern suites.
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
@@ -29,97 +15,73 @@ server {
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
add_header Strict-Transport-Security max-age=31536000 always;
# HSTS (可选,生产环境建议开启)
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# ACME 挑战目录 - 用于 SSL 证书申请和续期
location ^~ /.well-known/acme-challenge/ {
root /data/www/acme-challenge;
allow all;
try_files $uri =404;
}
# 根路径 - 用户前端应用
location = / {
return 404;
rewrite ^ /emotion-museum/ permanent;
}
location / {
location /emotion-museum/ {
alias /data/www/emotion-museum/;
autoindex off;
# 处理 Vue Router 的 history 模式
try_files $uri $uri/ /index.html;
# HTML 文件不缓存
location ~ \.html?$ {
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
}
# 静态资源缓存 1 年
location ~ \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
# 静态资源直接返回文件,不经过 try_files
location ~* ^/emotion-museum/(assets|static)/ {
add_header Cache-Control "public, max-age=31536000, immutable";
expires 1y;
try_files $uri =404;
}
# SPA 路由兜底
try_files $uri $uri/ /emotion-museum/index.html;
}
location = /emotion-museum {
rewrite ^(.*)$ $1/ permanent;
}
# 管理后台应用路径
location /emotion-museum-admin/ {
alias /data/www/emotion-museum-admin/;
autoindex off;
# 处理 Vue Router 的 history 模式
try_files $uri $uri/ /emotion-museum-admin/index.html;
# HTML 文件不缓存
location ~ \.html?$ {
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
}
# 静态资源缓存 1 年
location ~ \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
expires 1y;
}
}
location = /emotion-museum-admin {
rewrite ^(.*)$ $1/ permanent;
}
# Life-Script 应用路径
location /course-of-life/ {
alias /data/www/course-of-life/;
autoindex off;
try_files $uri $uri/ /course-of-life/index.html;
}
location = /course-of-life {
rewrite ^ /course-of-life/ last;
}
# life-script React 应用
location /life-script/ {
alias /data/www/life-script/;
autoindex off;
# 处理 React Router 的 history 模式
try_files $uri $uri/ /life-script/index.html;
# HTML 文件不缓存
location ~ \.html?$ {
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
}
# 静态资源缓存 1 年
location ~ \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
# 静态资源直接返回文件
location ~* ^/life-script/(assets|static)/ {
add_header Cache-Control "public, max-age=31536000, immutable";
expires 1y;
try_files $uri =404;
}
# SPA 路由兜底
try_files $uri $uri/ /life-script/index.html;
}
location = /life-script {
rewrite ^ /life-script/ last;
}
# 后端 API 代理
location /api {
proxy_pass http://127.0.0.1:19089;
proxy_set_header Host $host;
@@ -131,50 +93,6 @@ server {
proxy_read_timeout 60s;
}
# Swagger UI / Knife4j API 文档代理
# 使用 ^~ 前缀匹配,防止被 / 的 try_files 拦截
location ^~ /swagger-ui {
proxy_pass http://127.0.0.1:19089;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location ^~ /v3/api-docs {
proxy_pass http://127.0.0.1:19089;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location = /doc.html {
proxy_pass http://127.0.0.1:19089;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location ^~ /webjars {
proxy_pass http://127.0.0.1:19089;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Knife4j 4.x 额外需要的路径(swagger-resources 等)
location ^~ /swagger-resources {
proxy_pass http://127.0.0.1:19089;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# WebSocket 代理
location /ws {
proxy_pass http://127.0.0.1:19089;
proxy_http_version 1.1;
@@ -189,21 +107,23 @@ server {
proxy_read_timeout 7d;
}
# 健康检查端点
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# 隐藏文件访问控制
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
# 日志配置
access_log /www/wwwlogs/ssl-access.log;
error_log /www/wwwlogs/ssl-error.log;
}
server {
listen 80;
server_name lifescript.happylifeos.com;
return 301 https://$host$request_uri;
}
@@ -0,0 +1,106 @@
---
author: Peanut
created_at: 2026-06-28
purpose: 修复生产环境首页 404,删除 nginx 配置中显式阻断根路径的 location 块
---
# 修复 nginx 根路径 404 设计
## 背景
生产环境 `https://lifescript.happylifeos.com/` 访问首页返回 404 Not Found,但:
- 前端文件 `/data/www/emotion-museum/index.html` 实际已正确部署
- 子路径 `https://lifescript.happylifeos.com/emotion-museum-admin/``/life-script/``/emotion-museum/` 可以正常访问
- 后端 API 代理 `/api` 正常工作
## 根因(实际)
**真实生效的 nginx 配置不在 `conf/emotion-museum.conf`**,而是在 aaPanel 托管的:
`/www/server/panel/vhost/nginx/emotion-museum.conf`
原因:nginx 主配置 `/www/server/nginx/conf/nginx.conf` 的 include 顺序是:
```nginx
include /www/server/panel/vhost/nginx/*.conf;
```
它只 include aaPanel 的 vhost 目录。`/etc/nginx/sites-available/` 是部署脚本的"期望"路径,但**从未被 include**,所以 `deploy.py nginx` 实际上一直没真正生效。
真实配置中第 31-33 行有一个显式阻断根路径的 exact match
```nginx
location = / {
return 404;
}
```
并且前端在真实配置中映射的路径是 `/emotion-museum/`(不是根路径):
```nginx
location /emotion-museum/ {
alias /data/www/emotion-museum/;
...
try_files $uri $uri/ /emotion-museum/index.html;
}
```
所以访问 `/` 时,被 `location = / { return 404; }` 精确匹配拦截,根本不会走到任何 location 块。
## 修复方案
### 第一层:修改真实生效的 aaPanel 配置
直接 ssh 编辑 `/www/server/panel/vhost/nginx/emotion-museum.conf`,把:
```nginx
location = / {
return 404;
}
```
改成:
```nginx
location = / {
rewrite ^ /emotion-museum/ permanent;
}
```
这样根路径会被 301 永久重定向到 `/emotion-museum/`(前端实际部署位置)。
然后 `nginx -t && nginx -s reload` 让配置生效。
### 第二层:同步更新仓库内 `conf/emotion-museum.conf`
保持仓库内的配置文件与真实服务器一致(作为基线参考)。同步修改:
1. 删除之前的 `location / { alias /data/www/emotion-museum/; ... }` 通用块(真实配置没有)
2. 新增 `location /emotion-museum/ { ... }` 前端块(与真实配置对齐)
3. `location = /` 改为 `rewrite ^ /emotion-museum/ permanent;`
**注意**:虽然仓库内配置现在不被真实 nginx include,但保持同步是为了:
- 作为文档,记录服务器实际配置
- 未来如果切回 sites-available 部署模式,能直接生效
- 避免"仓库配置"和"服务器配置"分叉导致混乱
## 验证步骤
1. ssh 直接编辑服务器上的 `/www/server/panel/vhost/nginx/emotion-museum.conf`,改 `location = /`
2. `nginx -t` 验证语法
3. `nginx -s reload` 重载配置
4. 浏览器访问 `https://lifescript.happylifeos.com/` 确认 301 → `https://lifescript.happylifeos.com/emotion-museum/`
5. `/emotion-museum/` 正常返回前端页面(200
6. DevTools Network 无 404、Console 无报错
7. 其他子路径(`/emotion-museum-admin/``/life-script/``/api/``/ws``/health`)不受影响
8. 同步更新 `conf/emotion-museum.conf` 作为仓库基线
9. 提交 git commit
## 风险与回退
- **影响面小**:只改 1 个 location 块(3 行),其他 location 块完全不动
- **回退方案**:若出问题,把 `rewrite ^ /emotion-museum/ permanent;` 改回 `return 404;` 即可立即回滚
- **不会冲突**`/emotion-museum/``/emotion-museum-admin/``/life-script/` 都有自己的 location 块,`location = /` 精确匹配只对根路径生效
## 长期改进(不在本次范围)
`deploy.py nginx` 当前部署到 `/etc/nginx/sites-available/`,但服务器主配置 include 的是 aaPanel 路径,所以部署脚本实际上一直无效。后续应该:
-`deploy.py nginx` 同时更新 `/www/server/panel/vhost/nginx/emotion-museum.conf`
- 或者在 nginx 主配置中增加 `include /etc/nginx/sites-enabled/*.conf;`
- 本次不处理,单独跟踪