之前的文章中,我介绍过一种比较直接 的链式 VPN 方案:所有设备先连接到自己搭建的WireGuard 服务器,再由服务器把流量转 发到 Gluetun,最终通过上游 VPN 服务商的出口访问互联网。

这个方案的核心价值很明确:

  • 所有设备只需要配置一个 WireGuard;
  • 上游 VPN 只需要在服务器端维护;
  • 可以把手机、电脑、平板、家用设备统一接入同一个虚拟局域网;
  • 出口 IP 由商业 VPN、公司 VPN 或其他上游 VPN 提供,而不是直接暴露 VPS IP;
  • 整套系统可以通过 Docker 部署,尽量不污染宿主机环境。
  • 相比于直连VPN,该方案下VPN服务商能看到的只是你的VPN网关出口(你的VPS服务 器),而不是每个设备的真实 IP。
  • 另外,本地的ISP等也看不到你是否是在使用主流VPN,因为他们只能知道你在连接到一个 VPN网关(你的VPS服务器),但流量最终去了哪里是未知的。

不过,随着使用场景变多,原来的结构也逐渐暴露出一些局限。最典型的问题是,对流量的 控制不够细粒度。默认情况下所有流量都必须进入上游 VPN 隧道,这对于某些服务可能会 触发风控,或者导致访问问题。而且比较难方便地进行流量工程,对不同服务采用不同的出 口策略。原先通过 iptables 和路由表的方式虽然能实现分流,但规则一多就难维护。

因此,我把原来的方案重新整理成了一个更完整的个人 VPN 网关架构。新版方案不再只是 简单的 WG-Easy + Gluetun,而是变成了:

WG-Easy + sing-box + Gluetun + AdGuard Home + config.yaml 统一配置生成

对我来说,这套方案已经不只是“VPN 套 VPN”,而是一个可以长期维护、可扩展、可观察的 个人网络出口。它既可以服务日常上网,也可以服务远程办公、家庭内网访问、开发测试和 多设备统一管理。如果你只需要最简单的全局 VPN 转发,旧版思路仍然够用。但如果你希 望在隐私、可控性、分流规则和 DNS 管理之间取得更好的平衡,新版架构会更合适。

这篇文章会介绍新版架构的设计思路、流量路径、适合的使用场景,以及相比旧方案的主要 改进。如果你对新版方案感兴趣,或者想直接部署使用,可以直接查看我在 GitHub 上的 项目仓库

为什么需要新版架构

最早的链式 VPN 方案其实已经能解决很多问题。比如我在家里、办公室、外出网络中都可 以使用同一个 WireGuard 配置接入 VPS,然后通过 VPS 上的 Gluetun 进入上游 VPN。这 样所有设备都共享同一个上游 VPN 出口,也能避免在每台设备上反复安装、登录、配置不 同 VPN 客户端。

这个方案实际我平时使用下来也很稳定,性能也能够满足我的需求,基本上没有什么大问 题。但长时间使用下来,我还是遇到了几大痛点。

不是所有流量都适合走上游 VPN

我在实际的使用中发现,某些服务可能会因为 VPN 出口触发风控,例如账号登录、支 付、AI 服务等。比如一些我常用的流媒体平台,对于VPN有着严格的限制,有时这些流量更 适合直连。还有就是,我有时候需要网文在校园网内部的课程服务器,有时候会涉及远程桌 面,这需要比较低的延迟。这种情况下,走VPN的话即使是本国出口体验也非常不佳。

因此,我希望能有更细粒度的分流能力。比如通过规则集把我信任的一些服务的流量绕过上 游 VPN,直接从服务器侧访问互联网。这样既能保持上游 VPN 的隐私保护,又能避免一些 不必要的访问问题。以前的做法更多依赖 iptables、路由表和容器网络。能工作,但规则 一多就难维护。

