跳到主要内容

WireGuard 配置备忘录

· 阅读需 14 分钟
Skyone

封面

总结一下 WireGuard 的配置方法,以免长时间不用忘记。

主要包含以下内容:

  • 关键概念
  • 使用 wg-quick
  • 实际场景例子

文章基于 Arch Linux,理论上适用于所有 Linux 发行版。

WireGuard 简介

为了文章结构清晰,还是放一段 WireGuard 的介绍。

WireGuard is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography. It aims to be faster, simpler, leaner, and more useful than IPsec, while avoiding the massive headache. It intends to be considerably more performant than OpenVPN. WireGuard is designed as a general purpose VPN for running on embedded interfaces and super computers alike, fit for many different circumstances. Initially released for the Linux kernel, it is now cross-platform (Windows, macOS, BSD, iOS, Android) and widely deployable.

WireGuard 是一个极其简单、快速和现代的 VPN,它使用最先进的密码学。它旨在比 IPsec 更快、更简单、更精简、更有用,同时避免令人头疼的问题。它的性能比 OpenVPN 要好得多。WireGuard 被设计为一个通用的 VPN,适用于嵌入式接口和超级计算机,适用于许多不同的情况。最初发布于 Linux 内核,现在跨平台(Windows、macOS、BSD、iOS、Android),可广泛部署。

关键概念

WireGuard 没有服务端和客户端的概念,只有 peer 的概念。peer 之间是对等的,没有主从关系。可以理解为每个 peer 就是一个设备,WireGuard 只是在设备之间建立了一个虚拟的网络。

在由 WireGuard 建立的虚拟网络中,每个 peer 都有一个 IP 地址,peer 直接通过这个 IP 地址进行通信。当然,这些 IP 都属于同一个子网,这个子网的网段可以自己定义。

既然是 VPN,必然依赖物理网络。也就是说,peer 之间的通信必须通过物理网络,而 WireGuard 只是在物理网络上建立了一个虚拟的网络。这个虚拟的网络就是 WireGuard 的网络接口,可以理解为一个虚拟的网卡。

两个设备如果要建立连接,必须要有一方需要有公网 IP。

当然,也可以用一个中间设备来转发数据,这个中间设备必须要有公网 IP。

使用 wg-quick

使用 wg 命令配置 WireGuard 是一件很繁琐的事情,而且也不便于持久化。WireGuard 官方提供了一个脚本 wg-quick,可以简化配置过程。我们只需要写好一个配置文件,然后使用 wg-quick 命令就可以了。

最简单的配置文件如下:

[Interface]
Address = 10.0.0.1/24
ListenPort = 52021
PrivateKey = PEER_A_PRIVATE_KEY

[Peer]
PublicKey = PEER_B_PUBLIC_KEY
AllowedIPs = 10.0.0.2/32

[Peer]
PublicKey = PEER_C_PUBLIC_KEY
AllowedIPs = 10.0.0.3/32

Interface

Interface 部分是 WireGuard 的网络接口的配置。

对于一个 VPN 网络,每个 Peer 只需要一个网络接口。一个 Peer 可以同时连接任意个 VPN 网络,也就是说,一个 Peer 可以有任意个网络接口。但是对于一个配置文件来说,只能有一个 Interface 部分。要想连接多个 VPN 网络,就需要多个配置文件,分开管理。

配置 Address

虚拟网络的 IP 地址。格式为 IP/子网掩码。例如:192.168.100.1/24,指定本地虚拟网络的 IP 地址为 192.168.100.1,子网范围为 192.168.100.1 ~ 192.168.100.254。所有的 peer 必须在同一个子网中。

配置 ListenPort

前面提到,WireGuard 是建立在物理网络之上的。WireGuard 通过 UDP 协议进行通信,这个端口就是 WireGuard 用来通信的端口。两个 peer 之间必须要有一个拥有公网 IP,没有公网 IP 的 peer 可以不填。

