使用 WireGuard 访问家庭网络

WireGuard + Surge 异地组网实践

WireGuard 是一个高性能的 VPN,直接对标 OpenVPN,被 Linus 称赞为“art of work”并被合入到 Linux 主干。正好我最近搭了一台家庭服务器作为私人开发机,需要在外网环境访问家庭网络,自然 WireGuard 就成了不二选择。恰逢 Surge、Clash 都支持了 WireGuard,只需要配置好网络,访问内网就能更无感。不得不说,在配置过程中几乎没有踩到什么坑,WireGuard 确实是 art of work。

在使用 WireGuard 之前,请确保你的 Linux 内核 >= 5.10,我使用的内核都是 5.19(Ubuntu 22.04 LTS)。Surge 的版本是 4,在 Mac 和 iOS 版本上均测试通过。

我将整个网络分为了家庭内局域网段(192.168.150.0/24)和 WireGuard 网段(192.168.151.0/24),不建议使用 192.168.0.0/24 这种烂大街的网段,不然很容易产生不必要的冲突。另外提一嘴,我的需求是访问开发机,而不是整个家庭网络(即 192.168.150.0/24 内的全部设备),因此我没有使用 SNAT 转换网段,如果你对这部分内容感兴趣,推荐你参考 [1]。

网络拓扑结构如上图所示。家庭内部(Region: Home)有一个开发服务器(称为 dev),我给他分配的局域网地址是 192.168.150.2,WireGuard 地址是 192.168.151.2。一个公网服务器(称为 master),公网 IP 地址是 1.1.1.1,WireGuard 地址是 192.168.151.1。最右边是外部接入设备(称为 com),在这个设备中安装了 Surge,它只有一个 WireGuard 地址 192.168.151.3。

在 master 和 dev 上安装 WireGuard。

$ sudo apt install wireguard

为这三个有 WireGuard 地址的设备生成相应的公钥(pub key)和密钥(priv key),把这个命令执行三遍,每次生成的结果的第一行是密钥,第二行是公钥,请妥善保存,后续都会用到。

$ wg genkey > priv_key && wg pubkey < priv_key > pub_key && echo "priv_key" && cat priv_key && echo "pub_key" && cat pub_key && rm -f priv_key pub_key

假设设备的公钥和密钥如下所示:

Device Private Key Public Key
master priv_key_1 pub_key_1
dev priv_key_2 pub_key_2
com priv_key_3 pub_key_3

以 root 用户登陆 master 机器,将以下内容粘贴到 "/etc/wireguard/wg0.conf" 文件中。

[Interface]
# Master 的 WireGuard 地址
Address = 192.168.151.1/32
# WireGuard 监听端口
ListenPort = 24356
# Master 的私钥
PrivateKey = priv_key_1

# 配置 iptables 以保证内网数据包不会被防火墙过滤
# 允许 192.168.150.0/24 和 192.168.151.0/24 内网互通
PostUp = iptables -I FORWARD -s 192.168.151.0/24 -i wg0 -d 192.168.151.0/24 -j ACCEPT
PostUp = iptables -I FORWARD -s 192.168.151.0/24 -i wg0 -d 192.168.150.0/24 -j ACCEPT
PostUp = iptables -I FORWARD -s 192.168.150.0/24 -i wg0 -d 192.168.151.0/24 -j ACCEPT

# 删除内网互通在 wg 被关闭的时候
PostDown = iptables -D FORWARD -s 192.168.151.0/24 -i wg0 -d 192.168.151.0/24 -j ACCEPT
PostDown = iptables -D FORWARD -s 192.168.151.0/24 -i wg0 -d 192.168.150.0/24 -j ACCEPT
PostDown = iptables -D FORWARD -s 192.168.150.0/24 -i wg0 -d 192.168.151.0/24 -j ACCEPT

# Dev
[Peer]
# Dev 的公钥
PublicKey = pub_key_2
# Dev 的 WireGuard 地址
AllowedIPs = 192.168.151.2/32

# Com 同 Dev 的配置,不再赘述
[Peer]
PublicKey = pub_key_3
AllowedIPs = 192.168.151.3/32

# 如果你还有其他的 peers,列在下面。

保存后,启动 WireGuard。

$ sudo wg-quick up wg0
# 检查 wg0 是否正常启动
$ sudo wg

Master 机器的 WireGuard 配置完毕之后,继续配置开发机 dev 的 WireGuard,以 root 身份将配置内容粘贴到 "/etc/wireguard/wg0.conf"。

[Interface]
# Dev 的私钥
PrivateKey = priv_key_2
# Dev 的 WireGuard 地址
Address = 192.168.151.2/32

[Peer]
# Master 的公钥
PublicKey = pub_key_1
# 允许 WireGuard 内网互通
AllowedIPs = 192.168.151.0/24
# Master 的公网地址 + WireGuard 监听端口
Endpoint = 1.1.1.1:24356
# 内网服务器(无公网 IP)要打开这个选项,否则会出现无法连接的问题,更详细的信息参见
# https://www.wireguard.com/quickstart/
PersistentKeepalive = 25

保存后,启动 WireGuard。

$ sudo wg-quick up wg0
# 检查 wg0 是否正常启动
$ sudo wg

至此 dev 和 master 之间应该可以通过 WireGuard 地址相互访问,我们在 dev 机器上 ping 一下 master 机器。

$ ping -I wg0 192.168.151.1

最后是配置 com 的 Surge,这部分内容可以参考 [2],但是需要注意的是 Surge 的 Benchmark 是无法配合 WireGuard 使用的,而且也无法使用 ping 工具,因此想要测试连通性,需要在 dev 上启动一个 Web 服务,在浏览器里自行测试。Surge 的配置文件也很简单,如下所示。

[Proxy]
Home = wireguard, section-name = Home
[Rule]
IP-CIDR,192.168.151.0/24,Home,no-resolve
[WireGuard Home]
private-key = priv_key_3
self-ip = 192.168.151.3
mtu = 1280
peer = (public-key = pub_key_1, allowed-ips = 192.168.151.0/24, endpoint = 1.1.1.1:24356)

如果你希望在 com 通过 SSH 访问 dev 机器,那么需要你在 "~/.ssh/config" 中添加一项配置,假设 Surge 监听的 HTTP 地址是 "127.0.0.1:1081"。

Host home
  HostName 192.168.151.2
  User <your_user>
  ProxyCommand          nc -X connect -x 127.0.0.1:1081 %h %p

至此,你就可以畅通无阻访问家庭内部网络了。

References

  1. https://devld.me/2020/07/27/wireguard-setup/
  2. https://manual.nssurge.com/policy/wireguard.html
All rights reserved
Except where otherwise noted, content on this page is copyrighted.