架构
一个二进制跑四件事,共用一个 SQLite 文件。这里是短版;README 里有同样内容的时序图与 ER 图。
一台服务器里有什么
| 部分 | 监听 | 负责 |
|---|---|---|
| 面板 | :2053 /app/(代理面板 :2054 /dl/) | 会话、API、代理作用域。两个面板是同一套前端,会话决定能看到什么。 |
| 订阅服务 | :2056 /sub/ | 三种格式、落地页、客户端下载页、临时共享、"订阅不可用"说明页。 |
| 数据面 | 各线路端口 | 内嵌 sing-box:每条线路一个入站、每个上游一个出站,流量与连接跟踪,按用户限制。 |
| 后台 | — | 每 10 秒统计,每分钟判配额,上游巡检(各机只测自己用到的),每小时清理日志,证书续期,备份,每 5 秒主副同步。 |
四者共用 m-ui.db(SQLite,WAL 模式)。面板写,数据面和订阅服务读,所以面板里点一下保存,各处立刻看到同一份数据。没有消息队列、没有缓存服务、没有第二个数据库要跑。
保存一次改动,发生了什么
- 字段校验与端口检查 —— 对照其它线路、面板端口,以及本机上任何已经在监听的程序。
- 开写事务(
BEGIN IMMEDIATE)写入改动。 - 从库里渲染出整份配置,交给 sing-box 自己的解析器。解析不通过就回滚事务,请求带着原因失败。线上一动没动。
- 通过后按改动分级应用:改用户 → 换入站用户表(别人不断线);改上游 → 热换出站;改线路 → 重启数据面,新配置起不来(比如端口被别的进程抢走)就恢复上一份能用的。
一次订阅请求
GET /sub/<地址>:地址按用户名、随机订阅令牌、临时共享令牌(同一个用户,另一套凭据)依次匹配。停用的用户、到期的代理、对不上的地址都是 404 —— 浏览器看到一页说明,客户端拿到纯 404。有效用户:浏览器得到落地页;客户端按 ?format= 得到通用链接、Clash YAML 或 sing-box 配置。节点 = 用户已分配的线路 × 线路部署的服务器,再拼上外部节点与外部订阅。
主副机
主机每 5 秒把线路、上游、用户、凭据、代理和同步设置做成快照,哈希成修订号,并发推给所有副机,再拉回每台的报告(游标之后的流量、在线 IP、状态)。副机不判配额;主机停用的用户在下一份快照里自然消失。细节见多服务器。
数据模型
| 表 | 存什么 | 关系 |
|---|---|---|
| lines | 协议、端口、TLS、传输、参数、部署到哪些服务器 | → upstream(出口);↔ users(user_lines);↔ nodes |
| users | 各协议凭据、配额与用量、到期、设备与限速、订阅地址、共享令牌 | ↔ lines;→ reseller(可选);← plans(建号时) |
| upstreams | 出站类型与参数 | ← lines |
| nodes | 名称、域名 / 地址、API 地址与令牌、倍率 | ↔ lines |
| resellers | 额度(流量、带宽、设备)、到期、自己的落地页文案、被授权的线路 | → users、plans |
| stats、agent_counters、traffic_cursors | 时序与跨机计量 | |
| settings、admins、sub_logs、audit | 其余一切 |
后台节奏
| 周期 | 做什么 |
|---|---|
| 5 秒 | 主机 → 副机推快照、拉报告 |
| 10 秒 | 从数据面取流量与连接,按用户 / 线路 / 上游写统计 |
| 10 秒 | 判定限速规则(时段 / 突发),命中的状态随下一次快照推给副机 |
| 1 分钟 | 配额、到期、周期重置;数据面看门狗 |
| 10 分钟 | WAL 检查点,运行中的库随时可安全复制 |
| 6 小时 | 向 GitHub Releases 查一次新版本(只查) |
| 1 小时 | 按保留天数清理时序与日志;48 小时前的分钟样本并成小时桶 |
| 12 小时 | 证书续期检查(续期后 sing-box 自动换证书,不重启) |
| 每天 | 日报 |
代码结构
| 目录 | 职责 |
|---|---|
web/ | 面板与 API、代理面板、外部 API、内嵌前端(零构建 ES 模块) |
sub/ | 订阅格式、落地页、客户端下载、共享 |
render/ core/ | 线路 → sing-box 配置与干跑;内嵌数据面与跟踪 |
hub/ | 快照推送、流量回收、在线聚合 |
runner/ | 进程编排、三级重载与回滚、证书、备份 |
jobs/ monitor/ | 统计、配额判定、巡检、告警 |
database/ | 模型、SQLite 打开与迁移 |
selfupdate/ deploy/ | 版本检查与就地更新、安装脚本 |
图:README → 架构。深入:为什么内嵌内核 · 热更新是怎么做的 · 同步是怎么做的。