Files
gitlab-instance-0a899031_cn…/NOMADCNA_PROJECT_DEPLOYMENT_REPORT.md
root b2fc70b403 s
2026-06-06 23:25:03 +08:00

37 KiB
Raw Blame History

游牧中国 NomadCNA 项目与服务器部署报告

生成时间2026-06-06 23:16 CST
服务器时区Asia/Shanghai / CST +0800
项目路径:/home/ubuntu/gitlab-instance-0a899031_cnomadcna
Git 分支:test2
最新提交:00b1c8e2026-06-06 23:05:17 +0800
报告范围:当前仓库代码、前端/后端/数据服务、服务器上实际运行的相关服务、反向代理、端口、构建状态、运维风险与后续建议。
敏感信息处理本报告只记录环境变量名、用途、路径、端口和域名不记录任何密码、Token、Access Key、Secret、数据库连接串原文。

1. 项目定位

NomadCNA / 游牧中国是一个面向数字游民的中文优先、英文可切换的一站式网站,当前定位可以概括为:

  • 数字游民城市决策平台:展示中国城市的成本、网速、安全、气候、社区活跃度、标签和详情。
  • 数字游民社区入口:提供报名、登录、会员、资料录入、同城活动、交友匹配、站内消息。
  • 数字游民服务市场:提供共享办公、城市落地顾问、保障类服务、赏金任务、反馈和咨询线索。
  • 数字游民内容与工具电子书、视频、报告、AI 助手、FIRE/汇率/签证/气候工具。
  • 生产部署站点:当前主域为 nomadro.cn / www.nomadro.cnPocketBase 为 pocketbase.nomadro.cnFastAPI 为 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 后端 APIsystemd 管理
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 返回 200Next.js 页面可访问。
  • http://127.0.0.1:8090/api/health 返回 200PocketBase 可访问。
  • 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.jsv22.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/uploadsNext.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,包含 .nextnode_modulesbackend/.venv 等运行产物。

5. 前端应用结构

5.1 国际化

  • 支持语言:zhen
  • 默认语言: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.tsapp/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_vipFastAPI 的会员检查不会识别。
  • 如果某些页面走 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:updatedvip: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.tsputObject
  • 返回公开 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:9100127.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

启动命令最终为:

pnpm start

package.jsonstart 为:

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
启动命令:

/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
启动命令:

/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
启动命令:

/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 16Umami 使用
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

  • upstreamnomadro_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

  • upstreamnomadro_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

  • upstreamnomadro_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

  • upstreamnomadro_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

  • upstreamnomadro_ntfy
  • upstream 地址:127.0.0.1:9180
  • 当前只看到 HTTP server 配置。
  • 建议后续补 HTTPS。

11.6 Netdata

配置文件:/www/server/panel/vhost/nginx/netdata.nomadro.cn.conf

  • upstreamnomadro_netdata
  • upstream 地址:127.0.0.1:19999
  • 使用 Basic Auth 文件:/www/server/panel/vhost/nginx/netdata.nomadro.cn.htpasswd
  • 当前只看到 HTTP server 配置。

11.7 Nginx 配置校验

已执行 Nginx 配置测试:

nginx -t

结果syntax oktest 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.cnntfy.nomadro.cnnetdata.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。
  • Swap1.9Gi,已用约 512Mi。
  • 根分区69G总用量 17G可用 50G使用率 25%。
  • 当前负载较低。

14.3 防火墙

UFW 状态active
默认策略:

  • incomingdeny
  • outgoingallow
  • routeddeny

当前开放端口包括:

  • 80
  • 443
  • 22
  • 21
  • 20/tcp
  • 888/tcp
  • 8080
  • 36711/tcp
  • 39000:40000/tcp
  • 以及一个 8 规则

风险点:

  • FTP 端口 20/21 和被动端口段 39000:40000 对公网开放。
  • 宝塔面板端口 88836711 对公网开放。
  • 22 对公网开放。
  • 3306 MariaDB 当前监听 0.0.0.0:3306,即便 UFW 未列出 3306 开放,也建议数据库服务改为只监听本地或确保云防火墙关闭公网访问。

15. 环境变量与配置

15.1 根目录 .env.local

当前项目根目录存在 .env.local,生产构建会加载它。已确认其包含以下类别变量:

  • 根域名:ROOT_DOMAINNEXT_PUBLIC_ROOT_DOMAIN
  • PocketBaseNEXT_PUBLIC_POCKETBASE_URLPOCKETBASE_URL
  • 支付:PAYMENT_API_URLPAYMENT_PROVIDERPAYMENT_DEFAULT_AMOUNTPAYMENT_JOIN_AMOUNT
  • 站点:NEXT_PUBLIC_SITE_IDNEXT_PUBLIC_SITE_URLNEXT_PUBLIC_API_BASE_URL
  • MinIOMINIO_ENDPOINTMINIO_PORTMINIO_USE_SSL
  • PocketBase 管理员:POCKETBASE_EMAILPOCKETBASE_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

