我的WireGuard组网方案

这一篇note用来记录我的WireGuard组网方案,分享一下在我的使用场景下,我是如何使用WireGuard解决我的实际需求的。

注意,在使用本文的方案之前,请你先了解WireGuard的相关概念。

我的需求

先讲我的需求,我在多地有路由器:在家中有一台路由器,在学校实验室有一台路由器,在学校宿舍有一台路由器。并且每一台路由器下都有一些设备,例如家庭路由器下有PVE和Home-Lab服务器,学校实验室路由器下有一台服务器的BMC,宿舍下有我的游戏本。

而我平常可能需要随时连接任意一台设备,不管是我在学校、在家中、或是在实验室中,我都希望我能够快速地连接到任何一台路由器下的设备。传统方案就是找一台有公网的设备搭建frp,或者用公开的frp服务(例如SakuraFRP)。不过这样还不够便利,在我了解到WireGuard后,我发现这个东西可以解决我的需求。

通过WireGuard,我可以在随时随地,连接到我的家庭、实验室或者宿舍路由器下的任何一台设备。也可以连接其他加入了WireGuard网络的设备,

我的网络环境

接下来是我的网络环境介绍:

首先我的家庭路由器有双栈公网IP,不过本文只讨论IPv4,不讨论IPv6。

然后是学校实验室路由器和学校宿舍路由器,通过DHCP或PPPoE获取到学校内网IP地址。

还有一台阿里云ECS的云服务器,一台也在学校内网下的Linux服务器。

最后是我的移动设备,例如我的手机,我的笔记本。

接下来我需要将他们全部配置到一个大的WireGuard虚拟局域网中,以下是我的配置方案。

路由器互联

首先先介绍我各个路由器的LAN子网网段:

  • 家庭路由器home-gw 172.16.1.0/24
  • 实验室路由器lab-gw 172.16.3.0/24
  • 宿舍路由器dorm-gw 172.16.5.0/24

然后WireGuard VPN虚拟网段,我使用:172.16.0.0/24

第一步就是让他们之间互联,让这三个路由器的子网都能够加入WireGuard网络。

先规定:

  • home-gw在VPN中的地址为172.16.0.1/32
  • lab-gw在VPN中的地址为172.16.0.2/32
  • dorm-gw在VPN中的地址为172.16.0.3/32

那么home-gw的配置文件应该如下:

[Interface]
PrivateKey = <home-gw的私钥>
Address = 172.16.0.1/32
ListenPort = 51820

[Peer]
PublicKey = <lab-gw的公钥>
AllowedIPs = 172.16.0.2/32, 172.16.3.0/24

[Peer]
PublicKey = <dorm-gw的公钥>
AllowedIPs = 172.16.0.3/32, 172.16.5.0/24

由于lab-gwdorm-gw都在学校内网下,所以不需要由home-gw来主动连接他们

lab-gw的配置文件应该如下:

[Interface]
PrivateKey = <lab-gw的私钥>
Address = 172.16.0.2/32
ListenPort = 51820

[Peer]
PublicKey = <home-gw的公钥>
AllowedIPs = 172.16.0.1/32, 172.16.1.0/24
Endpoint = <home-gw的公网地址>

[Peer]
PublicKey = <dorm-gw的公钥>
AllowedIPs = 172.16.0.3/32, 172.16.5.0/24
Endpoint = <dorm-gw>的内网地址

由于lab-gwdorm-gw都在学校内网下,所以可以填写互相的IP地址作为Endpoint,同时使用home-gw的公网IP地址来连接到home-gw

dorm-gw的配置文件同理。

引入移动设备

做完这一步就完成了基本的三个局域网互通,目前三个路由器下的设备都可以相互访问。

下一步是引入移动设备(例如手机、平板),假设我出门在外,我需要连接宿舍路由器下的一台电脑,此时我也需要加入WireGuard网络。

按照一般的想法就是,给手机指定一个VPN的IP地址,例如172.16.0.4,然后在每一台设备下将手机作为peer加入。

