From 9ee203c221b34b918ebec55f80287d43ebd164ae Mon Sep 17 00:00:00 2001 From: root Date: Sat, 6 Jun 2026 23:25:39 +0800 Subject: [PATCH] \s --- NOMADCNA_PROJECT_DEPLOYMENT_REPORT.md | 1096 +++++++++++++++++++++++++ 1 file changed, 1096 insertions(+) create mode 100644 NOMADCNA_PROJECT_DEPLOYMENT_REPORT.md diff --git a/NOMADCNA_PROJECT_DEPLOYMENT_REPORT.md b/NOMADCNA_PROJECT_DEPLOYMENT_REPORT.md new file mode 100644 index 0000000..cdf1fb4 --- /dev/null +++ b/NOMADCNA_PROJECT_DEPLOYMENT_REPORT.md @@ -0,0 +1,1096 @@ +# 游牧中国 NomadCNA 项目与服务器部署报告 + +生成时间:2026-06-06 23:16 CST +服务器时区:Asia/Shanghai / CST +0800 +项目路径:`/home/ubuntu/gitlab-instance-0a899031_cnomadcna` +Git 分支:`test2` +最新提交:`00b1c8e`,2026-06-06 23:05:17 +0800 +报告范围:当前仓库代码、前端/后端/数据服务、服务器上实际运行的相关服务、反向代理、端口、构建状态、运维风险与后续建议。 +敏感信息处理:本报告只记录环境变量名、用途、路径、端口和域名,不记录任何密码、Token、Access Key、Secret、数据库连接串原文。 + +## 1. 项目定位 + +NomadCNA / 游牧中国是一个面向数字游民的中文优先、英文可切换的一站式网站,当前定位可以概括为: + +- 数字游民城市决策平台:展示中国城市的成本、网速、安全、气候、社区活跃度、标签和详情。 +- 数字游民社区入口:提供报名、登录、会员、资料录入、同城活动、交友匹配、站内消息。 +- 数字游民服务市场:提供共享办公、城市落地顾问、保障类服务、赏金任务、反馈和咨询线索。 +- 数字游民内容与工具:电子书、视频、报告、AI 助手、FIRE/汇率/签证/气候工具。 +- 生产部署站点:当前主域为 `nomadro.cn` / `www.nomadro.cn`,PocketBase 为 `pocketbase.nomadro.cn`,FastAPI 为 `api.nomadro.cn`。 + +当前项目已经不是纯前端展示站,已经具备“前端 + Next.js API + FastAPI + PocketBase + 支付 + 上传 + 消息 + 监控”的完整早期产品架构。 + +## 2. 访问地址与部署入口 + +### 2.1 对外域名 + +| 域名 | 当前用途 | 反向代理目标 | HTTPS 状态 | +| --- | --- | --- | --- | +| `https://nomadro.cn` | 游牧中国主站 | `127.0.0.1:4002` | 已配置证书 | +| `https://www.nomadro.cn` | 游牧中国主站 | `127.0.0.1:4002` | 已配置证书 | +| `http://api.nomadro.cn` | FastAPI 后端 API | `127.0.0.1:8000` | 当前只看到 HTTP 配置 | +| `https://pocketbase.nomadro.cn` | PocketBase REST API 与后台 | `127.0.0.1:8090` | 已配置证书 | +| `https://umami.nomadro.cn` | Umami 统计 | `127.0.0.1:9280` | 已配置证书 | +| `http://ntfy.nomadro.cn` | ntfy 推送服务 | `127.0.0.1:9180` | 当前只看到 HTTP 配置 | +| `http://netdata.nomadro.cn` | Netdata 监控面板 | `127.0.0.1:19999` | 当前只看到 HTTP 配置,已配置 Basic Auth | + +### 2.2 本机端口 + +| 端口 | 监听地址 | 服务 | 说明 | +| --- | --- | --- | --- | +| `4002` | `*:4002` | NomadCNA Next.js | 生产前端,systemd 管理 | +| `8000` | `127.0.0.1:8000` | NomadCNA FastAPI | 后端 API,systemd 管理 | +| `8090` | `127.0.0.1:8090` | PocketBase | 本站主数据服务 | +| `9280` | `127.0.0.1:9280` | Umami | 统计分析服务 | +| `9180` | `127.0.0.1:9180` | ntfy Docker 容器 | 通知推送服务 | +| `19999` | `127.0.0.1:19999` | Netdata | 宿主机监控 | +| `80/443` | `0.0.0.0` | Nginx | 站点反向代理 | +| `3306` | `0.0.0.0` | MariaDB/MySQL | 宝塔/其他服务使用,非当前 NomadCNA 主数据 | +| `5432` | `127.0.0.1` | PostgreSQL 16 | Umami 使用 | +| `21` | `0.0.0.0` | pure-ftpd | FTP 服务 | +| `888` | `0.0.0.0` | 宝塔面板 Nginx | 管理面板 | +| `36711` | `0.0.0.0` | 宝塔面板 webserver | 管理面板相关 | +| `7000/8999` | `*` | frp-panel | 同机运行的穿透/面板服务 | + +### 2.3 健康检查结果 + +已验证: + +- `http://127.0.0.1:8000/api/health` 返回 `200`,服务名为 `NomadCNA FastAPI`。 +- `http://127.0.0.1:4002/zh` 返回 `200`,Next.js 页面可访问。 +- `http://127.0.0.1:8090/api/health` 返回 `200`,PocketBase 可访问。 +- `https://nomadro.cn` 返回 `307` 到 `/zh`,随后返回 `200`。 +- `https://www.nomadro.cn` 返回 `307` 到 `/zh`,随后返回 `200`。 +- `http://api.nomadro.cn/api/health` 返回 FastAPI 健康信息。 +- `https://pocketbase.nomadro.cn/api/health` 返回 `200`。 + +## 3. 技术栈 + +### 3.1 前端 + +- Next.js `16.1.6` +- React `19.2.3` +- React DOM `19.2.3` +- TypeScript `^5` +- Tailwind CSS `^4` +- ECharts `^6.0.0` +- PocketBase JS SDK `^0.26.8` +- MinIO SDK `^8.0.7` +- 包管理器:`pnpm 10.25.0` +- Node.js:`v22.13.1` + +### 3.2 后端 + +- FastAPI +- Uvicorn +- httpx +- python-multipart +- PyJWT +- passlib[bcrypt] +- Pydantic v2 +- Python `3.12.3` + +### 3.3 数据与存储 + +- PocketBase:主业务数据库,运行在 `/opt/pocketbase`。 +- PocketBase 数据目录:`/opt/pocketbase/pb_data`。 +- PocketBase 迁移目录:`/opt/pocketbase/pb_migrations`。 +- MinIO:代码中已接入,Docker compose 中也有 `nomadro-minio` 配置,但当前 `docker ps` 只看到 `nomadro-ntfy` 正在运行。 +- 本地上传:FastAPI 挂载 `backend/uploads`,Next.js 上传接口使用 MinIO。 + +### 3.4 代理、运维与监控 + +- Nginx:宝塔路径 `/www/server/nginx`,站点配置在 `/www/server/panel/vhost/nginx/`。 +- systemd:管理 Next.js、FastAPI、PocketBase、Umami、Netdata 等服务。 +- Docker:当前运行 `nomadro-ntfy` 容器。 +- Netdata:宿主机实时监控。 +- Umami:站点访问统计。 +- 宝塔面板相关服务:Nginx、pure-ftpd、MariaDB、站点统计、面板防火墙。 + +## 4. 仓库结构 + +项目根目录主要文件: + +| 路径 | 说明 | +| --- | --- | +| `app/` | Next.js App Router 应用主体 | +| `app/[locale]/` | 中英文路由页面,支持 `/zh` 和 `/en` | +| `app/api/` | Next.js API routes,主要处理认证、支付、上传、会员状态 | +| `app/components/` | Navbar、Hero、城市卡片、弹窗、菜单、通知铃等组件 | +| `app/context/` | 主题和语言 Context | +| `app/data/` | 城市、博客、招聘等 fallback/mock 数据 | +| `app/lib/` | API 客户端、PocketBase、支付、MinIO、图表、Cookie 等工具 | +| `backend/` | FastAPI 本地 API 服务 | +| `config/` | 站点、导航、域名、服务、首页、页脚、筛选配置 | +| `i18n/` | 国际化路由和导航适配 | +| `messages/` | 中文和英文文案 | +| `public/` | 静态资源 | +| `next.config.ts` | Next.js 配置和 API rewrite | +| `proxy.ts` | locale 重定向代理 | +| `package.json` | 前端依赖和脚本 | +| `backend/requirements.txt` | Python 后端依赖 | +| `cnomadcna.sh` | 生产 Next.js systemd 启动脚本 | +| `PROJECT_ANALYSIS_REPORT.md` | 旧分析报告 | +| `NOMADCNA_PROJECT_DEPLOYMENT_REPORT.md` | 当前报告 | + +项目体积:当前仓库目录约 `746M`,包含 `.next`、`node_modules`、`backend/.venv` 等运行产物。 + +## 5. 前端应用结构 + +### 5.1 国际化 + +- 支持语言:`zh`、`en`。 +- 默认语言:`zh`。 +- URL 策略:总是带 locale 前缀。 +- `proxy.ts` 会将无 locale 的页面请求重定向到 `/zh`。 +- `/api`、`/_next`、静态文件和带扩展名路径不做 locale 重定向。 + +### 5.2 主要页面 + +当前 `app/[locale]` 下页面包括: + +| 页面 | 用途 | +| --- | --- | +| `/` | 首页,城市列表、内容入口、统计、活动、路线、社区模块 | +| `/dashboard` | 下一站推荐,根据预算、网速、气候、标签推荐城市 | +| `/city/[slug]` | 城市详情动态页 | +| `/meetups` | 线下活动列表 | +| `/meetups/host` | 发起活动 | +| `/dating` | 智能匹配、交友、伙伴、室友、合伙人 | +| `/tools` | 汇率、税务估算、签证倒计时、FIRE、气候匹配 | +| `/ai` | AI 助手,基于城市数据库返回建议 | +| `/gigs` | 赏金任务发布和接单 | +| `/services` | 数字游民服务咨询入口 | +| `/pricing` | Free / Basic / Pro 定价展示 | +| `/join` | 社区报名、资料录入、上传、支付跳转 | +| `/join/paid` | 支付回跳与会员开通确认 | +| `/messages` | 站内消息中心 | +| `/settings/notifications` | 通知偏好设置 | +| `/report`、`/report/data` | 数字游民报告 | +| `/map` | 成员地图 | +| `/blog` | 博客 | +| `/ebooks/[slug]` | 电子书动态页 | +| `/videos/[slug]` | 视频动态页 | +| `/app` | App 下载/介绍页 | +| `/feedback` | 反馈 | +| `/discuss` | 讨论社区 | +| `/jobs`、`/careers` | 招聘/职业 | +| `/about`、`/contact`、`/press`、`/support`、`/help` | 基础内容页 | +| `/terms`、`/privacy`、`/cookies`、`/safety`、`/guidelines` | 法务和社区规则 | + +### 5.3 首页数据策略 + +首页当前采用“线上 API 优先、fallback 静态数据兜底”的方式: + +- `/api/cities`:城市列表。 +- `/api/content/home`:首页内容卡片。 +- `/api/stats/overview`:城市、游民、活动、成本、讨论等统计。 +- `/api/profiles`:成员头像和正在旅行的人。 +- `/api/meetups`:近期活动。 +- `/api/discussions`:热门讨论。 +- `/api/routes`:热门路线。 + +如果 API 请求失败,会回退到 `config/home.config.ts` 和 `app/data/cities.ts` 内的本地数据。这让站点在后端短暂不可用时仍能展示基本内容。 + +### 5.4 导航与站点配置 + +站点标题:`游牧中国 NomadCNA - 数字游民生活操作系统` +站点描述:数字游民的一站式生活操作系统,覆盖城市决策、税务签证、智能匹配、赏金任务。 +主导航包括: + +- 城市 +- 下一站 +- 聚会 +- 社区 +- 工具箱 +- AI +- 赏金 +- 会员 +- 探索 + +## 6. API 层结构 + +当前 API 有两层,需要明确区分。 + +### 6.1 Next.js API routes + +`app/api` 下当前存在: + +| 路径 | 用途 | +| --- | --- | +| `/api/auth/me` | 读取登录态、刷新 PocketBase auth、返回 VIP 状态 | +| `/api/auth/logout` | 清除登录 Cookie | +| `/api/auth/sync-session` | 支付后同步 token 到 Cookie | +| `/api/auth/change-password` | 修改密码 | +| `/api/join` | 提交报名资料到 PocketBase 指定集合 | +| `/api/join/status` | 检查是否已经提交报名 | +| `/api/upload-media` | 通过 MinIO 上传图片/视频 | +| `/api/vip/check` | 检查 `site_vip` 会员记录 | +| `/api/pay` | 创建支付订单,调用 payjsapi / ZPay / XorPay | +| `/api/pay/status` | 查询支付状态 | +| `/api/meetup/check-user` | 检查用户是否存在和是否 VIP | +| `/api/meetup/ensure-user` | 确保用户存在 | +| `/api/meetup/complete-order` | 支付成功后确认订单并开通 VIP | +| `/api/meetup/need-password-change` | 检查是否需要改默认密码 | +| `/api/meetup/set-needs-password-change` | 设置需要改密码 | +| `/api/geo/china` | 拉取中国地图 GeoJSON | + +### 6.2 FastAPI 后端 + +FastAPI 运行在 `127.0.0.1:8000`,服务名 `cnomadcna-api.service`。主要接口包括: + +| 路径 | 用途 | +| --- | --- | +| `/api/health` | 健康检查 | +| `/api/auth/register` | 注册并设置 session | +| `/api/auth/login` | 登录并设置 session | +| `/api/auth/me` | 当前用户和会员状态 | +| `/api/auth/logout` | 清除 session | +| `/api/auth/change-password` | 修改密码 | +| `/api/meetup/check-user` | 检查用户和会员 | +| `/api/meetup/ensure-user` | 创建或登录用户 | +| `/api/meetup/complete-order` | 本地订单完成和 membership 写入 | +| `/api/vip/check` | 根据 `memberships` 检查 VIP | +| `/api/join` | 提交会员申请 | +| `/api/join/status` | 报名状态 | +| `/api/upload-media` | 本地上传到 `backend/uploads` | +| `/api/pay` | 本地开发支付 | +| `/api/pay/status` | 本地开发支付状态 | +| `/api/cities` | 城市列表 | +| `/api/cities/{slug}` | 城市详情 | +| `/api/content/home` | 首页内容 | +| `/api/content/{slug}` | 内容详情 | +| `/api/notifications` | 消息列表和筛选 | +| `/api/notifications/unread-count` | 未读数 | +| `/api/notifications/{id}/read` | 标记已读 | +| `/api/notifications/{id}/unread` | 标记未读 | +| `/api/notifications/{id}/archive` | 归档 | +| `/api/notifications/{id}/restore` | 恢复 | +| `/api/notifications/{id}/pin` | 置顶 | +| `/api/notifications/mark-all-read` | 全部已读 | +| `/api/notifications/preferences` | 读取/保存通知偏好 | +| `/api/recommendations/next-stop` | 下一站推荐 | +| `/api/routes` | 游牧路线 | +| `/api/services` | 服务列表 | +| `/api/services/leads` | 服务咨询线索 | +| `/api/downloads/{filename}` | 下载 PDF/Zip 等资源 | +| `/api/meetups` | 活动列表和创建 | +| `/api/discussions` | 讨论列表和创建 | +| `/api/gigs` | 赏金列表和发布 | +| `/api/gigs/{gig_id}/apply` | 接单 | +| `/api/profiles` | 成员资料 | +| `/api/matches/swipes` | 匹配滑动记录 | +| `/api/feedback` | 反馈 | +| `/api/stats/member-map` | 成员地图统计 | +| `/api/stats/overview` | 总览统计 | +| `/api/stats/city-ranking` | 城市排行 | +| `/api/geo/china` | 地图数据 | +| `/api/ai/assistant` | AI 助手模拟响应 | + +### 6.3 Next.js rewrite + +`next.config.ts` 把部分 `/api/*` 路径 rewrite 到 FastAPI: + +- health +- cities +- content +- notifications +- recommendations +- routes +- services +- downloads +- meetups +- discussions +- gigs +- profiles +- matches +- feedback +- stats +- ai + +这意味着: + +- 上面列出的业务数据 API 会由 FastAPI 处理。 +- Next.js 自身的 `/api/auth/*`、`/api/pay/*`、`/api/join/*`、`/api/upload-media`、`/api/vip/check` 等仍由 Next.js API routes 处理。 +- `app/lib/api-client.ts` 默认 `NEXT_PUBLIC_API_BASE_URL || http://127.0.0.1:8000`。生产环境必须保证 `NEXT_PUBLIC_API_BASE_URL` 指向公网可访问的 API 地址,例如 `http://api.nomadro.cn` 或未来的 `https://api.nomadro.cn`,否则浏览器会尝试请求访问者自己机器的 `127.0.0.1:8000`。 + +## 7. PocketBase 数据模型 + +### 7.1 PocketBase 服务 + +PocketBase systemd 配置: + +- 服务名:`pocketbase.service` +- 工作目录:`/opt/pocketbase` +- 启动命令:`/opt/pocketbase/pocketbase serve --http=127.0.0.1:8090 --dir=/opt/pocketbase/pb_data --origins=https://nomadro.cn,https://www.nomadro.cn,https://pocketbase.nomadro.cn` +- 数据目录:`/opt/pocketbase/pb_data` +- 迁移目录:`/opt/pocketbase/pb_migrations` +- 当前状态:active/running + +PocketBase 数据库文件: + +- `/opt/pocketbase/pb_data/data.db` +- `/opt/pocketbase/pb_data/auxiliary.db` +- `/opt/pocketbase/pb_data/types.d.ts` + +### 7.2 初始化脚本中的集合 + +`backend/init_db.py` 定义并初始化以下集合: + +| 集合 | 用途 | +| --- | --- | +| `cities` | 城市主数据,包括 slug、名称、成本、网速、安全、气候、坐标、标签 | +| `city_details` | 城市详情 JSON,包括指南、优缺点、评价、成本、天气、趋势等 | +| `profiles` | 成员资料和匹配展示 | +| `member_applications` | 社区报名资料 | +| `memberships` | FastAPI 使用的会员记录 | +| `orders` | FastAPI 本地订单 | +| `media_assets` | 上传媒体记录 | +| `meetups` | 线下活动 | +| `discussions` | 讨论帖 | +| `gigs` | 赏金任务 | +| `gig_applications` | 接单申请 | +| `services` | 服务市场条目 | +| `service_leads` | 服务咨询线索 | +| `routes` | 游牧路线 | +| `recommendation_logs` | 下一站推荐日志 | +| `notifications` | 站内通知 | +| `notification_receipts` | 通知已读/归档/置顶状态 | +| `notification_preferences` | 通知偏好 | +| `feedback` | 用户反馈 | +| `swipes` | 交友匹配滑动行为 | +| `content_items` | 电子书、视频、App、指南等内容卡片 | + +### 7.3 种子数据 + +种子数据覆盖: + +- 18 个中国数字游民城市,包括大理、成都、深圳、上海、杭州、厦门、北京、广州、重庆、昆明、三亚、丽江、西安、南京、长沙、青岛、苏州、珠海。 +- 城市成本、网速、安全、气候、经纬度、标签和英文描述。 +- 首页内容:数字游民落地手册、访谈视频、NomadCNA App、数字游民指南。 +- 活动、讨论、赏金、成员资料、服务、路线、通知。 +- 典型服务:远程工作者医疗与旅行保障、共享办公通行证、城市落地顾问。 +- 典型路线:云南慢生活线、湾区创业线、江南互联网线。 + +### 7.4 会员模型一致性风险 + +当前存在两套会员判断模型: + +- FastAPI 的 `/api/vip/check` 和 `/api/auth/me` 使用 `memberships` 集合。 +- Next.js 的 `/api/vip/check`、`/api/auth/me`、`/api/meetup/complete-order` 使用 `site_vip` 集合。 +- `/opt/pocketbase/pb_migrations` 当前列出的迁移包含 `memberships`,未在本次扫描输出中看到 `site_vip` 迁移文件。 + +这会带来风险: + +- 如果生产 PocketBase 中没有 `site_vip` 集合,Next.js 会员检查会一直返回非 VIP。 +- 如果支付完成只写 `site_vip`,FastAPI 的会员检查不会识别。 +- 如果某些页面走 Next.js API,某些页面走 FastAPI API,会员状态可能不一致。 + +建议统一为一套会员集合,或明确 `site_vip` 是跨站会员表、`memberships` 是旧表,并补充迁移、同步逻辑和文档。 + +## 8. 支付与报名链路 + +### 8.1 报名流程 + +主要页面:`/zh/join` + +流程: + +1. 用户填写昵称、性别、感情状态、职业、简介、微信、学历、毕业年份、手机号、图片/视频。 +2. 页面先检查 `/api/auth/me`。 +3. 未登录则打开认证弹窗。 +4. 已登录后调用 `/api/join` 写入报名资料。 +5. 再调用 `/api/vip/check`。 +6. 如果不是 VIP,则调用 `/api/pay` 跳转支付。 +7. 支付成功回跳 `/join/paid`。 +8. `/join/paid` 根据 `order_id` 调用 `/api/meetup/complete-order`。 +9. 订单确认后同步登录态、触发 `auth:updated` 和 `vip:updated` 事件。 +10. 新用户会显示默认密码提示,并允许修改密码。 + +### 8.2 支付配置 + +代码支持: + +- `zpay` +- `xorpay` +- payjsapi 风格 API +- PC / H5 / 微信浏览器支付环境判断 +- 微信内强制走 XorPay 的逻辑 +- ZPay 二维码轮询和支付成功后自动确认 + +关键环境变量名: + +- `PAYMENT_API_URL` +- `PAYMENT_PROVIDER` +- `PAYMENT_DEFAULT_AMOUNT` +- `PAYMENT_DEFAULT_TYPE` +- `PAYMENT_JOIN_AMOUNT` +- `PAYMENT_JOIN_TYPE` +- `ZPAY_SUBMIT_URL` +- `NEXT_PUBLIC_SITE_ID` + +`config/domain.config.ts` 中有保护逻辑:生产环境如果 `PAYMENT_API_URL` 指向 localhost,会使用 `https://api.${ROOT_DOMAIN}`。 + +### 8.3 安全注意点 + +- 新用户默认密码当前是 `12345678`,且页面会展示和复制该密码。这适合 MVP,但生产上存在弱口令风险。 +- 建议改为一次性随机临时密码、一次性登录链接,或强制首次设置密码后才完成登录。 +- 支付确认依赖订单 ID 格式解析,建议补充订单表记录、签名校验、回调审计和重复开通幂等测试。 + +## 9. 上传与对象存储 + +当前存在两套上传实现: + +### 9.1 Next.js MinIO 上传 + +路径:`app/api/upload-media/route.ts` + +- 接收 `multipart/form-data`。 +- 文件大小限制:20MB。 +- 生成对象 key:`{uploadPrefix}/{timestamp}_{random}.{ext}`。 +- 调用 `app/lib/minio/client.ts` 的 `putObject`。 +- 返回公开 URL。 + +关键环境变量: + +- `MINIO_ENDPOINT` +- `MINIO_PORT` +- `MINIO_USE_SSL` +- `MINIO_BUCKET` +- `MINIO_ACCESS_KEY` +- `MINIO_SECRET_KEY` +- `MINIO_REGION` +- `MINIO_PUBLIC_URL` +- `MINIO_UPLOAD_PREFIX` + +### 9.2 FastAPI 本地上传 + +路径:`backend/main.py` 的 `/api/upload-media` + +- 文件大小限制:20MB。 +- 写入 `settings.upload_dir`,默认 `backend/uploads`。 +- 通过 `/uploads/{name}` 静态路径提供访问。 +- 同时写 `media_assets` 集合。 + +### 9.3 当前部署观察 + +- Docker compose 中定义了 `nomadro-minio`,端口计划为 `127.0.0.1:9100` 和 `127.0.0.1:9101`。 +- 但当前 `docker ps` 只看到 `nomadro-ntfy` 运行,未看到 MinIO 容器。 +- `.env.local` 中存在 MinIO 配置项,但报告未记录敏感值。 + +建议尽快确认生产上传到底走 MinIO 还是 FastAPI 本地目录,并统一一条路径。 + +## 10. systemd 服务 + +### 10.1 NomadCNA Next.js + +服务名:`cnomadcna.service` +状态:enabled / active / running +工作目录:`/home/ubuntu/gitlab-instance-0a899031_cnomadcna` +启动脚本:`/home/ubuntu/gitlab-instance-0a899031_cnomadcna/cnomadcna.sh` +环境: + +- `NODE_ENV=production` +- `HOSTNAME=0.0.0.0` +- `PORT=4002` + +启动命令最终为: + +```bash +pnpm start +``` + +`package.json` 中 `start` 为: + +```bash +next start +``` + +当前运行: + +- 主进程:`node /usr/local/bin/pnpm start` +- 子进程:`next-server (v16.1.6)` +- 监听:`*:4002` +- 最近启动:2026-06-06 21:50 CST + +### 10.2 NomadCNA FastAPI + +服务名:`cnomadcna-api.service` +状态:enabled / active / running +工作目录:`/home/ubuntu/gitlab-instance-0a899031_cnomadcna` +环境文件:`/home/ubuntu/gitlab-instance-0a899031_cnomadcna/backend/.env` +启动命令: + +```bash +/home/ubuntu/gitlab-instance-0a899031_cnomadcna/backend/.venv/bin/uvicorn backend.main:app --host 127.0.0.1 --port 8000 +``` + +当前运行: + +- 主进程:`uvicorn` +- 监听:`127.0.0.1:8000` +- 最近启动:2026-06-06 21:46 CST + +### 10.3 PocketBase + +服务名:`pocketbase.service` +状态:enabled / active / running +工作目录:`/opt/pocketbase` +启动命令: + +```bash +/opt/pocketbase/pocketbase serve --http=127.0.0.1:8090 --dir=/opt/pocketbase/pb_data --origins=https://nomadro.cn,https://www.nomadro.cn,https://pocketbase.nomadro.cn +``` + +监听:`127.0.0.1:8090` + +### 10.4 Umami + +服务名:`umami.service` +状态:enabled / active / running +用户:`umami` +工作目录:`/opt/umami` +环境文件:`/opt/umami/.env.production` +启动命令: + +```bash +/usr/local/bin/node /opt/umami/.next/standalone/server.js +``` + +监听:`127.0.0.1:9280` +注意:最近日志有 Next.js Server Action 找不到的错误,可能来自旧前端请求或版本切换后的残留请求。 + +### 10.5 Netdata + +服务名:`netdata.service` +状态:enabled / active / running +监听:`127.0.0.1:19999` +Nginx 反代:`netdata.nomadro.cn`,带 Basic Auth。 + +### 10.6 其他同机服务 + +| 服务 | 状态 | 说明 | +| --- | --- | --- | +| `nginx` | running | 宝塔 Nginx,主反向代理 | +| `mysqld` | running | MariaDB/MySQL | +| `postgresql@16-main` | running | PostgreSQL 16,Umami 使用 | +| `docker` / `containerd` | running | Docker 运行时 | +| `pure-ftpd` | running | FTP | +| `frpp.service` | running | frp-panel | +| `site_total.service` | running | 宝塔站点统计 | +| `BT-FirewallServices.service` | running | 宝塔防火墙服务 | + +## 11. Nginx 反向代理 + +Nginx 配置路径:`/www/server/panel/vhost/nginx/` + +### 11.1 主站 + +配置文件:`/www/server/panel/vhost/nginx/www.nomadro.cn.conf` + +- upstream:`nomadro_nextjs` +- upstream 地址:`127.0.0.1:4002` +- `80` 端口:重定向到 HTTPS。 +- `443 ssl http2`:代理到 Next.js。 +- 证书:`/etc/letsencrypt/live/nomadro.cn/fullchain.pem` +- 日志: + - `/www/wwwlogs/www.nomadro.cn.log` + - `/www/wwwlogs/www.nomadro.cn.error.log` + +### 11.2 FastAPI + +配置文件:`/www/server/panel/vhost/nginx/api.nomadro.cn.conf` + +- upstream:`nomadro_api` +- upstream 地址:`127.0.0.1:8000` +- 当前只看到 HTTP server 配置。 +- 日志: + - `/www/wwwlogs/api.nomadro.cn.log` + - `/www/wwwlogs/api.nomadro.cn.error.log` + +建议为 `api.nomadro.cn` 配置 HTTPS,尤其是认证、支付、会员接口需要安全传输。 + +### 11.3 PocketBase + +配置文件:`/www/server/panel/vhost/nginx/pocketbase.nomadro.cn.conf` + +- upstream:`nomadro_pocketbase` +- upstream 地址:`127.0.0.1:8090` +- `80` 重定向到 HTTPS。 +- `443 ssl http2` 代理到 PocketBase。 +- 证书:`/etc/letsencrypt/live/pocketbase.nomadro.cn/fullchain.pem` + +### 11.4 Umami + +配置文件:`/www/server/panel/vhost/nginx/umami.nomadro.cn.conf` + +- upstream:`nomadro_umami` +- upstream 地址:`127.0.0.1:9280` +- `80` 重定向到 HTTPS。 +- `443 ssl http2` 代理到 Umami。 + +### 11.5 ntfy + +配置文件:`/www/server/panel/vhost/nginx/ntfy.nomadro.cn.conf` + +- upstream:`nomadro_ntfy` +- upstream 地址:`127.0.0.1:9180` +- 当前只看到 HTTP server 配置。 +- 建议后续补 HTTPS。 + +### 11.6 Netdata + +配置文件:`/www/server/panel/vhost/nginx/netdata.nomadro.cn.conf` + +- upstream:`nomadro_netdata` +- upstream 地址:`127.0.0.1:19999` +- 使用 Basic Auth 文件:`/www/server/panel/vhost/nginx/netdata.nomadro.cn.htpasswd` +- 当前只看到 HTTP server 配置。 + +### 11.7 Nginx 配置校验 + +已执行 Nginx 配置测试: + +```bash +nginx -t +``` + +结果:syntax ok,test successful。 + +## 12. TLS 证书 + +Certbot 当前证书: + +| 证书名 | 域名 | 到期时间 | +| --- | --- | --- | +| `nomadro.cn` | `nomadro.cn`, `www.nomadro.cn` | 2026-09-04 12:34:54 UTC | +| `pocketbase.nomadro.cn` | `pocketbase.nomadro.cn` | 2026-09-04 12:49:52 UTC | +| `umami.nomadro.cn` | `umami.nomadro.cn` | 2026-09-04 13:58:40 UTC | + +当前未看到 `api.nomadro.cn`、`ntfy.nomadro.cn`、`netdata.nomadro.cn` 的 Certbot 证书。 + +## 13. Docker 服务 + +当前 `docker ps` 只看到: + +| 容器 | 镜像 | 状态 | 端口 | +| --- | --- | --- | --- | +| `nomadro-ntfy` | `binwiederhier/ntfy:latest` | running | `127.0.0.1:9180->80` | + +`/opt/nomadro-services/docker-compose.yml` 中还定义了: + +- `nomadro-minio`:对象存储,计划监听 `127.0.0.1:9100` / `127.0.0.1:9101`。 +- `nomadro-ntfy`:通知推送。 +- `nomadro-uptime-kuma`:可用性监控,计划监听 `127.0.0.1:9301`。 +- `nomadro-netdata`:容器版 Netdata,计划监听 `127.0.0.1:9199`。 +- `nomadro-mirotalk`:视频会议,计划监听 `127.0.0.1:9300`。 + +实际运行和 compose 定义不完全一致。当前宿主机 systemd 版 Netdata 正在运行,Docker 版 Netdata 未运行。MinIO、Uptime Kuma、MiroTalk 当前也未在 `docker ps` 中出现。 + +## 14. 服务器资源与安全边界 + +### 14.1 系统信息 + +- 主机名:`VM-0-16-ubuntu` +- 云厂商:Tencent Cloud CVM +- 操作系统:Ubuntu 24.04.4 LTS +- 内核:Linux 6.8.0-101-generic +- 架构:x86_64 +- 运行时间:约 6 天 9 小时 + +### 14.2 资源状态 + +- 内存:3.6Gi,总可用约 2.5Gi。 +- Swap:1.9Gi,已用约 512Mi。 +- 根分区:69G,总用量 17G,可用 50G,使用率 25%。 +- 当前负载较低。 + +### 14.3 防火墙 + +UFW 状态:active +默认策略: + +- incoming:deny +- outgoing:allow +- routed:deny + +当前开放端口包括: + +- `80` +- `443` +- `22` +- `21` +- `20/tcp` +- `888/tcp` +- `8080` +- `36711/tcp` +- `39000:40000/tcp` +- 以及一个 `8` 规则 + +风险点: + +- FTP 端口 `20/21` 和被动端口段 `39000:40000` 对公网开放。 +- 宝塔面板端口 `888`、`36711` 对公网开放。 +- `22` 对公网开放。 +- `3306` MariaDB 当前监听 `0.0.0.0:3306`,即便 UFW 未列出 `3306` 开放,也建议数据库服务改为只监听本地或确保云防火墙关闭公网访问。 + +## 15. 环境变量与配置 + +### 15.1 根目录 `.env.local` + +当前项目根目录存在 `.env.local`,生产构建会加载它。已确认其包含以下类别变量: + +- 根域名:`ROOT_DOMAIN`、`NEXT_PUBLIC_ROOT_DOMAIN` +- PocketBase:`NEXT_PUBLIC_POCKETBASE_URL`、`POCKETBASE_URL` +- 支付:`PAYMENT_API_URL`、`PAYMENT_PROVIDER`、`PAYMENT_DEFAULT_AMOUNT`、`PAYMENT_JOIN_AMOUNT` +- 站点:`NEXT_PUBLIC_SITE_ID`、`NEXT_PUBLIC_SITE_URL`、`NEXT_PUBLIC_API_BASE_URL` +- MinIO:`MINIO_ENDPOINT`、`MINIO_PORT`、`MINIO_USE_SSL` +- PocketBase 管理员:`POCKETBASE_EMAIL`、`POCKETBASE_PASSWORD` + +### 15.2 FastAPI `backend/.env` + +当前 systemd 会读取 `backend/.env`,包含: + +- `PB_URL` +- `PB_ADMIN_EMAIL` +- `PB_ADMIN_PASSWORD` +- `API_COOKIE_NAME` +- `FRONTEND_ORIGINS` +- `UPLOAD_DIR` +- `DEV_AUTO_PAY` + +### 15.3 敏感文件 Git 风险 + +`git ls-files` 显示以下文件被 Git 跟踪: + +- `.env.example` +- `.env.local` +- `.env.local.bak.20260606212903` +- `backend/.env.example` + +其中 `.env.local` 和 `.env.local.bak.*` 不应被提交。`.env.example` 当前也包含真实样式的敏感配置,不应放真实账号或密码。 + +建议: + +1. 立即将 `.env.local` 和 `.env.local.bak.*` 从 Git 索引移除。 +2. 将 `.gitignore` 中的 `# .env*` 改为实际忽略规则。 +3. 重置已经暴露过的 PocketBase、支付、MinIO 等所有密钥。 +4. `.env.example` 只保留占位符,例如 `POCKETBASE_PASSWORD=replace_me`。 + +## 16. 构建与质量状态 + +### 16.1 `pnpm build` + +已执行: + +```bash +pnpm build +``` + +结果:通过。 + +构建输出: + +- Next.js `16.1.6` +- 成功编译。 +- TypeScript 检查通过。 +- 静态页面生成:85 个。 +- 路由包含 `/zh`、`/en` 以及所有主要页面。 +- API route 均被识别为动态服务端路由。 + +注意:本次构建刷新了 `.next` 产物时间戳,`.next/BUILD_ID` 时间为 2026-06-06 23:16 CST。 + +### 16.2 `pnpm lint` + +已执行: + +```bash +pnpm lint +``` + +结果:失败,`7 errors / 31 warnings`。 + +主要错误: + +- `app/[locale]/dashboard/page.tsx`:React Hooks 新规则提示 effect 内同步 `setLoading(true)`。 +- `app/api/meetup/complete-order/route.ts`:`userId` 和 `payType` 应使用 `const`。 +- `app/components/CityModal.tsx`:effect 内同步 `setMounted(true)`。 +- `app/components/SiteMenu.tsx`:effect 内同步 `setUserEmail(...)`。 +- `app/components/ThemeToggle.tsx`:effect 内同步 `setMounted(true)`。 +- `app/context/ThemeContext.tsx`:effect 内同步设置 theme/mounted。 + +主要警告: + +- 多处使用 ``,Next.js 建议使用 `next/image`。 +- 若干未使用变量。 +- `MembersMap.tsx` 有 hook 依赖提示。 + +结论: + +- 当前源码可以生产构建并运行。 +- 但 lint 不通过,CI 若以 lint 为发布门槛会失败。 +- 建议先修复 7 个 lint error,再逐步处理图片优化和未使用变量。 + +## 17. 当前运行日志观察 + +### 17.1 Next.js + +最近重启后正常启动,监听 `4002`。日志有 Node.js deprecation warning: + +- `util._extend` 已废弃,建议依赖链后续升级或等待 Next/相关依赖修复。 + +### 17.2 FastAPI + +最近启动正常。早些时候曾出现: + +- `PocketBase 404: Missing collection context.` + +随后 PocketBase 集合初始化后,`/api/cities`、`/api/profiles`、`/api/content/home` 已返回 `200`。 + +当前还看到外部或代理访问 `/` 和 `/favicon.ico` 到 FastAPI 时返回 `404`,这是正常的,因为 FastAPI 只提供 `/api/*` 和 `/uploads/*`。 + +### 17.3 PocketBase + +启动正常,REST API 和 Dashboard 均监听 `127.0.0.1:8090`。 + +### 17.4 Umami + +服务运行中,但日志出现 `Failed to find Server Action "000000..."`。可能是部署切换后旧请求、缓存或探测请求造成,需要后续观察。 + +### 17.5 宝塔 site_total + +`site_total.service` 日志持续出现写 HyperLogLog 文件失败,路径类似: + +- `/www/server/site_total/data/hll/2026-06-04/www.nomadro.cn.hll` +- `/www/server/site_total/data/hll/2026-06-04/ALL.hll` + +这不直接影响 NomadCNA 主站,但会影响宝塔站点统计准确性。 + +## 18. 运维命令速查 + +### 18.1 项目前端 + +```bash +cd /home/ubuntu/gitlab-instance-0a899031_cnomadcna +pnpm install +pnpm build +pnpm start +``` + +开发模式: + +```bash +pnpm dev +``` + +注意:`package.json` 中 dev 实际端口是 `3001`: + +```bash +next dev -p 3001 -H 0.0.0.0 +``` + +### 18.2 后端 + +```bash +cd /home/ubuntu/gitlab-instance-0a899031_cnomadcna +source backend/.venv/bin/activate +pip install -r backend/requirements.txt +uvicorn backend.main:app --host 127.0.0.1 --port 8000 +``` + +初始化 PocketBase 集合和种子: + +```bash +cd /home/ubuntu/gitlab-instance-0a899031_cnomadcna +source backend/.venv/bin/activate +python -m backend.init_db +``` + +### 18.3 systemd + +查看状态: + +```bash +systemctl status cnomadcna.service --no-pager -l +systemctl status cnomadcna-api.service --no-pager -l +systemctl status pocketbase.service --no-pager -l +systemctl status umami.service --no-pager -l +``` + +重启服务: + +```bash +systemctl restart cnomadcna.service +systemctl restart cnomadcna-api.service +systemctl restart pocketbase.service +``` + +查看日志: + +```bash +journalctl -u cnomadcna.service -n 100 --no-pager +journalctl -u cnomadcna-api.service -n 100 --no-pager +journalctl -u pocketbase.service -n 100 --no-pager +journalctl -u umami.service -n 100 --no-pager +``` + +### 18.4 Nginx + +测试配置: + +```bash +nginx -t +``` + +重载配置: + +```bash +systemctl reload nginx +``` + +主站日志: + +```bash +tail -f /www/wwwlogs/www.nomadro.cn.log +tail -f /www/wwwlogs/www.nomadro.cn.error.log +``` + +API 日志: + +```bash +tail -f /www/wwwlogs/api.nomadro.cn.log +tail -f /www/wwwlogs/api.nomadro.cn.error.log +``` + +### 18.5 健康检查 + +```bash +curl -fsS http://127.0.0.1:8000/api/health +curl -I http://127.0.0.1:4002/zh +curl -I http://127.0.0.1:8090/api/health +curl -fsS http://api.nomadro.cn/api/health +curl -I https://nomadro.cn +curl -I https://pocketbase.nomadro.cn/api/health +``` + +### 18.6 Docker 服务 + +```bash +docker ps +cd /opt/nomadro-services +docker compose ps +docker compose up -d +docker compose logs -f ntfy +``` + +## 19. 主要风险清单 + +### P0:敏感环境文件被 Git 跟踪 + +`.env.local` 和 `.env.local.bak.20260606212903` 已被 Git 跟踪。`.env.example` 也包含真实样式敏感信息。 +影响:密钥泄露风险。 +建议:从 Git 索引移除、重置所有已暴露密钥、改 `.env.example` 为占位符、更新 `.gitignore`。 + +### P0:API 子域未配置 HTTPS + +`api.nomadro.cn` 当前只看到 HTTP Nginx 配置。 +影响:登录态、支付确认、用户资料提交等请求如果走公网 HTTP,存在明文传输风险。 +建议:为 `api.nomadro.cn` 申请证书并强制 HTTP 到 HTTPS。 + +### P0:默认密码 `12345678` + +新用户支付后使用固定默认密码。 +影响:弱口令和撞库风险。 +建议:改为随机临时密码、一次性链接、强制首次设置密码。 + +### P1:会员集合不一致 + +Next.js 使用 `site_vip`,FastAPI 使用 `memberships`。 +影响:支付后不同接口可能返回不同会员状态。 +建议:统一会员表或明确同步策略。 + +### P1:MinIO 运行状态和代码配置不一致 + +代码中 Next.js 上传走 MinIO,但当前 Docker 只看到 `nomadro-ntfy`,未看到 MinIO 运行。 +影响:生产上传可能失败。 +建议:确认 MinIO 是否部署在其他机器/域名;如果是本机,启动并配置反代;如果不用 MinIO,统一改为 FastAPI 本地上传或其他对象存储。 + +### P1:Lint 不通过 + +`pnpm lint` 当前 7 个 error。 +影响:CI/CD、代码质量和后续维护。 +建议:优先修复 lint error,再处理 warning。 + +### P1:数据库与管理端口暴露面较大 + +MariaDB 监听 `0.0.0.0:3306`,FTP、宝塔面板、SSH 对公网开放。 +影响:攻击面扩大。 +建议:数据库只监听本地;管理端口限制 IP;SSH 使用密钥、禁用密码或更换端口;FTP 如非必要关闭。 + +### P2:`NEXT_PUBLIC_API_BASE_URL` 必须稳定设置 + +`app/lib/api-client.ts` 默认值是 `http://127.0.0.1:8000`。 +影响:若生产构建没有设置 `NEXT_PUBLIC_API_BASE_URL`,浏览器会访问用户本机 localhost。 +建议:生产环境固定设置为 API 公网域名,且优先升级到 HTTPS。 + +### P2:站点统计服务有错误日志 + +宝塔 `site_total` 无法写 hll 文件。 +影响:宝塔统计不准确。 +建议:检查目录是否存在、权限是否正确,或关闭无用统计。 + +### P2:同机服务较多 + +同机运行 NomadCNA、PocketBase、Umami、MariaDB、PostgreSQL、Docker、Netdata、FTP、宝塔、frp-panel。 +影响:故障面复杂,资源争用和安全边界不清晰。 +建议:为生产服务建立清晰分层,至少将数据库/监控/管理面板访问收紧。 + +## 20. 建议的下一步 + +### 20.1 立即处理 + +1. 清理 Git 中的 `.env.local`、`.env.local.bak.*`,重置所有相关密钥。 +2. 为 `api.nomadro.cn` 配置 HTTPS,并让前端 `NEXT_PUBLIC_API_BASE_URL` 使用 HTTPS。 +3. 统一 VIP 数据模型,确认 `site_vip` 是否存在并补充迁移。 +4. 修复 `pnpm lint` 的 7 个 error。 +5. 确认 MinIO 是否实际运行;若未运行,先修复上传链路。 + +### 20.2 一周内处理 + +1. 将默认密码机制改为随机临时密码或首次设置密码。 +2. 为 `ntfy.nomadro.cn`、`netdata.nomadro.cn` 补 HTTPS,或仅内网/白名单访问。 +3. 收紧 FTP、宝塔、SSH、MariaDB 的公网访问面。 +4. 为 PocketBase 数据目录建立自动备份策略。 +5. 添加 API smoke test,包括 `/api/health`、`/api/cities`、`/api/auth/me`、`/api/vip/check`、`/api/upload-media`。 + +### 20.3 产品增强 + +1. 城市数据接入真实来源,增加数据更新时间和数据来源说明。 +2. AI 助手接入真实模型,并基于用户画像、预算、收藏、路线生成建议。 +3. 站内消息接入 ntfy / 邮件 / 企业微信。 +4. 活动报名、赏金接单、服务咨询增加后台运营视图。 +5. 定价页与真实支付金额、会员权益完全一致。 +6. 对首页和城市卡片图片迁移到 `next/image` 或明确 CDN 图片策略。 + +## 21. 当前结论 + +NomadCNA 当前已经完成了数字游民网站的关键骨架: + +- 主站可通过 `nomadro.cn` 和 `www.nomadro.cn` 访问。 +- Next.js 生产服务、FastAPI、PocketBase 均在 systemd 中运行。 +- Nginx 已完成主站、PocketBase、Umami 的 HTTPS 反向代理。 +- FastAPI 健康接口、主站页面、PocketBase 健康接口均验证可用。 +- PocketBase 已有城市、内容、活动、讨论、赏金、成员、服务、路线、通知等完整业务集合。 +- 前端页面覆盖城市发现、下一站推荐、活动、匹配、工具、AI、赏金、服务、会员、报名、支付成功页和消息中心。 +- `pnpm build` 已通过,说明当前生产构建可用。 + +同时,当前最需要优先处理的是生产安全和一致性: + +- 敏感环境文件不能继续被 Git 跟踪。 +- API 域名需要 HTTPS。 +- 会员数据模型需要统一。 +- 固定默认密码需要替换。 +- 上传服务需要确认实际可用。 +- lint error 需要修复,以便后续稳定迭代。 + +整体判断:当前项目已经具备上线早期数字游民平台的基础能力,但在正式扩大用户规模前,应先完成密钥治理、HTTPS、会员模型、上传链路和 lint 修复。