# 游牧中国 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 修复。