配置 PrivateKey

本地 peer 的私钥。可以使用 wg genkey 命令生成。每个 peer 都有一自己独立的私钥。

PostUpPostDown

这两个配置项是可选的。指定在启动和关闭 WireGuard 时执行的命令。一般用来配置 iptables 规则,比如做 SNAT 或者 DNAT。

Peer

对于一个 VPN 网络,并不是所有 Peer 都必须指定,只需要明确流量到达每个 Peer 的路径即可。例如下面的 VPN 网络:

A 和 B 直接不直接连接,而是通过 C 中转,这时候 A 只需要指定 C 这一个 Peer 即可。然后通过 AllowedIPs 指定指向 B 的流量发送到 C。

配置 PublicKey

远程 peer 的公钥。可以使用 wg pubkey 命令从远程 peer 的私钥生成。每个对端都有自己的私钥,与之对应,也有自己独立的公钥。

配置 AllowedIPs

这是一个非常重要的配置项,它指定了流量的走向。格式为 IP/子网掩码

每个 Peer 的 AllowedIPs 不可以与其他任何 Peer 的 AllowedIPs 有重叠。

新手一般最搞不懂的就是这个配置项。这里我用最简单的话来解释一下:

AllowedIPs 告诉自己,目的地为 AllowedIPs 的流量全部发送到这个 Peer。

就是这么简单,对端的 AllowedIPs 并不能阻止流量到达对端。

举个例子:

这里 A 和 B 都指定了 C 为对端,但是 A 和 B 之间并不能直接通信,只能通过 C 中转。这时候 A 和 B 的配置需要指定 AllowedIPs192.168.1.0/24,也就是任何目的地为当前子网的流量都发送到 C

而 C 则需要分别指定 A 和 B 的 AllowedIPs,例如 C 对 A 的 AllowedIPs192.168.1.1/32,也就是只允许目的地为 A 的流量发送到 A

当 A ping B 时,目的地为 192.168.1.2 的流量倍发到 C,C 发现目的地为 192.168.1.2,符合 B 的 AllowedIPs,于是将流量发送到 B。

明白了这一点,你应该知道为什么每个 Peer 的 AllowedIPs 不可以与其他任何 Peer 的 AllowedIPs 有重叠。如果有重叠,那么流量就不知道该发送到哪里了。

配置 Endpoint

这个配置项是可选的,如果没有指定,那么 WireGuard 不会主动连接对端。只有当对端连接过来时,才会建立连接。也就类似 FTP 的被动模式。

只要对端拥有公网 IP,那么就应该指定 Endpoint。端口就是对端的 ListenPort。同样是以前面的例子为例:

其中 A 和 B 不需要配置 ListenPort,但是 C 必须要配置 ListenPort。A 和 B 需要配置 Endpoint,例如 A 的 Endpoint[C 的公网 IP]:[C 的 ListenPort]

配置 PersistentKeepalive

这个配置项是可选的,如果没有指定,那么 WireGuard 不会主动发送心跳包。如果对端没有配置 Endpoint,那么就需要配置 PersistentKeepalive,以保证连接不会断开。我一般配置为 25

实际场景例子

两台设备互联

首先是最简单的例子,两台设备互联。两台设备都有公网 IP,两台设备都需要配置 ListenPortEndpoint

A 设备的配置文件:

[Interface]
Address = 192.168.1.1/24
ListenPort = 51000
PrivateKey = PEER_A_PRIVATE_KEY

[Peer]
PublicKey = PEER_B_PUBLIC_KEY
AllowedIPs = 192.168.1.2/32
Endpoint = 114.5.1.5:51000

B 设备的配置文件:

[Interface]
Address = 192.168.1.2/24
ListenPort = 51000
PrivateKey = PEER_B_PRIVATE_KEY

[Peer]
PublicKey = PEER_A_PUBLIC_KEY
AllowedIPs = 192.168.1.1/32
Endpoint = 114.5.1.4:51000

