碎碎念

之前一直想着部署一套系统,好让自己不在家的时候也能访问家中部署的服务。然而使用 frp 之类的工具直接将服务暴露在公网上还是过于危险了一些,出于安全考虑,决定使用 VPN 工具组建一个虚拟的局域网,这样要进入家中的私有网络就必须先攻破 VPN 的防护,起到了一定的安全保障作用,让人比较放心。

说起 VPN,马上想到的自然是 OpenVPN。可惜我花了一两周时间也没搞明白我到底要部署哪些东西,写哪些配置文件,实在是太繁琐了。而且官方提供的 OpenVPN Server 貌似还只能提供两个客户端的连接支持,也不太够我几台设备用,所以后面看到 WireGuard 配置起来那么方便果断放弃了折腾 OpenVPN,省下了不少头发。WireGuard 配置起来又省心又方便,虽然功能可能没有 OpenVPN 那么强大,但对于简单的建立隧道的需求来说,WireGuard 已经完全够用了,而稳定性与安全性方面有 Linux 内核的背书,无需顾虑。比较蛋疼的一点是这个在 BSD 系统上支持不算好,在我的 pfSense 防火墙上配置需要一点手动操作,不过无伤大雅。这里就我配置 WireGuard 的过程作一简单记录,以供参考。

Wireguard 是怎么工作的

先简单讲讲 WireGuard 的工作流程。WireGuard 的工作核心是 TUN 网卡。对 Linux 网络稍微有点了解的人可能知道 TUN 设备是什么,简单来说就是虚拟出来的一张网卡,向这张网卡发送的数据会被送到指定的应用进行处理。建立隧道的两端需要分别运行 WireGuard,然后两边的 WireGuard 各创建一个虚拟网卡,网卡通向 WireGuard,两边 WireGuard 再建立一条网络连接,一根虚拟的网线就插上了,我们就有了一个点对点的 VPN 隧道。

除了两个 WireGuard 客户端之间点对点的隧道,WireGuard 还支持同一个接口连接多个客户端,这时候就有点像在接口之间插上了一个路由器,由 WireGuard 在这些接口之间转发数据,就有点像家里路由器和电脑的关系。这两种模式就是 WireGuard 的两种主要工作模式,非常简单。

WireGuard 的配置

WireGuard 套件的安装就不再赘述,官网上提供了各大发行版的详细信息。安装完毕后,有两种模式建立 WireGuard 隧道。一种方式是直接使用命令行工具,很方便,但后续调整起来比较麻烦。个人倾向于先写配置文件,再通过 wg-quick 这一工具根据配置文件启动 WireGuard 隧道。

wg-quick 用到的配置文件以 .conf 结尾,格式和 INI 很像,默认存储在 /etc/wireguard 目录下。配置文件主要由两部分构成,一个 [Interface] 部分用来设置本地端点的信息,而 [Peer] 则描述要连接到的远程接口的信息。一个 .conf 配置文件中只能有一个 [Interface],但能有多个 [Peer]。如果只设置一个 [Peer],那建立的就是点对点隧道。如果设置多个 [Peer],就需要 WireGuard 应用程序进行路由了。

WireGuard 客户端之间的握手十分简单,只要有一方能够访问另一方,双方互相交换公钥后就能够开启加密隧道。因此,WireGuard 的配置文件中只需要写清楚当前客户端的虚拟地址和私钥,对方的公钥,对方的实际地址(可选,只要有一方能访问到另外一方就行)还有路由规则。

配置参数

此配置文件仅为注释说明,请勿直接用于部署 WireGuard。此文件适用于 wg-quick

[Interface]
# 本机的私钥,用于验证身份和加密通讯
PrivateKey = yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk=

# WireGuard 在本地的监听端口
ListenPort = 51820

# 逗号分隔的 IP 地址,这些地址会被分配到这个接口
Address = 10.192.122.1/24

# 逗号分隔的 IP 地址,这些地址会被设置成这个接口的 DNS 地址。
DNS = 

# 控制添加路由规则的 iptables 表名。有两个特殊值 auto 和 off, 点对点通道可以通过设置为 off 从而手动进行路由
Table = 1234

# hook 函数,在接口进入指定状态的时候执行的 bash 命令,常用来设置防火墙条目和 DNS 选项
PreUp = 
PostUp = ip rule add ipproto tcp dport 22 table 1234
PreDown = ip rule delete ipproto tcp dport 22 table 1234
PostDown = 

# 保存状态,设置为真后,当接口关闭时会将接口的当前状态写入配置文件
SaveConfig = true

[Peer]
# 对方的公钥
PublicKey = xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg=

# 一个或多个逗号分隔的 CIDR 地址,目的 IP 地址在该范围内的数据包将被发送到此 Peer
AllowIPs = 10.192.122.3/32, 10.192.124.1/24

# 可选,用 wg-genpsk 生成的 preshared key,在公钥加密的基础上再套一层对称加密
PresharedKey = htrLzMKvHuQtepDodRF657vBmrpNA07d04JU8agKLUQ=

# 可选,对方的实际地址,可以是 ip:port 的格式也可以是 域名:port 的格式
Endpoint = demo.wireguard.com:51820

# 可选,心跳包间隔,用来保持 NAT 连接会话
PersistentKeepalive = 30 

pfSense 上对 WireGuard 的支持

pfSense 曾经直接在系统中提供 WireGuard 模块,但随着 FreeBSD 移除了 WireGuard,pfSense 也从 CE 2.5.0 版本开始不在基本系统中提供 WireGuard。不过在 pfSense CE 2.5.2 版本之后 WireGuard 重新以 add-on package 的形式提供,所以在新版本的 pfSense 需要到 package manager 里面手动安装 WireGuard。

pfSense 上对 WireGuard 的配置与 Linux 下基本一致,只是将命令行工具与配置文件换成了 Web UI。不过还是有一点要注意,pfSense 上对 WireGuard peer 的 AllowIPs 路由支持不是很好,在添加 AllowIPs 后只会自动添加一个地址块的静态路由,如果有多个地址块需要路由到 WireGuard,则需要手动向 pfSense 中添加静态路由才行。配置路由的过程可以参考 官方文档

参考

  1. Installation - WireGuard

  2. pirate/wireguard-docs: 📖 Unofficial WireGuard Documentation: Setup, Usage, Configuration, and full example setups for VPNs supporting both servers & roaming clients. (github.com)

  3. [WireGuard/2. 用 wg-quick 调用 wg0.conf 管理 WireGuard.md at master・wgredlong/WireGuard (github.com)](https://github.com/wgredlong/WireGuard/blob/master/2.% E7%94% A8%20wg-quick%20% E8% B0%83% E7%94% A8%20wg0.conf%20% E7% AE% A1% E7%90%86%20WireGuard.md)

  4. wg (8) - Linux manual page (man7.org)

  5. wg-quick (8) - Linux manual page (man7.org)

  6. Virtual Private Networks — WireGuard | pfSense Documentation (netgate.com)