Public note

个人 VPN 安卓端、软路由端与双服务器架构及 Codex 重建指南(脱敏版)

·Markdown 原文

个人 VPN 安卓端、软路由端与双服务器架构及 Codex 重建指南(脱敏版)

[!summary] 一句话结论 这不是“整台 VPS 的全栈方案”,只是一套个人 VPN:安卓和软路由用 Mihomo 做一级分流与入口选择;广州服务器承担主入口、兼容入口、订阅发布和二级分流;新加坡服务器承担 Remnawave 控制面、直连入口以及默认境外出口;广州与新加坡之间用 WireGuard 连接。

本文用于公开分享和交给 Codex 重建。文中已删除真实域名、IP 地址、订阅路径、账号、UUID、Reality 密钥、SNI、短 ID、SSH 别名、数据库凭据和自定义端口。所有尖括号内容都是部署者自己的占位符。

1. 范围与当前状态

本文只包含四个实际角色:

  1. 安卓端:FlClash + Mihomo。
  2. 软路由端:GL.iNet GL-MT3600BE + OpenClash + Mihomo。
  3. 广州服务器:公网入口、主 VPN 节点、兼容节点、订阅与规则发布、服务端二级分流。
  4. 新加坡服务器: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 自己按更短周期更新。同步过程必须满足:

  1. 先比较版本;版本未变则不启动第二个 Mihomo。
  2. 版本变化才下载完整产物。
  3. HTTP 版本标记与正文版本一致。
  4. 渲染为路由器专用 MRS 配置。
  5. 用本机 Mihomo 做冷加载检查,并在检查前验证可用内存与交换空间。
  6. 通过后原子替换活动配置并重启 OpenClash。
  7. 启动失败时恢复 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 提供两种能力:

  1. 安卓或软路由可手动选择的新加坡直连 Reality 入口。
  2. 广州 sg-default 经 WireGuard 抵达后的统一境外出口。

直连新加坡路径能少一跳,但不一定更快。移动网络、家庭宽带和云厂商互联路径不同,地理距离不能代替真实 URLTest、失败率和持续传输结果。

6.3 流量统计闭环

Remnawave 数据库保存节点和用户用量历史。新加坡的定时任务:

  1. 读取小时级聚合数据;
  2. 写入本机只读口径的单调账本;
  3. 生成不含用户凭据、节点密钥和订阅路径的最小 JSON 快照;
  4. 经 WireGuard 管理链路发送到广州;
  5. 广州校验快照后刷新信息面板 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. 最值得复用的设计原则

  1. 客户端先分流,服务端再防漏。
  2. 一个业务策略源,按设备能力生成不同运行产物。
  3. 控制面与数据面分开判断健康。
  4. 手动选择必须可读回、可持久化;候选必须经过门禁才能晋级。
  5. 配置与规则都不可变发布、原子切换、保留 last-good。
  6. 凭据只在目标机本地注入,分享文档永远只放占位符。
  7. 验收走真实用户路径:网关 → DNS → TCP → TLS → 策略 → 节点 → 出口 → 持续传输 → 应用。