www_site/docs/production-deployment-2026-09-11.md

56 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 生产部署记录2026-09-11
## 发布
- 发布提交:`ad87a71`(含 `de6fdb0` 邮箱/短信注册验证、`c439ccb` 图形验证码+唯一用户名、`5b9d74a` 用户资料管理与管理员删除用户、`57c854a`/`080af11`/`70f64b6`/`be7e1f4` CMS 入口修复、`ad87a71` 品牌 favicon 等)。
- 发布目录:`/home/flym/releases/ad87a71`www + API、`/home/flym/releases/cms-ad87a71`CMS
- 软链:`kaotings-www`→`releases/ad87a71`、`kaotings-cms`→`releases/cms-ad87a71`、`kaotings-api`→`releases/ad87a71/services/api`。
- 数据库迁移:`005_sms_provider.sql`、`006_usernames.sql` 已应用(`schema_migrations` 001006 齐全,`users.username` 列存在)。
## 本次发现并修复的问题(重要)
1. **Turbopack 外部模块缺失导致 CMS 500**Next 16Turbopack生产构建会把外部依赖pino/pg/drizzle-kit/pino-pretty带内容 hash 后缀)拷贝到 `.next/node_modules/<name>-<hash>/`,运行时按该名字 require。
- 本地 Windows 构建产物中 `.next/node_modules/` 只有空目录(文件未写入),导致此前发布(含 09-11 上午 `cms-57c854a` 包)的 CMS 管理端/API 一直 500`Cannot find module 'pino-<hash>'`www 首页因调用 CMS API 连带 500。
- 修复:以 `releases/df6a0e4/apps/cms/.next/node_modules`同版本依赖、hash 一致)覆盖 `cms-ad87a71/.next/node_modules` 后 CMS 恢复正常。
- 教训:**本地Windows构建的 CMS `.next` 不可直接用于生产**;后续 CMS 应在服务器上构建,或发布前校验 `.next/node_modules` 文件完整性pino 包应 ≥200 文件)。
2. **服务器资源**:内存 1.9G 无 swap服务器上跑 CMS 构建会 OOM本次已加 4G `/swapfile`)。
3. **sudo 构建残留 root 属主文件**:曾以 sudo 在发布目录内跑 `npm run build`,产生 root 属主的 `.next` 文件,导致后续以 flym 提取覆盖失败;已清理。发布目录内构建/清理应统一属主。
4. **SSH 未认证连接限流**:该服务器 sshd 未认证并发限制很严(疑似外部扫描占用 MaxStartups部署期间需控制连接频率、合并操作。
## 回滚
- 上一可用发布保留:`releases/080af11`www、`releases/cms-57c854a`CMS已修复 `.next/node_modules``node_modules`,可独立运行)。
- 回滚:软链指回上述目录 + `systemctl restart` 对应服务。API 回滚需同时评估 `005/006` 迁移(均为新增列/表,旧代码兼容,可保留迁移)。
## 验收
- `systemctl is-active kaotings-api kaotings-cms kaotings-web`active ×3。
- `GET /healthz`127.0.0.1:8000 与 https://www.kaotings.comok / 200。
- www`/`、`/register`、`/login`、`/icon.png` 均 200新代码标记 favicon 生效)。
- CMS`/cms/admin` 200`/cms/api/products?where[status][equals]=published` 200。
- API 门禁:`/api/v1/auth/me` 未登录 401。
## 备注
- 生产 `api.env` 尚未注入 SMTP/阿里云短信凭据(新配置项默认空值=功能关闭),注册验证能力待凭据注入后启用,属待办而非本次部署内容。
- Caddy 未改动CMS 根路径跳转由 CMS 自身 `/cms → /cms/admin` 处理)。
## 追加CMS 管理端登录后 404 根因与修复(重要)
**现象**:登录 CMS 后访问 `https://www.kaotings.com/cms/admin` 返回 404Next 默认 "This page could not be found."),未登录时正常显示登录页;其它管理路径(`/account`、`/collections/*`、`/globals/*`全部正常。与网络、DNS、浏览器、HTTP/3、CDN 无关(曾误判,已逐一排除:证书指纹一致、请求确实到达服务器并记录在 Caddy 日志中)。
**根因**(三处代码叠加):
1. `apps/cms/src/app/(payload)/admin/[[...segments]]/page.tsx` 把路由参数兜底成空数组:`segments: resolvedParams.segments ?? []`。
2. `@payloadcms/next``RootPage``Array.isArray(params.segments) ? `/${params.segments.join('/')}` : null` 计算 `currentRoute`;传入 `[]``path` 变成 `"/"`
3. `payload/shared``formatAdminURL``{adminRoute:'/admin', path:'/'}` 返回 `"/admin/"`(带尾斜杠,且该分支不做去尾斜杠处理),于是 `currentRoute("/admin/") !== adminRoute("/admin")`
`getRouteData` 中**只有根路由**的视图解析依赖 `currentRoute === adminRoute` 判断(`case 0`),条件不成立时 `DefaultView` 为空,`RootPage` 对**已登录用户**执行 `notFound()` → 404未登录用户走另一分支因此表现为"登录后才 404"。
**修复**`page.tsx` 中不再把 `segments` 兜底为空数组,保持 `undefined``@payloadcms/next` 类型声明把 `segments` 写成必填数组,与实现不符,故加一处类型断言并注释说明)。修复后已登录访问根路由返回 200 并正常渲染 `Dashboard - Payload`
**其它同批处理**
- CMS 改为在服务器上构建(本地 Windows 构建产物中 `.next/node_modules/*` 符号链接会退化为空目录,不可直接部署;服务器构建会生成有效的 `-> ../../node_modules/<pkg>` 符号链接)。
- 新增 4G swap避免服务器构建 OOM。
- Caddy 增加了访问日志(`log { output stdout }`),便于后续排查。
- 发布:`releases/cms-ad87a71-c`(含本次修复),回滚可指向 `releases/cms-ad87a71-b`(可运行,但根路由登录后 404