在通过调研和测试后,我发现 sing-box 的 TUN 模式非常适合做这种基于规则的分流。它 支持丰富的规则类型和灵活的路由策略,可以根据域名、IP等多维度来决定流量的下一跳。 通过把 sing-box 放在 WG-Easy 和 Gluetun 之间,我就能实现更智能的流量分流,而不是 简单的全局 VPN。然后singbox能够引用远程的规则集,例如 geosite-openai、geosite-paypal 等,这样我就不需要自己维护这些规则了。还有就是, 相比于部署一个openwrt虚拟机,singbox的部署和维护都更轻量级,对docker更友好。

如此一来,我就能够更灵活地进行流量工程了。比如:默认流量,为了隐私保护需要它们走 VPN。而有些在特定区域的服务,我希望从另外的VPN 出口访问;有些服务我希望直接访 问;有些服务我希望通过特定的 VPN 出口访问。通过sing-box 的规则分流,我可以更方便 地实现这些策略。

配置需要集中管理

原先仓库中配置都是分散在conf目录下,修改网段的等配置本来就不太方便。在加入 sing-box后,Docker Compose、wg-easy hook、sing-box JSON、AdGuardHome 配 置、iptables 规则一起维护,就比较痛苦了。所以,新版方案我用config.yaml 作为单 一配置入口,再通过模板生成 runtime 文件。

每次修改配置后,直接运行生成up.sh脚本就能把所有相关配置文件更新到位,避免了“改 了这个忘了改那个”的问题。

更完善的网络监控

原来的方案主要依赖日志来观察网络状态。我有时候像看一下当前有哪些设备现在连接了 WireGuard,这些设备都会访问什么服务,有没有异常流量等。在原先的方案里,这些信息 都需要自己在容器里查看日志,或者额外安装一些监控工具。新版方案通过singbox提供的 API接口,可以配合MetaCubeXD等工具来实时查看流量分布、规则命中、上游访问等信息, 提升了可观测性。

因此,新版架构的目标不是单纯“再套一层 VPN”,而是构建一个更像家庭或个人使用的可控 网络出口。

新版方案的组件

新版方案主要由四个核心容器组成。

WG-Easy:WireGuard 接入层

WG-Easy 仍然负责最基础也最重要的部分:提供 WireGuard 服务端和 Web 管理界面。所有 手机、电脑、平板、服务器都作为 WireGuard 客户端连接到 WG-Easy。用户可以通过 WG-Easy 的 Web UI 创建 peer、下载配置文件或扫码导入手机端。

在新版架构中,WG-Easy 不再只是把流量直接交给 Gluetun,而是通过 hook 和 policy routing 把客户端流量导入更复杂的网关路径。

AdGuard Home:统一 DNS 与过滤层

AdGuard Home 负责 DNS 解析、广告过滤、跟踪域名拦截和 DNS 查询日志。

新版架构中,来自 WireGuard 客户端的普通 DNS 请求会被限制到 AdGuard Home。也就是 说,客户端不能随便把 DNS 发到 8.8.8.81.1.1.1 或其他外部 DNS 服务器。

这样做的好处是:

  • 可以集中设置上游 DNS;
  • 可以统一管理过滤列表;
  • 可以查看客户端 DNS 查询;
  • 可以降低 DNS 泄露风险;
  • 可以避免每台设备单独配置过滤软件。

当然,这并不等于可以完全阻止所有形式的 DNS 绕过。比如 DoH、DoT 或某些应用内置解 析仍然需要额外策略处理。但对于普通 UDP/TCP 53 DNS 请求,网关可以做到统一收口。

sing-box:规则分流层

sing-box 是新版架构中最关键的变化。

它通过 TUN inbound 接收 WG-Easy 转发过来的流量,然后根据规则决定下一跳:

  • 命中 bypass_rule_sets 的流量直接出站;
  • 私有 IP 流量直接出站,避免误送进上游 VPN;
  • 其他默认流量打上 routing mark,交给 Linux policy routing,再进入 Gluetun;
  • 规则集可以使用远程 .srs 文件,例如 geosite-openai、geosite-paypal 等。

