readme
This commit is contained in:
642
README.md
642
README.md
@@ -1,110 +1,618 @@
|
||||
# 游牧中国 NomadCNA
|
||||
|
||||
数字游民生活操作系统 (Nomad OS) - 你的下一站,由数据决定
|
||||
NomadCNA 是面向数字游民的生活操作系统,用一个站点承载城市决策、会员加入、线上/线下活动、视频会议、Web 群聊、内容资源、任务赏金、支付和媒体存储等能力。
|
||||
|
||||
## 项目简介
|
||||
生产站点:
|
||||
|
||||
NomadCNA 是一个面向数字游民的站式生活平台,提供城市决策、税务签证、智能匹配、赏金任务等功能。从 Free 到 Pro,开启你的游牧人生。
|
||||
- 主站:https://nomadro.cn
|
||||
- API:https://api.nomadro.cn
|
||||
- PocketBase:https://pocketbase.nomadro.cn
|
||||
- MinIO:https://minio.nomadro.cn
|
||||
- MiroTalk P2P 视频房:https://mirotalk.nomadro.cn
|
||||
- Web 群聊:https://lounge.nomadro.cn
|
||||
- IRC 服务名:https://ergo.nomadro.cn
|
||||
|
||||
## 业务介绍
|
||||
|
||||
NomadCNA 的目标用户是正在中国或亚洲范围内长期旅居、远程工作、寻找社群和机会的数字游民。业务上分为以下几条主线:
|
||||
|
||||
| 模块 | 说明 |
|
||||
| --- | --- |
|
||||
| 城市探索 | 展示中国数字游民城市数据,包括生活成本、网络、温度、社群密度、安全、文化等指标。 |
|
||||
| 下一站决策 | 根据预算、网络、气候、标签偏好生成城市推荐。 |
|
||||
| 线上/线下活动 | 支持公开、登录成员、VIP、主持人等权限层级;线上和混合活动可进入 MiroTalk 视频房。 |
|
||||
| Web 群聊 | 使用 The Lounge + Ergo IRC Server 提供数字游民 Web 群组聊天,活动参与人可进入群聊。 |
|
||||
| 会员加入与支付 | 支持加入表单、支付订单、支付状态轮询、VIP/会员写入。 |
|
||||
| Digital 子站 | `/digital` 是内容专题站,包含数字游民指南、课程、电子书、资源、工作机会、个人资料等。 |
|
||||
| 媒体与内容 | 支持图片/视频上传、远程媒体代理缓存、内容投稿、博客、电子书、视频等内容页面。 |
|
||||
| 社区与增长 | 包含讨论、交友匹配、任务赏金、反馈、通知、站内消息、服务线索。 |
|
||||
|
||||
## 技术栈
|
||||
|
||||
- **前端框架**: Next.js 16 (App Router)
|
||||
- **UI 框架**: React 19 + Tailwind CSS 4
|
||||
- **样式**: Tailwind CSS
|
||||
- **字体**: Geist (Vercel)
|
||||
- **数据库**: PocketBase
|
||||
- **对象存储**: MinIO
|
||||
- **语言**: TypeScript
|
||||
| 层级 | 技术 |
|
||||
| --- | --- |
|
||||
| Web 前端 | Next.js 16 App Router、React 19、TypeScript、Tailwind CSS 4 |
|
||||
| API | Next.js Route Handlers、FastAPI、PocketBase SDK/HTTP |
|
||||
| 数据 | PocketBase、静态数据、MinIO 对象存储 |
|
||||
| 支付 | ZPay / XorPay 适配层 |
|
||||
| 视频会议 | MiroTalk P2P,Nginx HTTPS 反代 |
|
||||
| Web 群聊 | The Lounge 4.5.0 + Ergo IRC Server 2.18.0 |
|
||||
| 部署 | systemd、Nginx、Certbot、Docker |
|
||||
| 包管理 | pnpm 10.25.0 |
|
||||
|
||||
## 功能特性
|
||||
生产服务器当前 Node.js 版本为 `v22.13.1`。
|
||||
|
||||
- 🌏 **城市探索** - 发现最适合数字游民的中国城市
|
||||
- 📍 **城市数据** - 成本、生活质量、网络速度等数据对比
|
||||
- 🎯 **智能匹配** - 根据个人偏好推荐适合的城市
|
||||
- 🤝 **社区聚会** - 与各地游民建立联系
|
||||
- 💬 **社区互动** - 论坛、话题讨论
|
||||
- 🛠️ **实用工具** - 汇率、天气等实用工具
|
||||
- 🌙 **暗色模式** - 支持亮色/暗色主题切换
|
||||
- 🌐 **国际化** - 支持中文/英文
|
||||
## 源码解析
|
||||
|
||||
## 快速开始
|
||||
### 顶层结构
|
||||
|
||||
```text
|
||||
.
|
||||
├── app/ # Next.js App Router 主目录
|
||||
│ ├── [locale]/ # 中文/英文路由,默认 zh
|
||||
│ ├── api/ # Next.js Route Handlers
|
||||
│ ├── components/ # 主站通用组件
|
||||
│ ├── context/ # Locale、Theme 等上下文
|
||||
│ ├── data/ # 城市、地图、mock 数据
|
||||
│ ├── digital/ # Digital 子站组件、配置、数据和工具
|
||||
│ └── lib/ # API、支付、媒体、活动、PocketBase 等工具
|
||||
├── backend/ # FastAPI 后端
|
||||
├── config/ # 主站和 Digital 子站配置
|
||||
├── i18n/ # 路由和国际化导航封装
|
||||
├── messages/ # zh/en 文案
|
||||
├── public/ # 静态资源
|
||||
├── cnomadcna.sh # 生产 Next.js 启动脚本
|
||||
├── next.config.ts # Next.js 配置与 API rewrites
|
||||
├── package.json # 前端依赖与脚本
|
||||
└── tsconfig.json # TypeScript 配置
|
||||
```
|
||||
|
||||
### Next.js 页面结构
|
||||
|
||||
主站所有面向用户的页面位于 `app/[locale]`,路由强制带语言前缀:
|
||||
|
||||
- `/zh`、`/en`:首页与城市探索
|
||||
- `/zh/dashboard`:下一站决策仪表盘
|
||||
- `/zh/meetups`:线上/线下活动,含 MiroTalk 视频房和 Web 群聊入口
|
||||
- `/zh/meetups/host`:活动发布页
|
||||
- `/zh/dating`:社区交友/匹配
|
||||
- `/zh/discuss`:讨论
|
||||
- `/zh/gigs`:任务赏金
|
||||
- `/zh/tools`:工具箱
|
||||
- `/zh/report`、`/zh/report/data`:统计与年报
|
||||
- `/zh/digital`:Digital 子站入口
|
||||
|
||||
通用布局与组件:
|
||||
|
||||
- `app/layout.tsx`:根布局
|
||||
- `app/[locale]/layout.tsx`:语言布局
|
||||
- `app/components/Navbar.tsx`、`Footer.tsx`、`Sidebar.tsx`:主站导航与外壳
|
||||
- `app/context/LocaleContext.tsx`:运行时文案读取
|
||||
- `app/context/ThemeContext.tsx`:亮色/暗色主题
|
||||
|
||||
### Digital 子站
|
||||
|
||||
Digital 子站代码集中在 `app/digital` 与 `app/[locale]/digital`:
|
||||
|
||||
- `app/[locale]/digital/page.tsx`:专题首页
|
||||
- `app/[locale]/digital/course`:课程页
|
||||
- `app/[locale]/digital/course/[moduleIndex]/[lessonIndex]`:课程章节
|
||||
- `app/[locale]/digital/ebook`:电子书
|
||||
- `app/[locale]/digital/jobs`:远程工作
|
||||
- `app/[locale]/digital/join`:加入/申请
|
||||
- `app/[locale]/digital/profile`:用户资料
|
||||
|
||||
配置在 `config/digital`:
|
||||
|
||||
- `site.config.ts`:专题主题、功能开关、课程/电子书/加入等能力
|
||||
- `services.config.ts`:PocketBase、支付、MinIO 配置读取
|
||||
- `domain.config.ts`:域名和服务地址推导
|
||||
- `course.ts`、`lessons.ts`:课程数据
|
||||
|
||||
### API 分层
|
||||
|
||||
本项目有两层 API:
|
||||
|
||||
1. Next.js 内置 API:`app/api/*`
|
||||
2. FastAPI 后端:`backend/main.py`
|
||||
|
||||
`next.config.ts` 将大多数 `/api/*` 转发到 FastAPI:
|
||||
|
||||
```ts
|
||||
source: "/api/:path((?!(?:digital|media)(?:$|/.*)).*)"
|
||||
destination: "http://127.0.0.1:8000/api/:path*"
|
||||
```
|
||||
|
||||
因此:
|
||||
|
||||
- `/api/digital/*` 由 Next.js Route Handlers 处理
|
||||
- `/api/media/*` 由 Next.js Route Handlers 处理
|
||||
- 其他 `/api/*` 默认转发到 FastAPI
|
||||
|
||||
### Next.js API
|
||||
|
||||
| 路径 | 作用 |
|
||||
| --- | --- |
|
||||
| `app/api/digital/auth/*` | Digital 子站登录、退出、当前用户、注册、跨站同步 |
|
||||
| `app/api/digital/join` | Digital 加入/申请表单写入 PocketBase |
|
||||
| `app/api/digital/pay/*` | Digital 支付创建、确认、状态查询 |
|
||||
| `app/api/digital/upload-media` | 媒体上传到 MinIO |
|
||||
| `app/api/digital/vip/check` | VIP 状态检查 |
|
||||
| `app/api/media/proxy` | 远程媒体抓取、校验、缓存到 MinIO 后跳转公开 URL |
|
||||
|
||||
### FastAPI 后端
|
||||
|
||||
FastAPI 入口为 `backend/main.py`,配置读取在 `backend/settings.py`。核心能力:
|
||||
|
||||
| API | 作用 |
|
||||
| --- | --- |
|
||||
| `/api/health` | 健康检查 |
|
||||
| `/api/auth/email`、`/api/auth/google`、`/api/auth/me` | 主站认证 |
|
||||
| `/api/join`、`/api/join/status` | 加入表单与状态 |
|
||||
| `/api/upload-media` | 后端媒体上传 |
|
||||
| `/api/pay`、`/api/pay/status` | 支付创建与查询 |
|
||||
| `/cnomadcna/*_notify` | 支付网关回调 |
|
||||
| `/api/cities`、`/api/cities/{slug}` | 城市数据 |
|
||||
| `/api/content/*` | 首页内容、内容投稿、内容详情 |
|
||||
| `/api/notifications/*` | 通知、回执、偏好 |
|
||||
| `/api/recommendations/next-stop` | 下一站推荐 |
|
||||
| `/api/meetups` | 活动列表与活动创建 |
|
||||
| `/api/discussions` | 讨论列表与创建 |
|
||||
| `/api/gigs` | 任务赏金列表、创建、申请 |
|
||||
| `/api/profiles`、`/api/matches/swipes` | 资料与匹配 |
|
||||
| `/api/feedback` | 用户反馈 |
|
||||
| `/api/stats/*` | 成员地图、概览、城市排行 |
|
||||
| `/api/services`、`/api/services/leads` | 增值服务与线索 |
|
||||
| `/api/ai/assistant` | AI 助手占位接口 |
|
||||
|
||||
后端辅助模块:
|
||||
|
||||
- `backend/pb_client.py`:PocketBase HTTP 客户端
|
||||
- `backend/payment.py`:ZPay / XorPay 支付适配
|
||||
- `backend/minio_storage.py`:MinIO 上传
|
||||
- `backend/init_db.py`、`seed_data.py`、`enhanced_seed.py`:初始化与种子数据
|
||||
- `backend/settings.py`:环境变量读取
|
||||
|
||||
### 活动、视频与群聊源码
|
||||
|
||||
活动相关逻辑主要在:
|
||||
|
||||
- `app/[locale]/meetups/page.tsx`
|
||||
- `app/[locale]/meetups/host/page.tsx`
|
||||
- `app/lib/meetups.ts`
|
||||
|
||||
`app/lib/meetups.ts` 负责:
|
||||
|
||||
- MiroTalk 默认地址:`https://mirotalk.nomadro.cn`
|
||||
- MiroTalk 房间名规范化
|
||||
- MiroTalk 入会链接生成
|
||||
- Lounge 默认地址:`https://lounge.nomadro.cn`
|
||||
- Web 群聊服务标签:`The Lounge + Ergo IRC`
|
||||
|
||||
线上/混合活动详情页会展示:
|
||||
|
||||
- MiroTalk P2P 视频入口
|
||||
- 页面内 iframe 打开视频房
|
||||
- The Lounge Web 群聊入口
|
||||
- 信令/中继服务器和群聊入口域名
|
||||
|
||||
### 配置与国际化
|
||||
|
||||
| 文件 | 作用 |
|
||||
| --- | --- |
|
||||
| `config/site.config.ts` | 主站 SEO 与站点基础信息 |
|
||||
| `config/nav.config.ts` | 顶部导航 |
|
||||
| `config/footer.config.ts` | 页脚 |
|
||||
| `config/services.config.ts` | 主站支付配置 |
|
||||
| `config/runtime-env.ts` | 运行环境判断 |
|
||||
| `config/digital/*` | Digital 子站主题、服务、课程、域名配置 |
|
||||
| `messages/zh.json`、`messages/en.json` | 中英文文案 |
|
||||
| `i18n/routing.ts` | 语言列表与默认语言 |
|
||||
| `i18n/navigation.ts` | 语言路由 Link / Router 封装 |
|
||||
|
||||
## 本地开发
|
||||
|
||||
### 环境要求
|
||||
|
||||
- Node.js 18+
|
||||
- npm / yarn / pnpm / bun
|
||||
- Node.js 20+,生产当前使用 Node.js 22.13.1
|
||||
- pnpm 10+
|
||||
- Python 3.12+
|
||||
- PocketBase
|
||||
- 可选:MinIO、ZPay/XorPay 测试配置
|
||||
|
||||
### 安装依赖
|
||||
|
||||
```bash
|
||||
npm install
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### 开发模式
|
||||
### 前端开发
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
打开 [http://localhost:3000](http://localhost:3000) 查看项目。
|
||||
默认启动在:
|
||||
|
||||
### 生产构建
|
||||
```text
|
||||
http://localhost:3001
|
||||
```
|
||||
|
||||
### FastAPI 后端开发
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npm start
|
||||
python3 -m venv backend/.venv
|
||||
source backend/.venv/bin/activate
|
||||
pip install -r backend/requirements.txt
|
||||
uvicorn backend.main:app --host 127.0.0.1 --port 8000 --reload
|
||||
```
|
||||
|
||||
## 项目结构
|
||||
### 构建与启动
|
||||
|
||||
```
|
||||
├── app/ # Next.js App Router
|
||||
│ ├── components/ # React 组件
|
||||
│ ├── context/ # React Context (主题等)
|
||||
│ ├── lib/ # 工具库
|
||||
│ └── [locale]/ # 国际化路由
|
||||
├── config/ # 配置文件
|
||||
│ ├── site.config.ts # 站点配置
|
||||
│ ├── nav.config.ts # 导航配置
|
||||
│ ├── footer.config.ts # 页脚配置
|
||||
│ └── ...
|
||||
├── public/ # 静态资源
|
||||
└── i18n/ # 国际化配置
|
||||
```bash
|
||||
pnpm build
|
||||
pnpm start
|
||||
```
|
||||
|
||||
## 主要页面
|
||||
### 常用检查
|
||||
|
||||
- `/` - 首页 (城市探索)
|
||||
- `/about` - 关于我们
|
||||
- `/meetups` - 聚会活动
|
||||
- `/dating` - 社区交友
|
||||
- `/tools` - 实用工具
|
||||
- `/ai` - AI 助手
|
||||
- `/gigs` - 赏金任务
|
||||
- `/pricing` - 会员价格
|
||||
- `/join` - 加入社区
|
||||
```bash
|
||||
pnpm lint
|
||||
pnpm exec tsc --noEmit --pretty false
|
||||
APP_ENV=production NEXT_PUBLIC_APP_ENV=production NODE_ENV=production pnpm build
|
||||
```
|
||||
|
||||
## 配置
|
||||
## 环境变量
|
||||
|
||||
### 主题配置
|
||||
不要把真实密钥提交到 Git。`.env.example` 只放示例值,生产值放 `.env.local`、`backend/.env` 或 systemd Environment。
|
||||
|
||||
主题相关逻辑位于 `app/context/ThemeContext.tsx`,支持:
|
||||
- 手动切换亮色/暗色模式
|
||||
- 记住用户偏好 (localStorage)
|
||||
- 跟随系统设置
|
||||
### 前端公开变量
|
||||
|
||||
### 导航配置
|
||||
| 变量 | 说明 |
|
||||
| --- | --- |
|
||||
| `APP_ENV` | `development` / `production` |
|
||||
| `NEXT_PUBLIC_APP_ENV` | 浏览器可见运行环境 |
|
||||
| `NEXT_PUBLIC_SITE_URL` | 站点根地址 |
|
||||
| `NEXT_PUBLIC_SITE_ID` | 站点 ID,用于会员/VIP 隔离 |
|
||||
| `NEXT_PUBLIC_API_BASE_URL` | API 基础地址,生产通常为 `/api` |
|
||||
| `NEXT_PUBLIC_POCKETBASE_URL` | 浏览器可访问 PocketBase 地址 |
|
||||
| `NEXT_PUBLIC_MIROTALK_URL` | MiroTalk P2P 服务地址 |
|
||||
| `NEXT_PUBLIC_LOUNGE_URL` | The Lounge Web 群聊地址 |
|
||||
| `NEXT_PUBLIC_MINIO_PUBLIC_URL` | MinIO 文件公开地址 |
|
||||
|
||||
导航链接位于 `config/nav.config.ts`,可自定义修改。
|
||||
### 后端和服务端变量
|
||||
|
||||
### 页脚配置
|
||||
| 变量 | 说明 |
|
||||
| --- | --- |
|
||||
| `POCKETBASE_URL` | 服务端访问 PocketBase 的内网地址 |
|
||||
| `POCKETBASE_EMAIL` | PocketBase 管理员邮箱 |
|
||||
| `POCKETBASE_PASSWORD` | PocketBase 管理员密码 |
|
||||
| `PAYMENT_API_URL` | 支付 API 地址 |
|
||||
| `PAYMENT_PROVIDER` | `zpay` 或 `xorpay` |
|
||||
| `PAYMENT_DEFAULT_AMOUNT` | 默认支付金额 |
|
||||
| `PAYMENT_JOIN_AMOUNT` | 加入场景金额 |
|
||||
| `PAYMENT_JOIN_TYPE` | 加入场景订单类型 |
|
||||
| `ZPAY_PID`、`ZPAY_KEY` | ZPay 商户配置 |
|
||||
| `XORPAY_AID`、`XORPAY_SECRET` | XorPay 商户配置 |
|
||||
| `MINIO_ENDPOINT` | MinIO 内网端点 |
|
||||
| `MINIO_PORT` | MinIO 端口 |
|
||||
| `MINIO_USE_SSL` | 是否对 MinIO 内网连接启用 SSL |
|
||||
| `MINIO_BUCKET` | 存储桶 |
|
||||
| `MINIO_ACCESS_KEY` | MinIO Access Key |
|
||||
| `MINIO_SECRET_KEY` | MinIO Secret Key |
|
||||
| `MINIO_REGION` | MinIO 区域 |
|
||||
| `MINIO_UPLOAD_PREFIX` | 上传路径前缀 |
|
||||
| `FRONTEND_ORIGINS` | FastAPI CORS 白名单 |
|
||||
| `UPLOAD_DIR` | 后端本地上传目录 |
|
||||
|
||||
页脚链接位于 `config/footer.config.ts`,可自定义修改。
|
||||
## 生产服务器支持
|
||||
|
||||
## 贡献指南
|
||||
生产代码目录:
|
||||
|
||||
欢迎提交 Pull Request 和 Issue!
|
||||
```text
|
||||
/home/ubuntu/gitlab-instance-0a899031_cnomadcna
|
||||
```
|
||||
|
||||
## 许可证
|
||||
### 域名与服务映射
|
||||
|
||||
MIT License
|
||||
| 域名 | 上游 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `nomadro.cn` / `www.nomadro.cn` | `127.0.0.1:4002` | Next.js 主站,`cnomadcna.service` |
|
||||
| `api.nomadro.cn` | `127.0.0.1:8000` | FastAPI |
|
||||
| `pocketbase.nomadro.cn` | `127.0.0.1:8090` | PocketBase |
|
||||
| `minio.nomadro.cn` | `127.0.0.1:9100` / `9101` | MinIO API / Console |
|
||||
| `mirotalk.nomadro.cn` | `127.0.0.1:9300` | MiroTalk P2P |
|
||||
| `lounge.nomadro.cn` | `127.0.0.1:9000` | The Lounge Web IRC |
|
||||
| `ergo.nomadro.cn` | HTTPS redirect | 跳转到 `lounge.nomadro.cn`;IRC 后端只内网监听 |
|
||||
| `ntfy.nomadro.cn` | `127.0.0.1:9180` | ntfy 通知服务 |
|
||||
|
||||
### systemd 服务
|
||||
|
||||
| 服务 | 作用 | 当前策略 |
|
||||
| --- | --- | --- |
|
||||
| `cnomadcna.service` | Next.js 生产服务 | enabled,监听 `0.0.0.0:4002` |
|
||||
| `mirotalk-p2p.service` | MiroTalk P2P | enabled,监听 `127.0.0.1:9300` |
|
||||
| `ergo.service` | Ergo IRC Server | enabled,监听 `127.0.0.1:6667` 和 `[::1]:6667` |
|
||||
| `thelounge.service` | The Lounge Web IRC | enabled,监听 `127.0.0.1:9000` |
|
||||
|
||||
常用命令:
|
||||
|
||||
```bash
|
||||
systemctl status cnomadcna.service
|
||||
systemctl status mirotalk-p2p.service
|
||||
systemctl status ergo.service
|
||||
systemctl status thelounge.service
|
||||
|
||||
journalctl -u cnomadcna.service -n 100 --no-pager
|
||||
journalctl -u mirotalk-p2p.service -n 100 --no-pager
|
||||
journalctl -u ergo.service -n 100 --no-pager
|
||||
journalctl -u thelounge.service -n 100 --no-pager
|
||||
```
|
||||
|
||||
### Docker 服务
|
||||
|
||||
当前生产容器:
|
||||
|
||||
| 容器 | 镜像 | 端口 |
|
||||
| --- | --- | --- |
|
||||
| `nomadro-minio` | `minio/minio:latest` | `127.0.0.1:9100->9000`,`127.0.0.1:9101->9001` |
|
||||
| `nomadro-ntfy` | `binwiederhier/ntfy:latest` | `127.0.0.1:9180->80` |
|
||||
|
||||
检查:
|
||||
|
||||
```bash
|
||||
docker ps
|
||||
docker logs nomadro-minio --tail 100
|
||||
docker logs nomadro-ntfy --tail 100
|
||||
```
|
||||
|
||||
### Nginx
|
||||
|
||||
Nginx vhost 目录:
|
||||
|
||||
```text
|
||||
/www/server/panel/vhost/nginx
|
||||
```
|
||||
|
||||
关键配置:
|
||||
|
||||
- `www.nomadro.cn.conf`:主站
|
||||
- `api.nomadro.cn.conf`:FastAPI
|
||||
- `mirotalk.nomadro.cn.conf`:MiroTalk
|
||||
- `lounge.nomadro.cn.conf`:The Lounge + Ergo redirect
|
||||
- `minio.nomadro.cn.conf`:MinIO
|
||||
- `pocketbase.nomadro.cn.conf`:PocketBase
|
||||
|
||||
常用命令:
|
||||
|
||||
```bash
|
||||
nginx -t
|
||||
nginx -s reload
|
||||
```
|
||||
|
||||
### HTTPS 证书
|
||||
|
||||
证书由 Certbot 管理。`lounge.nomadro.cn` 证书包含两个域名:
|
||||
|
||||
```text
|
||||
lounge.nomadro.cn
|
||||
ergo.nomadro.cn
|
||||
```
|
||||
|
||||
当前证书路径:
|
||||
|
||||
```text
|
||||
/etc/letsencrypt/live/lounge.nomadro.cn/fullchain.pem
|
||||
/etc/letsencrypt/live/lounge.nomadro.cn/privkey.pem
|
||||
```
|
||||
|
||||
检查:
|
||||
|
||||
```bash
|
||||
certbot certificates
|
||||
```
|
||||
|
||||
### MiroTalk P2P
|
||||
|
||||
安装目录:
|
||||
|
||||
```text
|
||||
/opt/nomadro-services/mirotalk
|
||||
```
|
||||
|
||||
运行方式:
|
||||
|
||||
- systemd:`mirotalk-p2p.service`
|
||||
- 内网端口:`127.0.0.1:9300`
|
||||
- 公网入口:`https://mirotalk.nomadro.cn`
|
||||
- 活动页自动生成链接:`https://mirotalk.nomadro.cn/join?room=...&name=...`
|
||||
|
||||
健康检查:
|
||||
|
||||
```bash
|
||||
curl -I https://mirotalk.nomadro.cn/join?room=nomadcna-healthcheck
|
||||
```
|
||||
|
||||
### Ergo IRC Server
|
||||
|
||||
安装目录:
|
||||
|
||||
```text
|
||||
/opt/ergo
|
||||
```
|
||||
|
||||
配置:
|
||||
|
||||
```text
|
||||
/etc/ergo/ircd.yaml
|
||||
/etc/ergo/ergo.motd
|
||||
/var/lib/ergo/ircd.db
|
||||
```
|
||||
|
||||
当前策略:
|
||||
|
||||
- 网络名:`NomadCNA`
|
||||
- 服务名:`ergo.nomadro.cn`
|
||||
- 只监听本机 `127.0.0.1:6667` 和 `[::1]:6667`
|
||||
- 不开放公网 IRC TLS `6697`
|
||||
- `ergo.nomadro.cn` 的 HTTPS 请求跳转到 The Lounge
|
||||
|
||||
本机 IRC 握手检查:
|
||||
|
||||
```bash
|
||||
{ printf 'NICK health\r\nUSER health 0 * :NomadCNA Health\r\nJOIN #nomadcna\r\nQUIT :healthcheck\r\n'; sleep 1; } \
|
||||
| timeout 5s nc 127.0.0.1 6667
|
||||
```
|
||||
|
||||
### The Lounge Web 群聊
|
||||
|
||||
安装目录:
|
||||
|
||||
```text
|
||||
/opt/nomadro-services/thelounge
|
||||
```
|
||||
|
||||
配置:
|
||||
|
||||
```text
|
||||
/var/lib/thelounge/config.js
|
||||
```
|
||||
|
||||
当前策略:
|
||||
|
||||
- public mode
|
||||
- 只监听 `127.0.0.1:9000`
|
||||
- Nginx 通过 `https://lounge.nomadro.cn` 反代
|
||||
- 默认网络锁定到本机 Ergo:`127.0.0.1:6667`
|
||||
- 默认加入频道:`#nomadcna,#online-events`
|
||||
- 文件上传关闭
|
||||
- The Lounge 自身消息持久化关闭,Ergo 保留内存历史
|
||||
|
||||
健康检查:
|
||||
|
||||
```bash
|
||||
curl -I https://lounge.nomadro.cn/
|
||||
curl 'https://lounge.nomadro.cn/socket.io/?EIO=4&transport=polling&t=health'
|
||||
```
|
||||
|
||||
## 上线流程
|
||||
|
||||
### 前端上线
|
||||
|
||||
```bash
|
||||
cd /home/ubuntu/gitlab-instance-0a899031_cnomadcna
|
||||
APP_ENV=production NEXT_PUBLIC_APP_ENV=production NODE_ENV=production pnpm build
|
||||
systemctl restart cnomadcna.service
|
||||
systemctl status cnomadcna.service --no-pager
|
||||
```
|
||||
|
||||
### 后端上线
|
||||
|
||||
FastAPI 当前运行在 `127.0.0.1:8000`。更新后需重启对应 uvicorn 进程或其 systemd 服务。如果后续为 FastAPI 增加 systemd 单元,建议命名为:
|
||||
|
||||
```text
|
||||
cnomadcna-api.service
|
||||
```
|
||||
|
||||
### Nginx 配置变更
|
||||
|
||||
```bash
|
||||
nginx -t
|
||||
nginx -s reload
|
||||
```
|
||||
|
||||
### 服务健康检查
|
||||
|
||||
```bash
|
||||
curl -I https://nomadro.cn/zh/meetups
|
||||
curl -I https://api.nomadro.cn/api/health
|
||||
curl -I https://mirotalk.nomadro.cn/join?room=nomadcna-healthcheck
|
||||
curl -I https://lounge.nomadro.cn/
|
||||
curl -I https://ergo.nomadro.cn/
|
||||
```
|
||||
|
||||
## 数据与备份
|
||||
|
||||
建议纳入备份的内容:
|
||||
|
||||
| 路径/服务 | 说明 |
|
||||
| --- | --- |
|
||||
| `.env.local`、`backend/.env` | 生产环境变量和密钥 |
|
||||
| PocketBase 数据目录 | 用户、会员、订单、内容、活动等业务数据 |
|
||||
| MinIO 数据卷 | 上传媒体、远程媒体缓存 |
|
||||
| `/var/lib/ergo` | Ergo IRC 数据库 |
|
||||
| `/var/lib/thelounge` | The Lounge 配置、VAPID key、包配置 |
|
||||
| `/opt/nomadro-services/mirotalk` | MiroTalk 源码部署目录 |
|
||||
| `/www/server/panel/vhost/nginx/*.conf` | Nginx vhost 配置 |
|
||||
| `/etc/systemd/system/*.service` | systemd 单元 |
|
||||
|
||||
## 安全注意事项
|
||||
|
||||
- README 不应包含真实密钥、管理员密码、支付密钥或 MinIO Secret。
|
||||
- `.env.local` 和 `backend/.env` 不应提交到 Git。
|
||||
- The Lounge 当前为 public mode,适合活动公开群聊;如需长期身份和历史,可切换 private mode 并创建用户账号。
|
||||
- Ergo 原生 IRC 公网端口当前不开放,这是有意设计;需要原生 IRC 客户端时再开放 `6697` 并配置 TLS。
|
||||
- 内部服务优先绑定 `127.0.0.1`,统一通过 Nginx HTTPS 暴露。
|
||||
- 修改 Nginx 前必须先 `nginx -t`。
|
||||
- 更新证书后确认 SAN 包含对应域名。
|
||||
|
||||
## 开发约定
|
||||
|
||||
- 新页面优先放入 `app/[locale]`,并补充 `messages/zh.json`、`messages/en.json`。
|
||||
- 需要语言感知链接时使用 `i18n/navigation.ts` 导出的 `Link`。
|
||||
- 调用后端 API 使用 `app/lib/api-client.ts`。
|
||||
- 主站通用配置放 `config/*`,Digital 子站配置放 `config/digital/*`。
|
||||
- 媒体上传和远程媒体代理优先走 MinIO。
|
||||
- 支付相关逻辑优先复用 `app/lib/payment`、`backend/payment.py` 和 `config/*/services.config.ts`。
|
||||
- 线上活动相关逻辑优先复用 `app/lib/meetups.ts`。
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 为什么 `ergo.nomadro.cn` 不直接打开 IRC?
|
||||
|
||||
`ergo.nomadro.cn` 是 IRC 服务名,但原生 IRC 端口没有对公网开放。用户从浏览器进入 `lounge.nomadro.cn`,The Lounge 在服务器本机连接 Ergo。这样能减少公网攻击面,同时满足 Web 群聊需求。
|
||||
|
||||
### 为什么 `/api/digital/*` 没有转发到 FastAPI?
|
||||
|
||||
`next.config.ts` 明确排除了 `digital` 和 `media` 两类 API,它们由 Next.js Route Handlers 直接处理。其他 `/api/*` 才会转发到 FastAPI。
|
||||
|
||||
### 活动视频房如何生成?
|
||||
|
||||
`app/lib/meetups.ts` 会根据活动城市、日期、时间和 ID 生成 MiroTalk room slug。如果活动有自定义 `meetingUrl`,则优先使用自定义链接。
|
||||
|
||||
### 群聊频道如何进入?
|
||||
|
||||
The Lounge public mode 的默认网络已锁定到 Ergo,并默认加入 `#nomadcna` 和 `#online-events`。活动详情页的“进入群聊”按钮指向 `https://lounge.nomadro.cn`。
|
||||
|
||||
## 维护命令速查
|
||||
|
||||
```bash
|
||||
# 构建并重启主站
|
||||
APP_ENV=production NEXT_PUBLIC_APP_ENV=production NODE_ENV=production pnpm build
|
||||
systemctl restart cnomadcna.service
|
||||
|
||||
# 查看服务
|
||||
systemctl status cnomadcna.service --no-pager
|
||||
systemctl status mirotalk-p2p.service --no-pager
|
||||
systemctl status ergo.service --no-pager
|
||||
systemctl status thelounge.service --no-pager
|
||||
|
||||
# 查看日志
|
||||
journalctl -u cnomadcna.service -n 100 --no-pager
|
||||
journalctl -u mirotalk-p2p.service -n 100 --no-pager
|
||||
journalctl -u ergo.service -n 100 --no-pager
|
||||
journalctl -u thelounge.service -n 100 --no-pager
|
||||
|
||||
# Nginx
|
||||
nginx -t
|
||||
nginx -s reload
|
||||
|
||||
# 端口
|
||||
ss -ltnp | rg ':4002|:8000|:8090|:9000|:9300|:9100|:9101|:6667|:6697'
|
||||
|
||||
# Docker
|
||||
docker ps
|
||||
|
||||
# HTTPS
|
||||
certbot certificates
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user