个人 VPN 安卓端、软路由端与双服务器架构及 Codex 重建指南(脱敏版)
[!summary] 一句话结论 这不是“整台 VPS 的全栈方案”,只是一套个人 VPN:安卓和软路由用 Mihomo 做一级分流与入口选择;广州服务器承担主入口、兼容入口、订阅发布和二级分流;新加坡服务器承担 Remnawave 控制面、直连入口以及默认境外出口;广州与新加坡之间用 WireGuard 连接。
本文用于公开分享和交给 Codex 重建。文中已删除真实域名、IP 地址、订阅路径、账号、UUID、Reality 密钥、SNI、短 ID、SSH 别名、数据库凭据和自定义端口。所有尖括号内容都是部署者自己的占位符。
1. 范围与当前状态
本文只包含四个实际角色:
- 安卓端:FlClash + Mihomo。
- 软路由端:GL.iNet GL-MT3600BE + OpenClash + Mihomo。
- 广州服务器:公网入口、主 VPN 节点、兼容节点、订阅与规则发布、服务端二级分流。
- 新加坡服务器:Remnawave 控制面、直连 VPN 节点、WireGuard 境外出口、流量统计源。
截至 2026-09-12 的只读核对结果:
| 项目 | 当前已核对状态 |
|---|---|
| 托管配置 | 活动版本为 v2026.09.01.2,采用不可变版本发布 |
| 软路由 | OpenClash 运行中;已加载同一版本;当前手动选择 广州→新加坡—Reality—v2;真实客户端路径返回 HTTP 204 |
| 广州服务器 | Nginx、Remnanode/Xray、兼容入口、二级分流及规则更新任务运行中 |
| 新加坡服务器 | Remnawave、Remnanode/Xray、PostgreSQL、Valkey、Caddy 和流量导出任务运行中 |
| 主跨境链路 | wg0 有新鲜握手,是当前生产基线 |
| 实验链路 | wg1 没有新鲜握手,不得设为默认或自动切换目标 |
| 服务端 Xray | 两端当前均为 26.6.27;重建时应固定已验证版本或镜像摘要 |
| 安卓真机 | 本次未通过 ADB 读取手机运行态;本文记录的是服务器实际下发配置,手机最终选择仍需真机确认 |
“容器在运行”“端口在监听”只能证明组件存活,不能证明 VPN 可用。最终判断必须走真实安卓或家庭终端,覆盖 DNS、TLS、策略命中、入口选择、出口地区、持续传输和应用访问。
2. 总体架构
flowchart LR
subgraph C[客户端]
A[安卓端\nFlClash / Mihomo\nTUN + Fake-IP + Rule]
R[软路由端\nGL-MT3600BE\nOpenClash / Mihomo\n透明代理]
end
subgraph GZ[广州服务器:主入口与二级分流]
GN[Nginx\nTLS / SNI 分流\n订阅与规则发布]
GR[Remnanode + Xray\nReality 主入口]
GX[3x-ui + Xray\nWS/TLS 兼容与应急入口]
GP[二级路由\ngz-direct / sg-default / blocked]
PUB[不可变配置发布器\n校验 / 原子切换 / last-good]
end
subgraph SG[新加坡服务器:控制面与境外出口]
SC[Caddy\n控制面 HTTPS]
RW[Remnawave Backend]
DB[(PostgreSQL)]
KV[(Valkey)]
SN[Remnanode + Xray\n新加坡直连入口 / 出口]
ST[流量采集与最小快照]
end
A -->|广州 Reality / 兼容节点| GN
R -->|当前选择广州 Reality| GN
GN --> GR --> GP
GN --> GX --> GP
GP -->|国内目标| GD[广州公网直出]
GP -->|私网或禁用协议| BL[阻断]
GP -->|境外默认| WG[WireGuard 生产隧道]
WG --> SN --> NET[互联网]
A -.可手动选择新加坡直连.-> SN
R -.备用入口.-> SN
SC --> RW
RW --> DB
RW --> KV
RW -.节点管理与配置.-> GR
RW -.节点管理与配置.-> SN
DB --> ST -->|经私网发送脱敏统计快照| PUB
PUB -->|私密订阅与公开规则文件| A
PUB -->|同源配置,经轻量渲染| R
这张图里有两条不同的链路:
- 数据面:终端的真实网络流量,经客户端选择的入口和服务端出口转发。
- 控制面:Remnawave 管理节点,统计任务生成快照,广州发布器生成客户端配置。控制面失败不应立即切断已有数据面连接。
3. 安卓端设计
3.1 技术栈与职责
安卓端使用 FlClash,底层为 Mihomo:
- TUN 模式接管应用流量;
rule模式进行一级分流;- Fake-IP DNS,并让 DNS 查询遵循分流规则;
store-selected: true,保留用户手动选择,不做无证据的自动漂移;- Android 系统 Private DNS 关闭,避免与 TUN DNS 形成双重控制;
- 不依赖 Android 系统 HTTP 代理;
- 私网目标直连,广告规则拒绝,国内业务优先直连,AI 与境外业务进入 VPN 组;
- 最终未命中规则进入
→ Remnawave。
3.2 节点角色
服务器当前下发的安卓配置包含五种角色:
| 显示角色 | 协议 | 用途 |
|---|---|---|
| 新加坡直连 Reality | VLESS + TCP + REALITY + Vision | 备用直连入口;当前标记为降级备用 |
| 广州→新加坡 Reality v2 | VLESS + TCP + REALITY + Vision | 当前生产主路径 |
| 广州→新加坡 Reality v3 | VLESS + TCP + REALITY + Vision | 独立 WireGuard 候选;当前无新鲜握手,只能实验 |
| 广州→新加坡 VLESS-WS | VLESS + WebSocket + TLS | 兼容入口 |
| 广州→新加坡 VMess-WS | VMess + WebSocket | 应急入口,不作为日常首选 |
其中 → Remnawave 是唯一真实选路组。配置版本、更新时间、总体流量和分类流量属于只读信息面板,不得被任何路由规则引用,也不能成为真实出口。
3.3 一级分流语义
一级分流发生在手机本地,目的是减少不必要的代理流量:
私网目标 → DIRECT
明确拒绝的类别 → REJECT
国内业务规则集与国内 IP → DIRECT
AI、境外服务和强制代理类别 → → Remnawave
其余未命中流量 → → Remnawave
规则顺序是业务语义,不能把“国内直连”放到“强制代理”之前。否则某些使用特殊域名或国内 CDN 的境外服务会被误判为直连。
3.4 为什么不用自研安卓客户端
FlClash + Mihomo 已经覆盖 TUN、规则、DNS、节点选择、订阅更新和连接诊断。当前真正复杂的是跨端一致的配置生成、服务端二级防漏和可回滚发布,不是 UI。本方案因此优先维护配置与运维工具,不承担自研 VPN 内核和 Android 生命周期适配的成本。
4. 软路由端设计
4.1 设备与运行方式
软路由使用 GL.iNet GL-MT3600BE,约 512 MB 内存,系统为 OpenWrt,代理栈为 OpenClash + Mihomo。它作为家庭二级路由和透明代理网关:
- 家庭设备无需逐台安装客户端;
- 国内与私网流量由家庭宽带直接访问;
- 需要代理的流量才进入 VPN 节点;
- OpenClash 的管理流量和路由器自身管理端口必须绕过透明代理,避免把自己锁在代理链路里。
当前软路由加载 v2026.09.01.2,配置为 rule + fake-ip,共有 37 条规则、8 个 MRS provider;生产选择为 广州→新加坡—Reality—v2。
4.2 一个策略源,两个运行产物
手机完整配置不能原样塞进 512 MB 路由器。完整 GeoSite 在双核心校验时可能耗尽物理内存和 ZRAM,因此采用:
同一份客户端策略源
├── 安卓产物:保留完整 GeoSite 能力
└── 路由器产物:把高内存 GeoSite 机械转换为 MRS provider
路由器渲染器只做确定性的结构变换:
- 私网、广告和国内域名集合换成 MRS;
- 境外最终规则由同目标的
MATCH承接; - DNS policy 同步改成路由器可加载的 rule-set 表达;
- 保留节点、强制代理规则、国内业务规则、顺序和策略组名称;
- 当前路由器产物只保留三条 Reality 节点,不下发两个 WS 兼容节点。
这样能避免手机和软路由各维护一套容易漂移的业务规则,又不会让低内存路由器加载过重数据。
4.3 同步与回滚
当前路由器同步任务每 12 小时检查一次托管版本,规则 provider 自己按更短周期更新。同步过程必须满足:
- 先比较版本;版本未变则不启动第二个 Mihomo。
- 版本变化才下载完整产物。
- HTTP 版本标记与正文版本一致。
- 渲染为路由器专用 MRS 配置。
- 用本机 Mihomo 做冷加载检查,并在检查前验证可用内存与交换空间。
- 通过后原子替换活动配置并重启 OpenClash。
- 启动失败时恢复
last-good,同时恢复原来的活动配置路径。
策略组是手动 select,并持久化当前选择。不要把延迟测试直接等同于自动切换,更不能把尚无新鲜 WireGuard 握手的候选设为自动故障转移目标。
5. 广州服务器设计
广州服务器是主入口,不是所有流量的固定出口。它承担五项 VPN 职责。
5.1 公网入口与协议兼容
- Nginx 负责标准 HTTPS 入口、SNI/stream 分发、订阅与规则文件交付;
- Remnanode 内的 Xray 承担正式 Reality 主入口;
- 3x-ui 管理的 Xray 保留 VLESS-WS/TLS 和 VMess-WS 兼容入口;
- 主入口与兼容入口必须使用同一套二级分流语义,不能只修其中一套;
- 入口只暴露必要端口,Xray 内部监听和管理接口绑定回环或容器网络。
5.2 服务端二级分流
即使客户端已经做过一级规则,广州仍做第二次判定,防止旧客户端、错误规则或 CDN 解析导致出口泄漏:
| 出口标签 | 作用 |
|---|---|
gz-direct |
已知国内服务、国内 IP 和指定更新流量从广州直出 |
sg-default |
AI、境外服务和未命中流量经生产 WireGuard 到新加坡 |
blocked |
私网目标和明确禁用的协议直接阻断 |
关键顺序是:精确健康探针、私网阻断、禁用协议、强制新加坡类别、明确广州直出类别、国内域名、国内 IP。domainStrategy 使用 IPIfNonMatch:先按域名判断,无法匹配时再解析 IP 兜底。
同一业务策略只维护一份 JSON,由渲染器分别生成 Remnawave 和 3x-ui 所需的 Xray 路由。两份运行产物允许存在 API 管理规则和宿主结构差异,但业务域名集合、出口和优先级必须由测试保证一致。
5.3 WireGuard 与主机策略路由
wg0是广州到新加坡的生产链路;当前有新鲜握手;wg1是候选链路;当前没有新鲜握手;sg-default绑定生产 WireGuard 源地址;- 主机策略路由把该源地址送入专用路由表;
- 国内 IP 还有主机层兜底,可在必要时从广州公网正确 SNAT;
- WireGuard 可用必须同时看握手、隧道内连通、DNS/TLS 和持续传输,不能只看接口存在。
5.4 订阅、规则和 last-good 发布
广州维护客户端配置与规则的发布面:
- 每个基础配置版本不可变;
- 动态流量信息从不可变基础配置渲染成新的 delivery;
- 发布前做 schema、敏感信息、Mihomo 冷加载和关键策略检查;
- 验证通过后用软链接原子切换;
- 任何下载、渲染或验证失败,都继续服务上一份 last-good;
- GeoSite、GeoIP 和 MRS 更新先校验哈希与格式,再让 Mihomo/Xray 真实加载;
- 规则、国内 IP 集与 DNS 映射由 systemd timer 定时更新。
6. 新加坡服务器设计
新加坡服务器同时有控制面角色和数据面角色,但两者应保持逻辑隔离。
6.1 控制面
当前控制面组件:
| 组件 | 作用 |
|---|---|
| Remnawave Backend | 用户、节点、订阅元数据、用量和节点配置管理 |
| PostgreSQL | Remnawave 权威数据 |
| Valkey | 缓存与运行状态 |
| Caddy | 控制面 HTTPS 入口与证书 |
数据库和缓存不暴露公网,只允许同一 Compose 网络内访问。控制面故障时应优先保住已有节点数据面,而不是重建全部容器。
6.2 数据面
Remnanode/Xray 提供两种能力:
- 安卓或软路由可手动选择的新加坡直连 Reality 入口。
- 广州
sg-default经 WireGuard 抵达后的统一境外出口。
直连新加坡路径能少一跳,但不一定更快。移动网络、家庭宽带和云厂商互联路径不同,地理距离不能代替真实 URLTest、失败率和持续传输结果。
6.3 流量统计闭环
Remnawave 数据库保存节点和用户用量历史。新加坡的定时任务:
- 读取小时级聚合数据;
- 写入本机只读口径的单调账本;
- 生成不含用户凭据、节点密钥和订阅路径的最小 JSON 快照;
- 经 WireGuard 管理链路发送到广州;
- 广州校验快照后刷新信息面板 delivery。
手机主动同步或到达自动同步周期后才会看到新数值。统计更新失败不应中断现有订阅或 VPN 数据面。
7. 四条实际流量路径
| 场景 | 路径 |
|---|---|
| 家庭国内访问 | 家庭设备 → 软路由一级规则 → 家庭宽带直出 |
| 手机/家庭境外主路径 | 安卓或软路由 → 广州 Reality → 服务端二级分流 → WireGuard wg0 → 新加坡 Xray → 互联网 |
| 国内目标被客户端送入节点 | 客户端 → 广州入口 → gz-direct → 广州公网直出 |
| 新加坡直连备用 | 安卓或软路由 → 新加坡 Reality → 新加坡公网直出 |
WS 兼容路径只替换“客户端到广州入口”这一段。进入广州后仍必须走相同的 gz-direct / sg-default / blocked 二级语义。
8. 技术选型总结
| 能力 | 选型 | 选择理由 | 不选或暂不做 |
|---|---|---|---|
| 安卓客户端 | FlClash + Mihomo | TUN、规则、DNS、订阅和诊断完整,维护成本低 | 暂不自研客户端 |
| 家庭网关 | OpenClash + Mihomo | 成熟透明代理,能复用客户端策略语义 | 不让每个家庭设备单独配置 |
| 路由器规则格式 | MRS provider | 低内存、按需下载、适合 512 MB 设备 | 不直接加载完整 GeoSite |
| 主协议 | VLESS + TCP + REALITY + Vision | 入口性能和可用性较好,适合作为主路径 | WS 只保留兼容与应急 |
| 节点控制面 | Remnawave | 统一节点、用户、订阅与用量 | 不把业务规则散落在面板手改 |
| 数据面 | Remnanode + Xray | 与 Remnawave 配套,路由与多出口能力完整 | 不用单一 Freedom 出口覆盖所有目标 |
| 跨地域隧道 | WireGuard | 配置小、性能稳定、适合绑定 Xray 出口 | 不把候选链路无验证自动上线 |
| 广州入口 | Nginx | stream/SNI、HTTPS 交付和兼容入口控制细 | 不让管理面直接暴露内部监听 |
| 新加坡控制入口 | Caddy | 少量 HTTPS 服务配置简洁、证书管理方便 | 不让它替代 Xray 数据面 |
| 调度 | systemd service/timer | 超时、依赖、日志、失败状态和重试清晰 | 不把关键任务散落为无状态 cron |
| 发布 | 不可变 release + 原子软链接 + last-good | 配置失败不影响现网,可审计、可回滚 | 不原地覆盖活动配置 |
9. 配置事实源与推荐仓库结构
最重要的原则是:节点密钥与业务策略分离;客户端一级策略与服务端二级策略分别只有一个事实源。
vpn-ops-kit/
├── config/
│ ├── client/
│ │ ├── policy.yaml # 一级分流事实源
│ │ ├── mobile.yaml.tmpl # 安卓模板,无秘密
│ │ └── router-transform.yaml # 路由器机械转换定义
│ └── server/
│ ├── split-policy.json # 二级分流事实源
│ ├── remnawave-routing.json # 生成产物
│ └── compatibility-routing.json # 生成产物
├── edge/
│ ├── nginx/
│ └── caddy/
├── wireguard/
│ └── README.md # 只写变量与步骤,不放密钥
├── scripts/
│ ├── render-mobile
│ ├── render-router
│ ├── render-server-routing
│ ├── publish
│ ├── rollback
│ └── collect-traffic
├── systemd/
├── tests/
│ ├── config-schema
│ ├── routing-parity
│ ├── secret-scan
│ ├── rollback
│ └── end-to-end
├── docs/
│ ├── architecture.md
│ └── operations.md
└── .env.example
Git 只保存模板、业务策略、渲染器、服务单元和测试。真实订阅、节点 UUID、Reality 密钥、WireGuard 私钥、面板密码、数据库密码和完整运行配置只能放在密码管理器、目标机 root-only 文件或 systemd credentials 中。
10. 用 Codex 重建的顺序
阶段 0:只读盘点与端口规划
让 Codex 先只读检查两台服务器和软路由:操作系统、CPU/内存、Docker、systemd、防火墙、现有监听、DNS、时间同步和冲突端口。第一轮不安装、不删除、不重启。输出角色表、端口表、依赖、风险和回滚点。
阶段 1:建立仓库、模板和秘密边界
创建上述仓库结构、.env.example、占位配置和 secret scan。真实秘密由部署者在目标机本地注入,禁止粘贴进 Codex 对话或提交 Git。
阶段 2:先建新加坡控制面与数据面
先部署 PostgreSQL、Valkey、Remnawave 和 Remnanode,确认控制面健康、数据库可备份、Xray 固定版本正常。Caddy 只暴露必要的控制面 HTTPS。
阶段 3:建立生产 WireGuard
建立广州到新加坡的 wg0,验证双向隧道内连通、MTU、DNS/TLS、实际 HTTP 和重复大文件。候选 wg1 单独部署、单独验收,未通过门禁前不进入默认路由。
阶段 4:部署广州主入口与二级分流
部署 Nginx、广州 Remnanode/Xray 和兼容 Xray。先生成两套二级路由并做一致性测试,再分别加载。验证国内目标走 gz-direct、境外目标走 sg-default、私网与禁用协议走 blocked。
阶段 5:部署配置与规则发布器
生成安卓基础配置,注入目标机本地秘密,依次通过 schema、secret scan、Mihomo 冷加载和规则断言,再发布不可变版本。规则更新任务也必须采用下载到临时目录、校验、冷加载、原子切换和 last-good 回滚。
阶段 6:安卓真机验收
导入私密订阅,确认 TUN 已连接、VPN 网络被系统验证、Private DNS 关闭、没有系统 HTTP 代理、不可绕过。分别测试国内直连、广州主路径、新加坡备用入口、DNS、TLS、应用登录和持续传输。
阶段 7:软路由部署与家庭验收
安装 OpenClash/Mihomo 和 MRS 渲染器。先做内存预算,再冷加载候选;通过后原子切换。用真实 Wi-Fi 终端检查 DHCP、网关、DNS、国内直连、境外代理、当前选择持久化、重启恢复和 last-good 回滚。
阶段 8:再开启自动任务
只有手工全链路通过后,才启用规则更新、配置同步、统计导出和 delivery 刷新定时器。任何自动任务连续失败都只能保留旧版本,不能为了“自动修复”切到未验收节点。
11. 可直接交给 Codex 的重建提示词
我要在自己控制的设备上重建一套个人 VPN。范围严格限定为:
1. 安卓端 FlClash/Mihomo;
2. GL.iNet GL-MT3600BE 软路由上的 OpenClash/Mihomo;
3. 广州服务器的 Nginx、Remnanode/Xray、兼容 Xray、订阅发布和二级分流;
4. 新加坡服务器的 Caddy、Remnawave、PostgreSQL、Valkey、Remnanode/Xray 和境外出口。
目标架构:
- 安卓与软路由用同一份一级分流语义,但分别渲染为移动端完整配置和路由器 MRS 轻量配置;
- 策略组采用手动 select 并持久化选择,不做未经验证的自动切换;
- 广州是主入口,服务端有 gz-direct、sg-default、blocked 三类出口;
- 境外默认经 WireGuard wg0 到新加坡;wg1 只作为候选,未通过全链路门禁前不得启用;
- 新加坡同时承载 Remnawave 控制面和 Xray 数据面,但数据库、缓存与管理端口不得公开;
- 基础配置、动态统计 delivery 和规则文件都使用不可变 release、严格校验、原子切换和 last-good 回滚;
- WS 节点只作兼容和应急,Reality + Vision 为主协议;
- 所有真实秘密都由我在目标机本地注入。你只能创建占位符,不能要求我把密钥、订阅、域名、IP、UUID、SNI、短 ID、数据库密码或 Cookie 发到对话里。
请分阶段执行:
A. 第一轮只读盘点,不安装、不修改、不重启;
B. 输出角色、端口、数据流、控制流、风险和回滚点;
C. 创建 vpn-ops-kit 仓库结构、模板、systemd 单元、渲染器、secret scan、配置一致性测试和验收脚本;
D. 按新加坡控制面与节点、WireGuard、广州入口与二级分流、发布器、安卓、软路由的顺序部署;
E. 每一阶段先验证再继续,所有变更必须可回滚;
F. 最终验收必须覆盖真实终端的网关、DNS、TCP、TLS、策略命中、当前节点、出口地区、重复持续下载、浏览器和实际应用,不得用“进程运行”或单次 HTTP 状态代替。
先只做阶段 A,并把发现的冲突和需要我决定的选项列出来。
12. 验收门禁
安卓端
- [ ] FlClash TUN 已连接,Android 报告 VPN 已验证且不可绕过;
- [ ] Private DNS 关闭,无系统 HTTP 代理;
- [ ] 远程配置版本正确,真实策略组与信息面板边界清楚;
- [ ] 手动选择在重启后仍保留;
- [ ] 国内目标直连,境外目标进入选定节点;
- [ ] DNS、TLS、应用登录、消息发送和持续传输均通过。
软路由端
- [ ] OpenClash 运行,Mihomo 加载的是路由器专用 MRS 产物;
- [ ] 内存与 ZRAM 有安全余量,同版本检查不启动第二核心;
- [ ] LAN 客户端的网关和 DNS 正确;
- [ ] 当前节点选择可读取且能持久化;
- [ ] 国内访问不占 VPN,境外访问命中选定节点;
- [ ] 更新失败或 OpenClash 启动失败时自动恢复 last-good。
广州与新加坡服务器
- [ ] Remnawave 控制面健康,数据库与缓存不对公网开放;
- [ ] 广州主入口、新加坡直连入口和兼容入口分别可建立真实连接;
- [ ]
wg0有新鲜握手、隧道内连通,并通过 DNS/TLS 与重复大文件; - [ ]
wg1未通过同样门禁前保持非生产; - [ ] 国内目标命中
gz-direct,境外目标命中sg-default,私网与禁用协议命中blocked; - [ ] 主入口与兼容入口的业务规则一致;
- [ ] 规则更新、流量快照、delivery 刷新和回滚都经过一次实际演练。
真实用户路径
- [ ] 安卓移动网络和家庭 Wi-Fi 分别连续测试,不用一次延迟代表长期质量;
- [ ] 浏览器、应用、视频或大文件持续传输没有首包长时间等待、随机断流或出口漂移;
- [ ] 切换节点后读取策略组当前值,并只清理受影响的旧连接;
- [ ] 重启软路由或单个服务后能自动恢复,不依赖人工补命令;
- [ ] 回滚后旧版本仍能完成同一条真实用户路径。
13. 当前已知限制
- 安卓真机本次未接入 ADB,服务器下发配置已核对,但手机当前选择和系统 VPN 状态仍需用户侧确认。
wg1当前没有新鲜握手;它是实验候选,不是备用即用链路。- 新加坡直连 Reality 当前是降级备用;直连少一跳不代表在所有运营商下更快。
- 当前切换模型以手动选择为主,没有经过完整门禁的自动故障转移。
- 软路由能统计“家庭来源”流量,但服务器侧不能仅凭一条代理连接可靠还原家庭内部具体设备。
- 版本号和软件版本是 2026-09-12 的运行快照;重建时要重新核对兼容矩阵,并固定通过验证的版本,而不是直接使用
latest。
14. 最值得复用的设计原则
- 客户端先分流,服务端再防漏。
- 一个业务策略源,按设备能力生成不同运行产物。
- 控制面与数据面分开判断健康。
- 手动选择必须可读回、可持久化;候选必须经过门禁才能晋级。
- 配置与规则都不可变发布、原子切换、保留 last-good。
- 凭据只在目标机本地注入,分享文档永远只放占位符。
- 验收走真实用户路径:网关 → DNS → TCP → TLS → 策略 → 节点 → 出口 → 持续传输 → 应用。