From 91c089a894f23715a5542471ec84c94f6104b939 Mon Sep 17 00:00:00 2001 From: zl-q Date: Mon, 11 May 2026 19:09:35 +0800 Subject: [PATCH] fix: resolve legal/about pages in production, update deploy docs - Fix markdown file path resolution for SSR production builds - Try multiple paths (public/legal, client/legal) for dev and prod - Update deploy/README.md with frontend deployment instructions - Document PM2, Nginx configuration, and port mapping --- deploy/README.md | 122 +++++++++++++++++++++++++++++ web/src/components/AboutPage.astro | 21 +++-- web/src/components/LegalPage.astro | 21 +++-- 3 files changed, 154 insertions(+), 10 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 84aa518..f590cf9 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -14,6 +14,8 @@ - Docker - Docker Compose v2 - AWS CLI v2 +- Node.js 22+ (前端 SSR 服务) +- PM2 (前端进程管理) 确认命令: @@ -21,6 +23,31 @@ docker --version docker compose version aws --version +node --version # 需要 >= 22.12.0 +pm2 --version +``` + +## 服务架构 + +生产环境运行以下服务: + +| 服务 | 端口 | 说明 | +|------|------|------| +| Nginx | 80, 443 | 反向代理,SSL 终结 | +| 前端 SSR | 4322 | Node.js + Astro SSR | +| 后端 API | 5775 | Docker 容器 | +| Redis | 6379 | Docker 容器 | +| Worker Agent | - | Docker 容器 | + +### 端口映射 + +``` +Internet → Nginx (443) + ├── /_astro/* → 静态文件 (client 目录) + ├── /images/* → 静态文件 (client 目录) + └── /* → 反向代理到 localhost:4322 (前端 SSR) + +前端 SSR (4322) → /api/* → 反向代理到 localhost:5775 (后端 API) ``` ## 环境变量 @@ -199,3 +226,98 @@ docker compose --env-file ./.env -f docker-compose.prod.yml --profile workers do ``` 谨慎使用 `down -v`,它会删除 Redis 持久化数据。 + +## 前端部署 + +### 构建前端 + +在本地开发机器上: + +```bash +cd web +PUBLIC_API_URL=https://api.meeyao.com npm run build +``` + +构建产物在 `web/dist/` 目录: +- `dist/client/` - 静态资源 (CSS, JS, 图片) +- `dist/server/` - SSR 服务端代码 + +### 上传到服务器 + +```bash +# 上传构建产物 +rsync -avz -e "ssh -i xunmee.pem" web/dist/ ubuntu@18.218.38.213:/home/ubuntu/deploy/web/ + +# 上传依赖配置 +rsync -avz -e "ssh -i xunmee.pem" web/package.json web/package-lock.json ubuntu@18.218.38.213:/home/ubuntu/deploy/web/ + +# 安装生产依赖 +ssh -i xunmee.pem ubuntu@18.218.38.213 "cd /home/ubuntu/deploy/web && npm install --omit=dev" +``` + +### PM2 管理 + +```bash +# 启动服务 +pm2 start server/entry.mjs --name meeyao-web + +# 设置端口 (默认 4321,需要改为 4322) +export HOST=0.0.0.0 +export PORT=4322 +pm2 restart meeyao-web + +# 保存进程列表 (开机自启) +pm2 save + +# 查看状态 +pm2 status + +# 查看日志 +pm2 logs meeyao-web +``` + +### Nginx 配置 + +前端 SSR 服务监听 `localhost:4322`,Nginx 配置要点: + +```nginx +server { + listen 443 ssl http2; + server_name meeyao.com; + + # 静态资源直接从 client 目录提供 + location /_astro { + root /home/ubuntu/deploy/web/client; + expires 30d; + add_header Cache-Control "public, immutable"; + } + + location /images { + root /home/ubuntu/deploy/web/client; + expires 30d; + } + + # 其他请求代理到 Node.js SSR + location / { + proxy_pass http://127.0.0.1:4322; + proxy_http_version 1.1; + 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; + } +} +``` + +### 前端更新流程 + +```bash +# 1. 本地构建 +cd web && PUBLIC_API_URL=https://api.meeyao.com npm run build + +# 2. 上传 +rsync -avz -e "ssh -i xunmee.pem" dist/ ubuntu@18.218.38.213:/home/ubuntu/deploy/web/ + +# 3. 重启服务 +ssh -i xunmee.pem ubuntu@18.218.38.213 "pm2 restart meeyao-web" +``` diff --git a/web/src/components/AboutPage.astro b/web/src/components/AboutPage.astro index 3c55e61..2dc992d 100644 --- a/web/src/components/AboutPage.astro +++ b/web/src/components/AboutPage.astro @@ -17,12 +17,23 @@ const titleMap: Record = { en: 'About Us', }; -const filePath = path.resolve('public/legal', locale, 'about_us.md'); +// Try multiple paths for dev and production environments +const possiblePaths = [ + path.resolve('public/legal', locale, 'about_us.md'), + path.resolve('client/legal', locale, 'about_us.md'), + path.resolve('../client/legal', locale, 'about_us.md'), +]; let raw = ''; -try { - raw = fs.readFileSync(filePath, 'utf-8'); - raw = raw.replace(/^#\s+.+\n*/m, ''); -} catch { +for (const filePath of possiblePaths) { + try { + raw = fs.readFileSync(filePath, 'utf-8'); + raw = raw.replace(/^#\s+.+\n*/m, ''); + break; + } catch { + // Try next path + } +} +if (!raw) { raw = `Content not available.`; } const content = await marked(raw); diff --git a/web/src/components/LegalPage.astro b/web/src/components/LegalPage.astro index 6ca2f63..9a6ecd7 100644 --- a/web/src/components/LegalPage.astro +++ b/web/src/components/LegalPage.astro @@ -46,12 +46,23 @@ const subtitle = subtitleMap[docType]?.[locale] ?? ''; const warning = warningMap[locale]; const legalTitle = legalTitleMap[locale]; -const filePath = path.resolve('public/legal', locale, `${docType}.md`); +// Try multiple paths for dev and production environments +const possiblePaths = [ + path.resolve('public/legal', locale, `${docType}.md`), + path.resolve('client/legal', locale, `${docType}.md`), + path.resolve('../client/legal', locale, `${docType}.md`), +]; let raw = ''; -try { - raw = fs.readFileSync(filePath, 'utf-8'); - raw = raw.replace(/^#\s+.+\n*/m, ''); -} catch { +for (const filePath of possiblePaths) { + try { + raw = fs.readFileSync(filePath, 'utf-8'); + raw = raw.replace(/^#\s+.+\n*/m, ''); + break; + } catch { + // Try next path + } +} +if (!raw) { raw = `Content not available.`; } const content = await marked(raw);