然而这样是有一个坑的,例如我的手机在外面,我通过home-gw的公网IP,让我的手机接入了VPN网络,然后例如我想访问到lab-gw,然后当前配置就是这样的:

  • home-gw

    [Interface]
    PrivateKey = <home-gw的私钥>
    Address = 172.16.0.1/32
    ListenPort = 51820
    
    [Peer]
    PublicKey = <lab-gw的公钥>
    AllowedIPs = 172.16.0.2/32, 172.16.3.0/24
    
    [Peer]
    PublicKey = <phone的公钥>
    AllowedIPs = 172.16.0.4/32
  • lab-gw

    [Interface]
    PrivateKey = <lab-gw的私钥>
    Address = 172.16.0.2/32
    ListenPort = 51820
    
    [Peer]
    PublicKey = <home-gw的公钥>
    AllowedIPs = 172.16.0.1/32, 172.16.1.0/24
    Endpoint = <home-gw的公网地址>
    
    [Peer]
    PublicKey = <phone的公钥>
    AllowedIPs = 172.16.0.4/32

这样就会发现一个问题,我的手机能够访问到home-gw的子网设备,但是无法访问lab-gw的子网设备。

仔细发现就能理解,当手机请求lab-gw的子网时,先将数据发送到home-gwhome-gw看到手机的请求后,根据路由表把数据转发给lab-gw,最后lab-gw把数据转发到子网下的设备。

但是回程时就会出现问题,当lab-gw子网下的设备要把数据发回去时,他需要把数据发回172.16.0.4,那么此时lab-gw就会尝试直接把数据发给172.16.0.4,因为有这个peer的存在,所以实际上回程的时候数据包不会发回home-gw再发回手机。

所以就必须要区分手机的逻辑VPN地址,例如他是home-gw的peer时,那他的VPN地址就应该是172.16.0.4;而当他是lab-gw的peer时,那他的VPN地址就该是172.16.0.5。(要和home-gw区分开来)

当设备多了的时候,这个VPN的IP地址就容易乱,不方便管理和记忆。所以在这里我们就引入一个新的网段,例如我这里是:172.16.2.0/24172.16.4.0/24172.16.6.0/24,然后手机设备根据实际情况来选择IP,例如当他作为home-gw的peer时,那么他的IP就是172.16.2.11/32,而以此类推,lab-gw的peer时,IP是172.16.4.11/32dorm-gw同理。


此时的home-gw配置文件应该长这样:

[Interface]
PrivateKey = <home-gw的私钥>
Address = 172.16.0.1/32
ListenPort = 51820

[Peer]
PublicKey = <lab-gw的公钥>
AllowedIPs = 172.16.0.2/32, 172.16.3.0/24, 172.16.4.0/24

[Peer]
PublicKey = <dorm-gw的公钥>
AllowedIPs = 172.16.0.3/32, 172.16.5.0/24, 172.16.6.0/24

[Peer]
PublicKey = <phone的公钥>
AllowedIPs = 172.16.2.11/32

lab-gw的就长这样:

[Interface]
PrivateKey = <lab-gw的私钥>
Address = 172.16.0.2/32
ListenPort = 51820

[Peer]
PublicKey = <home-gw的公钥>
AllowedIPs = 172.16.0.1/32, 172.16.1.0/24, 172.16.2.0/24
Endpoint = <home-gw的公网地址>

[Peer]
PublicKey = <dorm-gw的公钥>
AllowedIPs = 172.16.0.3/32, 172.16.5.0/24, 172.16.6.0/24
Endpoint = <dorm-gw>的内网地址

[Peer]
PublicKey = <phone的公钥>
AllowedIPs = 172.16.4.11/32

dorm-gwlab-gw同理,以此类推。

此时手机加入WireGuard网络后,可以被三个路由器下的设备连接,也可以连接三个路由器下的设备。

引入服务器

其实服务器的配置反而会比较简单,直接单独作为一个peer,在每个路由器的配置文件中添加即可。

就算是在内网中的服务器,也只需要添加peer,让他主动连接有公网的路由器来加入WireGuard网络即可。

总结

总结一下我的网络拓扑图如下:

我的WireGuard网络拓扑图


最后,建议在所有在位于NAT后面的设备的[Peer]中加上PersistentKeepalive = 25