docs: update

This commit is contained in:
ryan
2026-06-26 21:17:43 +08:00
parent 894f8f1ea2
commit b48414e1fe
6 changed files with 19 additions and 347 deletions
-335
View File
@@ -1,335 +0,0 @@
# wavelet 部署指南
本文档详细介绍了 **wavelet** 脚手架系统在不同业务阶段的部署方案,涵盖从**最小化单机部署**到**最大化高可用分布式部署**的全生命周期架构。
---
## 一、 系统组件概览
在部署系统前,请了解各运行组件及其角色:
| 组件名称 | 运行命令/形式 | 职责说明 | 必选/可选 |
| :--- | :--- | :--- | :--- |
| **HTTP API 服务** | `bin/openflare-server api` | 接收并处理前端及第三方的 RESTful API 请求 | **必选** |
| **异步任务工作进程** | `bin/openflare-server worker` | 消费并处理异步队列任务(如邮件发送、清理上传文件等) | **必选** |
| **定时任务调度器** | `bin/openflare-server scheduler` | 定时向 Redis 队列下发 Cron 任务(仅负责触发,不负责执行) | **必选** |
| **前端服务 (Node.js)** | `pnpm start` | 提供 React/Next.js 页面服务(在分离部署时使用) | 分离模式必选 |
| **PostgreSQL** | 关系型主数据库 | 存储用户、系统配置、认证源、任务执行记录等核心数据 | **必选** |
| **Redis** | 缓存与消息队列中间件 | 存储 Session 会话、临时缓存以及 Asynq 异步任务队列数据 | **必选** |
| **ClickHouse** | 分析型数据库 | 存储历史数据同步或进行高性能分析 | 可选 |
| **对象存储 (S3)** | 兼容 S3 的云存储/私有云 | 存放用户上传的静态文件、图片等 | 可选 |
---
## 二、 部署配置准备
系统在启动前会从当前目录加载 `config.yaml` 配置文件。
生产环境部署前,请复制 `config.example.yaml` 为 `config.yaml`,并至少确认以下关键参数的配置:
```yaml
app:
env: "production" # 生产环境标识
addr: ":8000" # API 服务监听端口
session_secret: "prod-random-secret" # 极其重要的加密密钥,首发启动后不可更改
session_domain: ".yourdomain.com" # 跨域共享 Session 时需配置
database:
host: "db.yourdomain.com"
port: 5432
username: "postgres"
password: "YOUR_DB_PASSWORD"
database: "refreshing"
redis:
addrs:
- "redis.yourdomain.com:6379"
password: "YOUR_REDIS_PASSWORD"
```
---
## 三、 方案一:最小部署 — 单机嵌入式极简版 (推荐)
此部署方案将**前端静态网页全部直接打入 Go 后端二进制文件中**,极大地简化了部署运维,是中小型应用、内部系统、SaaS 早期阶段的首选。
### 📊 架构设计
- **服务载体**:单台云服务器 (1核2G 即可)。
- **依赖服务**:在一台机器上启动轻量级 PostgreSQL 与 Redis(可采用 Docker 部署)。
- **进程管理**:在一台机器上直接拉起打包好的 Go 单文件,并分别运行 `api`、`worker`、`scheduler` 进程。
- **前端托管**:Go 服务直接在 8000 端口承载前端的所有页面,不需要额外配置 Node.js 生产服务器。
### 🛠️ 步骤说明
#### 1. 单机依赖服务初始化 (使用 Docker Compose)
在机器上准备以下 `docker-compose.yml` 快速启动 PostgreSQL 和 Redis:
```yaml
version: '3.8'
services:
postgres:
image: postgres:15-alpine
container_name: refreshing-db
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: YOUR_DB_PASSWORD
POSTGRES_DB: refreshing
ports:
- "5432:5432"
volumes:
- ./data/pg:/var/lib/postgresql/data
restart: always
redis:
image: valkey/valkey:8.0-alpine
container_name: refreshing-redis
command: valkey-server --requirepass YOUR_REDIS_PASSWORD
ports:
- "6379:6379"
volumes:
- ./data/redis:/data
restart: always
```
执行命令启动:
```bash
docker compose up -d
```
#### 2. 前后端一键嵌入式打包
在开发或编译机上,运行编译指令:
```bash
make build-embedded
```
该命令会自动完成前端的静态编译导出 (`frontend/out`)、复制到 Go 后端目录,最后使用 `-tags embed_frontend` 生成后端单文件:
- 产物路径:`bin/openflare-server`
#### 3. 进程管理 (使用 Systemd)
将 `bin/openflare-server` 拷贝到生产服务器 `/usr/local/bin/openflare-server`,并为 `api`、`worker` 和 `scheduler` 配置 Systemd 管理服务。
新建 API 进程服务文件 `/etc/systemd/system/openflare-api.service`:
```ini
[Unit]
Description=Refreshing API Service
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/app
ExecStart=/usr/local/bin/openflare-server api
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
```
同理,新建 Worker 服务 `/etc/systemd/system/openflare-worker.service`(将命令改为 `openflare-server worker`),以及 Scheduler 服务 `/etc/systemd/system/openflare-scheduler.service`(将命令改为 `openflare-server scheduler`)。
启动并启用所有服务:
```bash
systemctl daemon-reload
systemctl enable --now refreshing-api refreshing-worker refreshing-scheduler
```
#### 4. 配置 Nginx 证书
配置 Nginx 作为反向代理并启用 HTTPS 证书:
```nginx
server {
listen 80;
server_name yourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name yourdomain.com;
ssl_certificate /path/to/cert.crt;
ssl_certificate_key /path/to/cert.key;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
---
## 四、 方案二:标准部署 — 前后端物理分离架构
此方案中前端与后端彻底解耦。前端采用 SSR/ISR (Next.js Node 服务) 运行,后端采用独立的 API 服务运行。
### 📊 架构设计
- **前端部署**:单独部署到 Node.js 托管环境(如多台前端机器或 Vercel/Cloudflare Pages)。
- **后端部署**:多台后端云服务器,统一指向云数据库 RDS 与云缓存 Redis。
- **通信方式**:前后端通过 Nginx 规则路由或独立域名(如 `app.yourdomain.com` 访问前端,`api.yourdomain.com` 访问后端)进行跨域通信。
### 🛠️ 步骤说明
#### 1. 部署后端 Go 服务
1. 编译后端:
```bash
go build -o bin/openflare-server main.go
```
2. 在后端服务器上,同样使用 Systemd 或 Docker 守护启动 `openflare-server api`、`openflare-server worker` 和 `openflare-server scheduler`。
3. 配置后端 Nginx 将客户端 API 请求(如 `/api/...`)反向代理至后端绑定的端口(如 `:8000`)。
#### 2. 部署前端 Next.js 服务
1. 前端服务器环境确保已安装 Node.js 和 pnpm。
2. 安装依赖并编译生产版本:
```bash
cd frontend
pnpm install
pnpm build
```
3. 使用 PM2 守护前端 Node.js 服务运行。新建 `ecosystem.config.js`:
```javascript
module.exports = {
apps: [
{
name: 'refreshing-frontend',
script: 'node_modules/next/dist/bin/next',
args: 'start -p 3000',
instances: 'max',
exec_mode: 'cluster',
env: {
NODE_ENV: 'production',
WAVELET_BACKEND_URL: 'https://api.yourdomain.com'
}
}
]
};
```
启动前端服务:
```bash
pm2 start ecosystem.config.js
```
#### 3. 跨域与 Cookie 说明
- 若前后端使用**不同子域名**部署(例如 `app.yourdomain.com` 和 `api.yourdomain.com`),必须在 `config.yaml` 中将 `app.session_domain` 显式设置为顶级域名(`.yourdomain.com`),以确保 Session Cookie 可以在子域间顺利透传。
- 在跨域状态下,前端请求必须配置 `withCredentials: true`,API 端的跨域中间件(`corsMiddleware`)会自动将该域添加至允许源中。
---
## 五、 方案三:最大部署 — 企业级高可用分布式架构 (Max)
当系统面临高并发流量、海量后台任务或极高的可用性要求时,需要将所有组件拆分为无状态水平扩容,并引入高可用的云基础设施。
### 📊 架构设计图
```
┌────────────────────────┐
│ 域名 / 负载均衡器 │
│ (SLB / Cloudflare) │
└──────────┬─────────────┘
│
┌──────────────────┴──────────────────┐
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ 前端集群 │ │ 后端 API 集群 │
│ (Next.js Node) │ │ (Go 无状态实例) │
│ [弹性扩容 / 8台+] │ │ [弹性扩容 / 8台+] │
└─────────────────────┘ └──────────┬──────────┘
│
┌────────────────────────────────────────┼────────────────────────────────────────┐
▼ ▼ ▼
┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐
│ 异步 Worker 集群 │ │ 定时 Scheduler │ │ S3 对象存储集群 │
│ (多节点并发处理) │ │ (主备模式,限单节点)│ │(R2/MinIO/AWS S3) │
└─────────┬─────────┘ └─────────┬─────────┘ └───────────────────┘
│ │
└───────────────────┬────────────────────┘
│
┌───────────────────┴────────────────────┐
▼ ▼
┌───────────────────────────────────┐ ┌───────────────────────────────────┐
│ Redis 哨兵/集群 │ │ PG 主从读写分离集群 │
│ (高可用缓存/Asynq 队列) │ │ (RDS Primary-Replica) │
└───────────────────────────────────┘ └───────────────────────────────────┘
```
### ⚙️ 最大部署配置要点
#### 1. 数据库高可用 (主从读写分离)
在 `config.yaml` 中配置 `database` 的主库写与从库读:
```yaml
database:
enabled: true
host: "pg-primary.yourdomain.com" # 主库地址(写)
port: 5432
username: "postgres"
password: "YOUR_DB_PASSWORD"
database: "refreshing"
# 配置读写分离只读副本(GORM 自动轮询读,支持配置多个从库)
replicas:
- host: "pg-replica-1.yourdomain.com"
port: 5432
username: "postgres"
password: "YOUR_DB_PASSWORD"
- host: "pg-replica-2.yourdomain.com"
port: 5432
username: "postgres"
password: "YOUR_DB_PASSWORD"
```
#### 2. Redis 高可用 (哨兵/Sentinel 或集群)
- **Sentinel 哨兵模式**:通过配置 `redis.master_name` 启用,SDK 会自动监视 Master 的主备切换。
- **Cluster 集群模式**:将 `redis.cluster_mode` 设为 `true`,并提供所有集群节点的 `addrs`。
```yaml
redis:
addrs:
- "redis-node-1.yourdomain.com:6379"
- "redis-node-2.yourdomain.com:6379"
- "redis-node-3.yourdomain.com:6379"
cluster_mode: true
```
#### 3. 对象存储与缓存分离 (S3 + Local Cache)
高可用集群下,本地文件系统不再可共享。文件存储必须启用 S3 兼容服务,并在多节点间开启本地高速磁盘缓存加速读取:
```yaml
s3:
enabled: true
endpoint: "https://your-r2-or-s3-id.r2.cloudflarestorage.com"
region: "auto"
bucket: "refreshing-assets"
access_key_id: "YOUR_S3_KEY"
secret_access_key: "YOUR_S3_SECRET"
local_cache:
enabled: true # 开启本地磁盘缓存
cache_dir: "/data/s3_cache" # 本地高性能 SSD 挂载点
```
#### 4. 后端进程横向拆分部署
- **API 集群**:启动数十个甚至上百个 `wavelet api` 无状态容器。它们可以通过负载均衡器直接挂载,支持随时弹性缩容扩容。
- **Worker 集群**:启动多个 `wavelet worker` 容器。因为 `Asynq` 基于 Redis 分布式处理,多个 Worker 进程可以安全地同时运行并竞抢同一队列的异步任务,自动保障任务的并发吞吐能力。
- **Scheduler 独占**:**【注意】** 为避免重复触发定时 Cron 任务,`wavelet scheduler` 定时调度器进程**同一时间应仅运行单个活跃实例**(主备高可用可以通过容器平台的单实例保障或 K8s Job 机制来限制实例数为 1)。
#### 5. ClickHouse 高并发同步
在大数据量、高频支付结算场景下,开启 ClickHouse 以接收系统的历史数据同步,通过定时器把 PostgreSQL 的压力转移到 ClickHouse 列式存储中。
```yaml
clickhouse:
enabled: true
hosts:
- "ch-node-1.yourdomain.com:9000"
- "ch-node-2.yourdomain.com:9000"
```
#### 6. OpenTelemetry 分布式链路追踪
最大部署架构必须引入链路追踪(Jaeger 或 OTel Collector)以便排查节点间请求延迟或网络问题。
在生产环境,通过配置 OTel 将 Span 发送至公共日志分析平台。
```yaml
otel:
sampling_rate: 0.05 # 开启 5% 的流量追踪采样率以减少开销
```
---
## 六、 部署方案对比与选择建议
| 指标维度 | 方案一:最小单机嵌入版 | 方案二:标准前后端分离版 | 方案三:最大高可用分布式版 |
| :--- | :--- | :--- | :--- |
| **支持流量/并发** | 1,000 ~ 5,000 QPS (视机器性能) | 5,000 ~ 20,000 QPS | 20,000 ~ 100,000+ QPS (无限扩展) |
| **服务器数量** | 1 台 | 3 ~ 5 台 | 10 台以上集群 |
| **运维复杂度** | 极简 (只需部署一个程序) | 中等 (需维护 Node 和 Go 两套环境) | 较高 (K8s/多组件集群维护) |
| **适合场景** | 个人项目、内部系统、SaaS 早期起步 | 正常线上运营项目、有中等规模团队 | 大型企业级应用、高并发核心交易系统 |
+8 -2
View File
@@ -57,7 +57,7 @@ curl -fsSL https://raw.githubusercontent.com/Rain-kl/OpenFlare/main/scripts/inst
--docker
```
安装脚本在本地安装模式下会下载最新 Agent,默认写入 `/opt/openflare-agent`,生成 `agent.json`,并在 Linux + systemd 环境创建 `openflare-agent.service`。
安装脚本在本地安装模式下会下载最新 Agent,默认写入 `/opt/openflare-agent`,生成 `agent.json`,自动检测并创建低权限系统账号 `openflare`(将整个安装目录赋权给该用户),并在 Linux + systemd 环境创建 `openflare-agent.service` 服务。该服务将以 `openflare` 普通用户运行,并通过 Linux Capabilities(`CAP_NET_BIND_SERVICE`)保障其监听特权端口(如 80、443)的能力。
支持参数:
@@ -131,6 +131,12 @@ docker run -d --name openflare-agent --restart unless-stopped \
ghcr.io/rain-kl/openflare-agent:latest
```
> [!NOTE]
> **非 Root 安全加固运行**
> Agent 容器内部已完成安全加固,在启动后会统一以低权限非 root 用户 `openflare` 运行。
> 容器已内置了 `cap_net_bind_service` 内核能力,使得低权限进程依然能够正常监听宿主机的 `80` 和 `443` 特权端口。
> 同时,OpenResty 运行时所需的各种临时路径(包括 PID 路径、各类临时缓存目录如 `client_body_temp_path`、`proxy_temp_path` 等)都由 Agent 控制器动态渲染并自动重定向至挂载的 `/data` 数据目录,彻底避免在非 root 权限运行时写入默认系统路径而导致的权限拒绝错误(Permission Denied)。
## 启动与验证
systemd 环境:
@@ -214,5 +220,5 @@ curl -fsSL https://raw.githubusercontent.com/Rain-kl/OpenFlare/main/scripts/unin
| --- | --- |
| `agent_token 和 discovery_token 不能同时为空` | 检查 `agent.json` 至少配置了一个 Token |
| 节点一直离线 | 在 Agent 节点执行 `curl -I http://your-server:3000`,确认 Server 地址可达 |
| OpenResty 没有启动 | 查看 `journalctl -u openflare-agent`,确认 `openresty_path` 可执行且 80/443 端口未被占用 |
| OpenResty 没有启动 | 查看 `journalctl -u openflare-agent`,确认 `openresty_path` 可执行,80/443 端口未被占用,且运行用户(如 `openflare`)对数据目录具有读写权限 |
| 发布后重复失败 | Agent 会阻断同一 `version + checksum` 的重复应用;需要修正配置后重新发布,或激活旧版本回滚 |
+5 -2
View File
@@ -85,7 +85,7 @@ cp .env.example .env
# 编辑 .env,至少修改 APP_SESSION_SECRET 与数据库密码
docker compose up -d
docker compose ps
docker compose logs -f wavelet
docker compose logs -f openflare
```
首次访问 `http://localhost:3000`,默认账号为 `root` / `123456`。登录后请立即修改默认密码。
@@ -117,6 +117,9 @@ go run main.go all
Docker 部署是 Agent 推荐的部署方式。Docker 部署时直接运行 Agent 镜像,该镜像基于 OpenResty 镜像制作,内置 Agent 控制器与 OpenResty 二进制。未显式配置 `node_ip` 时,Agent 会优先通过第三方 API 获取真实出口 IP,避免把 Docker 网桥地址登记为节点 IP。
> [!NOTE]
> Agent 镜像已完成非 Root 安全加固,统一以普通用户 `openflare` 权限运行,通过内核 capabilities 授权(`cap_net_bind_service`)监听 80/443 特权端口,并自动重定向临时文件和 PID 路径至挂载数据卷以防止写入冲突。
挂载配置文件:
```bash
@@ -143,7 +146,7 @@ docker run -d --name openflare-agent --restart unless-stopped \
## Agent 接入(脚本安装)
除了 Docker 部署外,也支持通过安装脚本将 Agent 部署在本地宿主机上。
除了 Docker 部署外,也支持通过安装脚本将 Agent 部署在本地宿主机上。安装脚本会自动在本地 Linux 系统中注册低权限的 `openflare` 服务账号,并将 systemd 服务配置为以该用户身份运行,利用 Linux Capabilities 安全地监听 80/443 特权端口。
使用 `discovery_token` 自动注册:
+1 -1
View File
@@ -79,7 +79,7 @@ docker run -d \
-e DB_ENABLED=false \
-e SQLITE_PATH='/data/openflare.db' \
-e LOG_LEVEL='info' \
ghcr.io/rain-kl/openflare:latest
ghcr.io/rain-kl/openflare-server:latest
```
启动参数说明:
+2 -3
View File
@@ -110,8 +110,7 @@ flowchart TD
D -- 是 (匹配成功) --> E[放行请求 - ALLOW]
D -- 否 --> F{匹配到国家/地区地域白名单?}
F -- 是 (匹配成功) --> E
F -- 否且已配置任意白名单 --> H
F -- 否且未配置白名单 --> G{匹配到 IP 黑名单 / 黑名单 IP 组?}
F -- 否 --> G{匹配到 IP 黑名单 / 黑名单 IP 组?}
G -- 是 (匹配成功) --> H[阻断请求 - BLOCK]
G -- 否 --> I{匹配到国家/地区地域黑名单?}
I -- 是 (匹配成功) --> H
@@ -124,7 +123,7 @@ flowchart TD
### 2. 判决步骤细则
1. **白名单前置**:
为了防止误杀以及保障核心回源流量(如搜索引擎蜘蛛、CDN 回源 IP、办公区出口)的顺畅,WAF **优先匹配 IP 白名单与地域白名单**。一旦白名单匹配成功,直接绕过后续的所有黑名单检测和 CC 挑战,立刻放行。只要当前生效规则组配置了任意白名单,请求未命中全部白名单时会被拦截,白名单在这种情况下表现为准入名单。
为了防止误杀以及保障核心回源流量(如搜索引擎蜘蛛、CDN 回源 IP、办公区出口)的顺畅,WAF **优先匹配 IP 白名单与地域白名单**。一旦白名单匹配成功,直接绕过后续的所有黑名单检测和 CC 挑战,立刻放行。如果请求未命中白名单,则继续向下进行黑名单检测及其他后续判定。
2. **黑名单强力阻断**:
如果在白名单判定中未被捕获,请求将进入黑名单漏斗。一旦请求源 IP 命中 IP 黑名单、命中引用的黑名单 IP 组、或是处于被禁止的国家/地区范围内,Lua 引擎立即将 `ngx.ctx.openflare_waf_blocked` 标记设为 `true`。
3. **输出响应**:
+3 -4
View File
@@ -144,8 +144,7 @@ IP 组是进行大批量 IP 过滤的基石。OpenFlare 提供了极富弹性的
│ (否)
▼
2. 匹配国家 / 省份地域白名单? ────────(是)─────► [ 放行 (ALLOW) ]
│ (否,且已配置任意白名单) ─► [ 拦截 (BLOCK) ]
│ (否,且未配置白名单)
│ (否)
▼
3. 匹配 IP 黑名单 / 黑名单 IP 组? ──────(是)─────► [ 拦截 (BLOCK) ] ──► 返回自定义状态码与HTML拦截页
│ (否)
@@ -167,8 +166,8 @@ IP 组是进行大批量 IP 过滤的基石。OpenFlare 提供了极富弹性的
## 最佳实践与调优建议
* **白名单准入语义**:一旦某个生效规则组配置了 IP 白名单、白名单 IP 组或地域白名单,请求必须命中其中至少一条白名单规则才会继续放行;未命中白名单的请求会被拦截。白名单命中后仍会优先绕过后续黑名单与 PoW 检查。
* **白名单前置与保护**:在部署高强度黑名单或地域屏蔽前,建议首先创建一个「受信任 IP 组」,放入你团队的办公室出口 IP、本地开发 IP 以及可能访问你的第三方回调源站 IP(如微信、支付宝支付回调地址),并在规则组的**白名单**中优先引入。这可以有效防止误杀,但也会让未在白名单内的来源无法访问。
* **白名单放行语义**:一旦某个生效规则组配置了 IP 白名单、白名单 IP 组或地域白名单,且请求命中了其中至少一条白名单规则,该请求将被直接放行,并优先绕过后续的黑名单与 PoW 检查;未命中的请求则会继续进行黑名单等后续防护校验。
* **白名单前置与保护**:在部署高强度黑名单或地域屏蔽前,建议首先创建一个「受信任 IP 组」,放入你团队的办公室出口 IP、本地开发 IP 以及可能访问你的第三方回调源站 IP(如微信、支付宝支付回调地址),并在规则组的**白名单**中优先引入。这可以有效防止误杀,确保信任的 IP 即使命中黑名单或 CC 限制也能无阻碍访问。
* **合理微调 PoW 难度**:人机 CC 挑战的哈希碰撞计算(`challenge_difficulty`)是一把双刃剑。
* 难度值 `3`:几乎瞬间完成计算,防 CC 强度低。
* 难度值 `4`:普通手机/低端浏览器在 100~300ms 内完成计算,防护性能良好。