服务器转发两设备

这个例子是上面例子的变种,只是多了一个服务器。服务器有公网 IP,两台设备没有公网 IP,只能通过服务器转发。

A 设备的配置文件:

[Interface]
Address = 192.168.1.2/24
PrivateKey = PEER_A_PRIVATE_KEY

[Peer]
PublicKey = PEER_C_PUBLIC_KEY
AllowedIPs = 192.168.1.0/24
Endpoint = 114.5.1.5:51000

B 设备的配置文件:

[Interface]
Address = 192.168.1.3/24
PrivateKey = PEER_B_PRIVATE_KEY

[Peer]
PublicKey = PEER_C_PUBLIC_KEY
AllowedIPs = 192.168.1.0/24
Endpoint = 114.5.1.5:51000

C 设备的配置文件:

[Interface]
Address = 192.168.1.1/24
ListenPort = 51000
PrivateKey = PEER_C_PRIVATE_KEY

[Peer]
PublicKey = PEER_A_PUBLIC_KEY
AllowedIPs = 192.168.1.2/32

[Peer]
PublicKey = PEER_B_PUBLIC_KEY
AllowedIPs = 192.168.1.3/32

更复杂的情况

这是我自己实际的例子:

  • 有多台没有公网 IP 的随身携带的设备,比如手机和笔记本电脑,这里用设备A表示。
  • 家里有一个树莓派4B,没有公网 IP,为设备 B。
  • 有一台服务器,有公网 IP,为设备 C。
  • 家里有局域网,局域网内设备若干。

要求:

  • ABC 之间互联。
  • 所有设备都能无缝访问家里的局域网网段,IP 都不需要改。
  • 不影响对公网的访问。

A 设备(笔记本电脑)的配置文件:

[Interface]
Address = 192.168.1.2/24
PrivateKey = PEER_A_PRIVATE_KEY

[Peer]
PublicKey = PEER_C_PUBLIC_KEY
AllowedIPs = 192.168.1.0/24, 192.168.10.0/24
Endpoint = 114.5.1.5:51000

B 设备(树莓派)的配置文件:

[Interface]
Address = 192.168.1.3/24
PrivateKey = PEER_B_PRIVATE_KEY

PostUp = iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j SNAT --to-source 192.168.10.100
PostDown = iptables -t nat -D POSTROUTING -s 192.168.1.0/24 -j SNAT --to-source 192.168.10.100

[Peer]
PublicKey = PEER_C_PUBLIC_KEY
AllowedIPs = 192.168.1.0/24
Endpoint = 114.5.1.5:51000

C 设备(服务器)的配置文件:

[Interface]
Address = 192.168.1.1/24
ListenPort = 51000
PrivateKey = PEER_C_PRIVATE_KEY

# Peer A: 笔记本电脑
[Peer]
PublicKey = PEER_A_PUBLIC_KEY
AllowedIPs = 192.168.1.2/24

# Peer B: 家里的树莓派
[Peer]
PublicKey = PEER_B_PUBLIC_KEY
AllowedIPs = 192.168.1.3/24, 192.168.10.0/24

最值得注意的是 B 设备的配置文件。由于需要使其他 VPN 网络(192.168.1.0/24)的设备和家里的局域网(192.168.10.0/24)的设备互联,可以把 B 设备看作 VPN 网络的网关(只针对局域网网段),所以 B 设备需要配置 SNAT 规则。

iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j SNAT --to-source 192.168.10.100

POSTROUTING 上添加 SNAT 规则,将源 IP 为 192.168.1.0/24 的流量的源 IP 改为 192.168.10.100

也就是将来自 VPN 网络的其他设备发往家里局域网的流量的源 IP 改为 B 设备的 IP。这样家里其他设备认为是树莓派发来的流量,会将回复的流量发给树莓派,树莓派再转发给 VPN 网络的其他设备。

【完】