如果你看对应的singbox的配置文件,会发现一个比较奇怪的点:sing-box 里的 gluetun outbound 在配置上也是 direct类型,但它带有 routing_mark。实际上,这个 mark 会被Linux policy routing 捕获,把流量导向 Gluetun。因此它并不是普通意义上的直 连,而是“通过系统路由送到 Gluetun”。

换句话说,sing-box 在这里更像一个智能分流器,而 Gluetun 是最终的上游 VPN 出口。 这里除了通过gluetun,singbox自己也可以通过类似的方式配置其他类型的 outbound,例 如 WireGuard、VLESS、Trojan 等,来适配更多样化的上游服务。如果你不需要gluetun提 供的各种便利性服务,甚至可以在这里就把它换成其他 VPN 客户端或直接的互联网出口。

需要注意的是,singbox在这里是拿不到域名信息,所以我们在这里需要开启sniff 功能来识别域名。这样才能基于域名的规则集来做分流。对于一些不支持sniff的协议或加 密流量,可能就只能基于IP规则来做分流了。

Gluetun:上游 VPN 出口层

Gluetun 负责连接商业 VPN、公司 VPN 或其他支持的上游 VPN 服务。

它的优势是支持大量 VPN 服务商,并且把 OpenVPN / WireGuard 客户端、认证参数、防火 墙规则、健康检查等逻辑都封装在容器里。

在新版架构中,绝大多数默认流量最终都会进入 Gluetun,再由 Gluetun 通过上游 VPN 隧 道访问互联网。这样客户端看到的是自己的 WireGuard 网络,而互联网看到的是上游 VPN 的出口 IP。

整体网络拓扑

新版架构可以理解为下面这个路径:

  flowchart TD
  subgraph devices["Your Devices"]
    phone["Phone"]
    pc["PC"]
    laptop["Laptop"]
  end

  subgraph server["Your Server"]
    wgeasy["WG-Easy (WireGuard Server)"]
    adguard["AdGuard Home (DNS Filtering)"]
    singbox["sing-box (TUN Router / Rule Engine)"]
    gluetun["Gluetun (VPN Provider Client)"]
  end

  phone -- WireGuard --> wgeasy
  pc -- WireGuard --> wgeasy
  laptop -- WireGuard --> wgeasy

  wgeasy -- DNS only --> adguard
  wgeasy -- regular traffic --> singbox
  singbox -- bypass_rule_sets --> direct["Direct Internet"]
  singbox -- default route --> gluetun
  gluetun -- VPN tunnel --> provider["VPN Provider"]
  provider --> internet["Internet"]
  direct --> internet

从流量角度看,可以分成三类:

  1. DNS 流量:WireGuard 客户端的 DNS 请求被固定转发到 AdGuard Home。
  2. 命中绕过规则的流量:例如 OpenAI、PayPal 或其他你放进 bypass_rule_sets 的规则集,可以走 direct。
  3. 默认流量:没有命中绕过规则的普通互联网流量会进入 Gluetun,再通过上游 VPN 出口访问互联网。

此外,还可以配置 direct_subnets,让特定网段绕过 sing-box。这适合一些明确的内网 访问场景,例如访问家庭局域网、特定 Docker 网络或某些专用子网。

配置管理:从手写配置到生成式配置

新版方案的另一个重要变化是配置管理方式。

以前你可能需要同时修改:

  • docker-compose.yml
  • WireGuard hook
  • iptables 规则
  • Gluetun 环境变量
  • DNS 配置
  • sing-box JSON
  • AdGuard Home 配置

这样虽然灵活,但维护成本很高。尤其是网络结构稍微变化后,很容易出现“一个地方改 了,另一个地方忘了改”的问题。新版方案把主要配置集中到 config.yaml, 然后通过生成脚本把它渲染成 runtime/ 下的各种实际的配置文件。

