WireGuard 初体验

1 概要

本文主要介绍 WireGuard(以下简称 WG)的基本配置方法,并记录一下配置过程中踩到的坑和相应的解决办法。

2 环境

服务器是 Bandwagon 的 VPS 主机,安装的操作系统是 CentOS 7。

客户端操作系统是 macOS 和 Android,后面会尝试在 Linux/Windows 上折腾,但是理论上没太大区别。

3 服务端设置

本章节的大部分操作都需要在 root 身份下运行,请先切换到 root 用户,或在每个命令前加上 sudo

3.1 安装

在 CentOS 上,主要使用 yum 作软件包管理。

WG 的软件包是 wireguard-dkmswireguard-tools。由于 WG 使用了 Linux 的 DKMS 框架,而 CentOS 7 默认是不提供的,因此还需要安装 dkms

首先添加软件源:

1
2
3
4
5
6
7
8
9
# 添加epel软件源,dkms需要从这个软件源安装
yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
# 添加wireguard软件源
curl -o /etc/yum.repos.d/jdoss-wireguard-epel-7.repo https://copr.fedorainfracloud.org/coprs/jdoss/wireguard/repo/epel-7/jdoss-wireguard-epel-7.repo

# 查看所有的软件源,如果列出了以下两个软件源,即表示成功
# - copr:copr.fedorainfracloud.org:jdoss:wireguard/x86_64
# - epel/x86_64
yum repolist

注意:这里有个坑,Bandwagon 提供的 CentOS 7 系统,第一次添加 epel 软件源可能不会生效。如果出现这种情况,请执行命令:

1
2
3
4
5
6
# 删除垃圾文件
rm -f /etc/yum.repos.d/epel.*
rm -f /etc/yum.repos.d/epel-testing.*

# 重新添加epel软件源
yum reinstall https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm

软件源添加完成后,安装必要的软件包:

1
2
# 安装wireguard软件包,dkms作为依赖会自动安装
yum install -y wireguard-dkms wireguard-tools

安装成功后,需要重启服务器,让 dkms 生效。

3.2 WG 配置

3.2.1 生成密钥

WG 使用非对称加密算法来保护信道,因此首先要生成一对密钥:

1
2
3
4
5
6
# 生成公私密钥
wg genkey | tee wg-priv-key | wg pubkey > wg-pub-key
# 查看私钥
cat wg-priv-key
# 查看公钥
cat wg-pub-key

3.2.2 编写配置文件

这里假定使用 51802 作为 VPN 服务的端口,192.168.99.0/24 作为 VPN 内网的 IP 段,VPN 服务器的内网 IP 为 192.168.99.1

注意:VPN 内网的 IP 段,不能与客户端所在的内网 IP 段冲突。

创建文件 /etc/wireguard/wg0.conf,添加如下内容:

1
2
3
4
5
[Interface]
PrivateKey = <上一步生成的私钥>
ListenPort = 51802
Address = 192.168.99.1/24
SaveConfig = true

基于安全考虑,请将上一步生成的私钥文件删除,并修改配置文件的权限:

1
2
3
# 修改配置文件权限
chown root:root /etc/wireguard/wg0.conf
chmod 600 /etc/wireguard/wg0.conf

3.2.3 启动服务

启动 WG:

1
wg-quick up wg0

查看状态:

1
wg show

这里配置的 WG 还不会随开机自动启动,考虑到服务器很少有重启的情况,就没有深入研究。以后有时间会研究自启动方案。

3.3 系统配置

3.3.1 启用数据转发

1
2
3
echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/10-ipforward.conf

sysctl --system

3.3.2 开启数据包伪装

注意:如果你使用了防火墙工具包(如 firewalld/ufw),那么 iptables 里面的规则都是由该工具包维护的,请使用工具包对应的指令添加,而不要直接修改 iptables。

我的服务器用的是 firewalld,需要通过以下命令开启数据包伪装:

1
firewall-cmd --add-masquerade

ufw 等其他防火墙工具包,请参照对应的文档。

直接配置 iptables(适用于没有使用任何防火墙工具包的场景):

1
2
iptables -A FORWARD -i wg0 -j ACCEPT
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

注意:直接添加的 iptables 规则会在重启后丢失,如需持久化,请使用 iptables-save

3.3.3 开放服务端口

如果你使用了防火墙,那么需要在防火墙中开放 WG 的服务端口。

WG 使用的是 UDP 协议,本文中使用的服务端口为 51802,执行命令:

1
2
3
4
5
# 动态添加规则
firewall-cmd --add-port 51802/udp

# 如果希望规则在服务器重启后仍然生效,执行:
firewall-cmd --add-port 51802/udp --permanent

ufw 等其他防火墙工具包,请参照对应的文档。

4 客户端配置

4.1 编写配置文件

不管何种客户端,都是基于 WG 的内核,因此配置文件都是相同的。

配置客户端的第一步,也是生成一对密钥。大部分客户端直接提供了生成密钥的功能,此外也可以使用服务器端的 wg 命令来生成。

不同于大部分 VPN 服务,WG 目前不提供自动分配 IP 的功能。因此在配置客户端时,需要手工指定一个 IP,这个 IP 应该属于前面规划的 VPN 子网 IP 段中。当配置多个客户端时,要确保它们的 IP 互相不冲突。

这里假定为客户端分配的 IP 为 192.168.99.2

客户端配置文件的格式如下:

1
2
3
4
5
6
7
8
9
[Interface]
PrivateKey = <客户端私钥>
Address = 192.168.99.2/24
DNS = 8.8.8.8, 8.8.4.4, 1.1.1.1, 1.0.0.1

[Peer]
PublicKey = <服务端公钥>
AllowedIPs = 0.0.0.0/0
Endpoint = <服务器公网IP或域名>:51802

之后将这个配置文件,导入到对应的客户端中即可。

4.2 注册到服务端

只配置客户端还是不够的,还需要将客户端的公钥注册到 WG 的服务端,服务端才会允许该客户端连接。

在服务器端,通过 wg 命令,可以动态添加客户端:

1
wg set wg0 peer <客户端公钥> allowed-ips "192.168.99.2/32"

注意:在这条命令中,子网掩码必须使用 /32

当然,wg 也同样提供了动态删除客户端的命令:

1
wg set wg0 peer <客户端公钥> remove

至此,全部配置完成,只需在客户端启动 VPN 连接即可。

Enjoy It!

5 总结

正如你看到的那样,WG 在实际使用中还不是那么方便。比如:不能自动分配 IP,每次增 / 减客户端都需要去服务端配置。

作者创建了 wg-dynamic 项目,计划解决其中的一些问题,不过目前还是 WIP 状态。

VPN 还有一点麻烦的地方是,它会将客户端的所有流量都路由到 VPN,不像 socks5/http 代理那样可以配合 PAC 使用。(当然这也可以通过设置复杂的路由规则解决,不过都是基于 IP 的,而不是域名)。

另外据说 WG 更容易遭到识别,不过以我家的宽带来看,两个主流的科学上网协议都撞了墙,只有 WG 还生龙活虎。

单就个人感受来说,WG 使用起来利大于弊。

6 参考资料