已执行:

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

已执行:

pnpm lint

结果:失败,7 errors / 31 warnings

主要错误:

  • app/[locale]/dashboard/page.tsxReact Hooks 新规则提示 effect 内同步 setLoading(true)
  • app/api/meetup/complete-order/route.tsuserIdpayType 应使用 const
  • app/components/CityModal.tsxeffect 内同步 setMounted(true)
  • app/components/SiteMenu.tsxeffect 内同步 setUserEmail(...)
  • app/components/ThemeToggle.tsxeffect 内同步 setMounted(true)
  • app/context/ThemeContext.tsxeffect 内同步设置 theme/mounted。

主要警告:

  • 多处使用 <img>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 项目前端

cd /home/ubuntu/gitlab-instance-0a899031_cnomadcna
pnpm install
pnpm build
pnpm start

开发模式:

pnpm dev

注意:package.json 中 dev 实际端口是 3001

next dev -p 3001 -H 0.0.0.0

18.2 后端

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 集合和种子:

cd /home/ubuntu/gitlab-instance-0a899031_cnomadcna
source backend/.venv/bin/activate
python -m backend.init_db

18.3 systemd

查看状态:

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

重启服务:

systemctl restart cnomadcna.service
systemctl restart cnomadcna-api.service
systemctl restart pocketbase.service

查看日志:

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

测试配置:

nginx -t

重载配置:

systemctl reload nginx

主站日志:

tail -f /www/wwwlogs/www.nomadro.cn.log
tail -f /www/wwwlogs/www.nomadro.cn.error.log

API 日志:

tail -f /www/wwwlogs/api.nomadro.cn.log
tail -f /www/wwwlogs/api.nomadro.cn.error.log

18.5 健康检查

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 服务

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

P0API 子域未配置 HTTPS

api.nomadro.cn 当前只看到 HTTP Nginx 配置。
影响:登录态、支付确认、用户资料提交等请求如果走公网 HTTP存在明文传输风险。
建议:为 api.nomadro.cn 申请证书并强制 HTTP 到 HTTPS。

P0默认密码 12345678

新用户支付后使用固定默认密码。
影响:弱口令和撞库风险。
建议:改为随机临时密码、一次性链接、强制首次设置密码。

P1会员集合不一致

Next.js 使用 site_vipFastAPI 使用 memberships
影响:支付后不同接口可能返回不同会员状态。
建议:统一会员表或明确同步策略。

P1MinIO 运行状态和代码配置不一致

代码中 Next.js 上传走 MinIO但当前 Docker 只看到 nomadro-ntfy,未看到 MinIO 运行。
影响:生产上传可能失败。
建议:确认 MinIO 是否部署在其他机器/域名;如果是本机,启动并配置反代;如果不用 MinIO统一改为 FastAPI 本地上传或其他对象存储。

P1Lint 不通过

pnpm lint 当前 7 个 error。
影响CI/CD、代码质量和后续维护。
建议:优先修复 lint error再处理 warning。

P1数据库与管理端口暴露面较大

MariaDB 监听 0.0.0.0:3306FTP、宝塔面板、SSH 对公网开放。
影响:攻击面扩大。
建议:数据库只监听本地;管理端口限制 IPSSH 使用密钥、禁用密码或更换端口FTP 如非必要关闭。

P2NEXT_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.cnnetdata.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.cnwww.nomadro.cn 访问。
  • Next.js 生产服务、FastAPI、PocketBase 均在 systemd 中运行。
  • Nginx 已完成主站、PocketBase、Umami 的 HTTPS 反向代理。
  • FastAPI 健康接口、主站页面、PocketBase 健康接口均验证可用。
  • PocketBase 已有城市、内容、活动、讨论、赏金、成员、服务、路线、通知等完整业务集合。
  • 前端页面覆盖城市发现、下一站推荐、活动、匹配、工具、AI、赏金、服务、会员、报名、支付成功页和消息中心。
  • pnpm build 已通过,说明当前生产构建可用。

同时,当前最需要优先处理的是生产安全和一致性:

  • 敏感环境文件不能继续被 Git 跟踪。
  • API 域名需要 HTTPS。
  • 会员数据模型需要统一。
  • 固定默认密码需要替换。
  • 上传服务需要确认实际可用。
  • lint error 需要修复,以便后续稳定迭代。

整体判断当前项目已经具备上线早期数字游民平台的基础能力但在正式扩大用户规模前应先完成密钥治理、HTTPS、会员模型、上传链路和 lint 修复。