因此,普通用户只需要改 config.yaml。而高级用户如果要调整更多的配置,则可以修改 templates/ 下的 Jinja2 模板。这样既保证了配置的集中管理,也保留了足够的灵活性。

需要注意的是,我建议不要直接修改 runtime/ 目录下的文件。它们是生成物,每次重新运行都会被覆 盖。

sing-box 分流规则如何工作

新版方案中,sing-box 的规则大致可以理解为:

{
  "route": {
    "rules": [
      { "inbound": "tun-in", "action": "sniff" },
      { "ip_is_private": true, "outbound": "direct" },
      {
        "rule_set": ["geosite-openai", "geosite-paypal"],
        "outbound": "direct"
      },
      { "outbound": "gluetun" }
    ]
  }
}

这表示:

  1. 先对流量做 sniff,识别域名等信息;
  2. 私有 IP 地址直接走 direct;
  3. 命中规则集的流量走 direct;
  4. 其他所有流量走 gluetun outbound。

bypass_rule_sets 的含义是“绕过上游 VPN”,不是“绕过你的服务器”。

例如你配置了:

singbox:
  bypass_rule_sets:
    - tag: "geosite-openai"
      url: "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-openai.srs"
    - tag: "geosite-paypal"
      url: "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-paypal.srs"

那么这些服务的流量仍然会经过你的 WireGuard 服务器和 sing-box,只是不再进入 Gluetun 的上游 VPN 隧道,而是由服务器侧直接访问互联网。

这对一些对 VPN 出口敏感的服务很有帮助。比如有些服务看到商业 VPN IP 会要求额外验 证,甚至直接拒绝访问。通过规则绕过上游 VPN 后,可以减少这类问题。

extra_rule_sets 是什么

新版配置里还有一个 extra_rule_sets

singbox:
  extra_rule_sets:
    - tag: "geosite-google"
      url: "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-google.srs"
    - tag: "geosite-apple"
      url: "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-apple.srs"

它的作用是:下载并缓存这些规则集,但不参与当前路由匹配。也就是 说,extra_rule_sets 不会改变流量路径。只有放进 bypass_rule_sets,或者在 sing-box 模板里显式引用,规则才会真正生效。

我保留这个配置项,是为了方便未来扩展。例如我可能想先把 Google、Apple、Amazon 等 规则集准备好,但不马上启用。等到需要时,只需要把对应规则移到 bypass_rule_sets,或者添加新的 route rule。

如果你追求最简配置,也可以把 extra_rule_sets 设置成空数组:

singbox:
  extra_rule_sets: []

注意,YAML 中最好写成显式空数组,而不是只写一个空 key:

# 推荐
extra_rule_sets: []

# 不推荐,容易被解析成 null
extra_rule_sets:

DNS:为什么要默认引入 AdGuard Home

在 VPN 网关中,DNS 是一个很容易被忽略的问题。如果只管普通流量,不管 DNS,就可能 出现这种情况:

  • 浏览器流量走了你的 VPN 网关;
  • DNS 查询却发给了本地网络、运营商 DNS 或某个公共 DNS;
  • 最终造成 DNS 泄露,或者规则分流判断不准确。

新版架构里,WireGuard 客户端的普通 DNS 请求会被限制到 AdGuard Home。这样你可以在 网关侧统一管理 DNS。

AdGuard Home 可以带来几个好处:

  • 广告和跟踪域名过滤;
  • 自定义上游 DNS;
  • 查询日志;
  • 本地域名重写;
  • 对不同客户端做差异化策略。

不过需要注意,如果你想完全禁止所有 DNS 绕过,还需要考虑 DoH/DoT/QUIC等情况。本文 中的 DNS 限制主要针对传统 UDP/TCP 53 查询。

适合的使用场景

新版架构可以覆盖的场景比旧版更多,综合考虑下,主要适用于以下几种情况:

1. 多设备共享一个上游 VPN

这是最基础的使用方式。

你只需要在服务器上配置一次上游 VPN,所有设备通过 WireGuard 接入。手机、电脑、平 板、备用机都不需要分别安装上游 VPN 客户端。

这对于设备数量较多、平台较杂,或者上游 VPN 客户端体验不佳的情况尤其有用。

2. 远程访问家庭或办公网络

所有设备接入同一个 WireGuard 网络后,可以形成一个统一的虚拟局域网。

你可以用它访问:

  • 家里的 NAS;
  • 办公室内网服务;
  • 私有 Git 服务;
  • 家庭媒体服务器;
  • SSH 管理入口。

如果配合 direct_subnets,还可以让部分内网访问不经过复杂的 sing-box 分流逻辑。

3. 对不同服务采用不同出口策略

有些服务适合走商业 VPN,有些服务则不适合。

例如:

  • 默认流量走 Gluetun 上游 VPN;
  • OpenAI、PayPal 等敏感服务走 direct;
  • Torrent、P2P 流量走Gluetun或者其他专门的 VPN 出口;
  • 私有 IP 和内网地址不进入上游 VPN;
  • 特定规则集预先下载,但暂不启用。

这种结构比旧版本的“全局代理”更灵活,也比纯手写 iptables 规则更容易维护。

5. 低侵入式部署

整套方案基于 Docker Compose。宿主机只需要安装 Docker 和 Docker Compose,主要网络 逻辑都在容器和生成配置中完成。这对 VPS、家用服务器、软路由、树莓派都比较友好。

部署流程概览

实际部署时,流程大致是:

git clone https://github.com/saturneric/wg-easy-gluetun.git
cd wg-easy-gluetun

然后编辑:

vim config.yaml

至少需要配置:

  • 上游 VPN 的 WireGuard / OpenVPN 参数;
  • WG-Easy 管理密码;
  • 服务器公网地址或域名;
  • AdGuard Home 上游 DNS;
  • sing-box 绕过规则;
  • 必要的服务端口和固定容器 IP。

启动时使用:

./up.sh -d

不要直接运行普通的 docker compose up,因为 runtime compose 文件和相关配置需要 先由生成器创建。up.sh 会先运行配置生成逻辑,再启动完整 stack。

安全注意事项

这类网关方案虽然方便,但也需要注意安全边界。

1. 不要使用默认密码

config.yaml 里的 WG-Easy 密码、Clash API secret、AdGuard Home 凭据都应该修改。 尤其是管理界面如果暴露在公网,默认密码会非常危险。

2. 谨慎暴露管理端口

通常只应该公开 WireGuard UDP 端口。WG-Easy、MetaCubeXD、AdGuard Home 管理界面最 好不要直接暴露在公网。

3. 确认上游 VPN 服务条款

多设备共享、网关转发、链式 VPN 是否被允许,取决于你的上游 VPN 服务条款。部署前应 该自己确认。

4. 注意 DNS 绕过

本方案会限制普通 DNS 查询,但不能自动阻止所有应用层 DoH / DoT 行为。如果你需要更 严格的 DNS 策略,需要额外做域名、IP、SNI 或应用层策略控制。

总结:相比旧版方案的主要变化

和旧版 WG-Easy + Gluetun 相比,新版架构主要有这些变化:

方面 旧版 新版
接入层 WG-Easy WG-Easy
上游 VPN Gluetun Gluetun
分流能力 主要依赖路由和 iptables sing-box 规则集分流
DNS 需要额外配置 默认集成 AdGuard Home
配置方式 多文件手动维护 config.yaml + 模板生成
规则管理 粗粒度 geosite / rule-set 级别
可观测性 主要看日志 可配合 MetaCubeXD 查看 sing-box
扩展能力 相对有限 更适合未来加入更多规则和服务

总而言之,旧版更简单,适合只想把所有流量送进上游 VPN 的用户。新版则更适合长期使用,尤其适 合需要分流、DNS 过滤、集中管理和多场景适配的用户。