系列文章前情提要:
1.WireGuard系列文章(一):什么是V**[1]
2.WireGuard 系列文章(二):WireGuard 简介 - 快速、现代、安全的 V** 隧道[2]
3.WireGuard 系列文章(三):WireGuard 安装[3]
快速入门
您首先要确保对 概念概述[4] 有很好的掌握,然后 安装 WireGuard[5]。之后,请继续阅读此处。
配置实战
单个配置如下所示:(gif 过大,无法上传,点击链接)
wg(8) 演示gif: https://pic-cdn.ewhisper.cn/img/2021/12/04/7246780de4f1b6408a5ff58d6155eba1-walkthrough.gif
命令行界面
可以通过 添加新接口,该接口应自动处理模块加载:ip-link(8)
# ip link add dev wg0 type wireguard
IP 地址和 peer 可以通过ifconfig(8)
或ip-address(8)
分配
# ip address add dev wg0 192.168.2.1/24
或者,如果总共只有两个 peer ,则可以:
代码语言:javascript复制# ip address add dev wg0 192.168.2.1 peer 192.168.2.2
该接口可以使用随附的 wg(8)
[6] 实用程序配置密钥和对等(peer)端点(endpoint):
# wg setconf wg0 myconfig.conf
或
代码语言:javascript复制# wg set wg0 listen-port 51820 private-key /path/to/private-key peer ABCDEF... allowed-ips 192.168.88.0/24 endpoint 209.202.254.14:8172
最后,可以使用 ifconfig(8)
或 ip-link(8)
激活接口:
# ip link set up dev wg0
还有wg show
和 wg showconf
命令,用于查看当前配置。不带参数的 wg
调用 wg show
默认为对所有 WireGuard 接口进行调用。
wg(8) 工具
wg(8)
[7] 和 ip(8)
的许多例行的启动和拆卸动作都可以通过随附的 wg-quick(8)
工具[8] 实现自动化:
wg-quick(8)工具演示: https://pic-cdn.ewhisper.cn/img/2021/12/04/1e7d824a83ad1dde845cab160d5b205c-wg-quick-tool.gif
密钥生成
WireGuard 需要 base64 编码的公钥和私钥。这些可以使用 wg(8)
[9] 实用程序生成:
umask 077
wg genkey > privatekey
这将在 stdout 上创建包含新私钥 privatekey
的内容。
然后,您可以从私钥派生公钥:
代码语言:javascript复制wg pubkey < privatekey > publickey
这将从 stdin 读取privatekey
并将相应的公钥publickey
写入 stdout。
当然,您可以一次完成所有操作:
代码语言:javascript复制wg genkey | tee privatekey | wg pubkey > publickey
NAT 和防火墙遍历持久性
默认情况下,WireGuard 在不使用时会尝试尽可能保持静默;这不是一个健谈的协议。在大多数情况下,它仅在对等方希望发送数据包时传输数据。当系统未要求它发送数据包时,它会停止发送数据包,直到再次被请求。在大多数配置中,这运行良好。但是,当对等方位于 NAT 或防火墙后面时,它可能希望能够接收传入的数据包,即使它不发送任何数据包。由于 NAT 和有状态防火墙会跟踪"连接",因此,如果 NAT 或防火墙后面的对等方希望接收传入的数据包,他必须通过定期发送保持活动数据包来保持 NAT/防火墙映射有效。这称为持久保持活动( persistent keepalives)。启用此选项后,每隔几秒钟就会向服务器终结点(endpoint)发送一次保持活动状态的数据包。适用于各种防火墙的合理间隔为 25 秒。将其设置为 0 会关闭该功能,这是默认设置,因为大多数用户不需要此功能,并且会使 WireGuard 稍微更健谈。可以通过将字段 PersistentKeepalive =
添加到配置文件中的对等项或在命令行中进行设置 persistent-keepalive
来指定此功能。如果不需要此功能,请不要启用它。但是,如果您位于 NAT 或防火墙后面,并且希望在网络流量静默很久之后接收传入连接,则此选项将使"连接"在 NAT 眼中保持打开状态。
配置详解
WireGuard 使用 INI 语法作为其配置文件格式。配置文件可以放在任何路径下,但必须通过绝对路径引用。默认路径是 /etc/wireguard/wg0.conf
。
配置文件的命名形式必须为 {WireGuard 接口的名称}.conf。通常情况下 WireGuard 接口名称以 wg 为前缀,并从 0 开始编号,但你也可以使用其他名称,只要符合正则表达式 ^[a-zA-Z0-9_= .-]{1,15}就行。
你可以选择使用 wg
命令来手动配置 V**,但一般建议使用 wg-quick
,它提供了更强大和用户友好的配置体验,可以通过配置文件来管理配置。
下面是一个配置文件示例:
代码语言:javascript复制[Interface]
# Name = peer1.private
Address = 10.4.1.3/32
ListenPort = 51820
PrivateKey = thisPeerPrivateKeyXXXXXXXX=
DNS = 223.5.5.5
MTU = 1500
PreUp = echo WireGuard PreUp
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PreDown = echo WireGuard PreDown
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
[Peer]
# Name = peer2.private
AllowedIPs = 10.4.1.1/24
Endpoint = peer1.private:51820
PublicKey = remotePeerPublicKeyXXXX=
PersistentKeepalive = 25
✔️ 实用配置: PostUp 和 PostDown 可以按照上文进行配置:
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
当然,目前的体验最好的实践是傻瓜式地通过 Netmaker 完成所有配置。
[Interface]
这一节定义本地 V** 配置。例如:
•如果本地节点是客户端,只需路由自身的流量,那就只暴露一个 IP(作为客户端嘛,就不需指定端口)。
代码语言:javascript复制[Interface]
# Name = phone.private
Address = 10.4.1.5/32
PrivateKey = <private key for phone.private>
•如果本地节点是中继服务器,它需要将流量转发到其他对等节点(peer),并公开整个 V** 子网的路由。
代码语言:javascript复制[Interface]
# Name = public-server1.example-vpn.tld
Address = 10.4.1.1/24
ListenPort = 51820
PrivateKey = <private key for public-server1.example-vpn.tld>
DNS = 223.5.5.5
Address
定义本地节点应该对哪个地址范围进行路由。
1.如果是常规的客户端,则将其设置为节点本身的单个 IP(使用 CIDR 指定,例如 10.4.1.3/32);
2.如果是中继服务器,则将其设置为可路由的子网范围。
例如:
•常规客户端,只路由自身的流量:Address = 10.4.1.3/32
•中继服务器,可以将流量转发到其他对等节点(peer):Address = 10.4.1.1/24
(注意是 /24
, 即整个子网)
•也可以指定多个子网或 IPv6 子网:Address = 10.4.1.1/24,2001:DB8::/64
ListenPort
当本地节点是中继服务器时,需要通过该参数指定端口来监听传入 V**连接,默认端口号是 51820
。常规客户端(只作为客户端,不作为服务器端)则不需要此选项。
PrivateKey
本地节点的私钥,所有节点(包括中继服务器)都必须设置。不可与其他服务器共用。
DNS
通过 DHCP 向客户端宣告 DNS 服务器。客户端将会使用这里指定的 DNS 服务器来处理 V**子网中的 DNS 请求,但也可以在系统中覆盖此选项。例如:
•如果不配置则使用系统默认 DNS
•可以指定单个 DNS:DNS = 223.5.5.5
•也可以指定多个 DNS:DNS = 223.5.5.5,223.6.6.6
MTU
定义连接到对等节点(peer)的 MTU
(Maximum Transmission Unit,最大传输单元),默认不需要设置,一般由系统自动确定。
PreUp
启动 V** 接口之前运行的命令。这个选项可以指定多次,按顺序执行。
例如:
•添加路由:PreUp = ip rule add ipproto tcp dport 22 table 1234
PostUp
启动 V** 接口之后运行的命令。这个选项可以指定多次,按顺序执行。
例如:
•从文件或某个命令的输出中读取配置值:
代码语言:javascript复制PostUp = wg set %i private-key /etc/wireguard/wg0.key <(some command here)
•添加一行日志到文件中:
代码语言:javascript复制PostUp = echo "$(date %s) WireGuard Started" >> /var/log/wireguard.log
•调用 WebHook:
代码语言:javascript复制PostUp = curl https://events.example.dev/wireguard/started/?key=abcdefg
•添加路由:
代码语言:javascript复制PostUp = ip rule add ipproto tcp dport 22 table 1234
•添加 iptables 规则,启用数据包转发:
代码语言:javascript复制PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
•强制 WireGuard 重新解析对端域名的 IP 地址:
代码语言:javascript复制PostUp = resolvectl domain %i "~."; resolvectl dns %i 10.4.1.1; resolvectl dnssec %i yes
PreDown
停止 V** 接口之前运行的命令。这个选项可以指定多次,按顺序执行。
例如:
•添加一行日志到文件中:
代码语言:javascript复制PreDown = echo "$(date %s) WireGuard Going Down" >> /var/log/wireguard.log
•调用 WebHook:
代码语言:javascript复制PreDown = curl https://events.example.dev/wireguard/stopping/?key=abcdefg
PostDown
停止 V** 接口之后运行的命令。这个选项可以指定多次,按顺序执行。
例如:
•添加一行日志到文件中:
代码语言:javascript复制PostDown = echo "$(date %s) WireGuard Going Down" >> /var/log/wireguard.log
•调用 WebHook:
代码语言:javascript复制PostDown = curl https://events.example.dev/wireguard/stopping/?key=abcdefg
•删除 iptables 规则,关闭数据包转发:
代码语言:javascript复制PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
[Peer]
定义能够为一个或多个地址路由流量的对等节点(peer)的 V** 设置。对等节点(peer)可以是将流量转发到其他对等节点(peer)的中继服务器,也可以是通过公网或内网直连的客户端。
中继服务器必须将所有的客户端定义为对等节点(peer),除了中继服务器之外,其他客户端都不能将位于 NAT 后面的节点定义为对等节点(peer),因为路由不可达。对于那些只为自己路由流量的客户端,只需将中继服务器作为对等节点(peer),以及其他需要直接访问的节点。
举个例子,在下面的配置中,public-server1
作为中继服务器,其他的客户端有的是直连,有的位于 NAT 后面:
•public-server1
(中继服务器)[peer]
: public-server2
, home-server
, laptop
, phone
•public-server2
(直连客户端)[peer]
: public-server1
•home-server
(客户端位于 NAT 后面)[peer]
: public-server1
, public-server2
•laptop
(客户端位于 NAT 后面)[peer]
: public-server1
, public-server2
•phone
(客户端位于 NAT 后面)[peer]
: public-server1
, public-server2
配置示例:
•对等节点(peer)是路由可达的客户端,只为自己路由流量
代码语言:javascript复制[Peer]
# Name = public-server2.private
Endpoint = public-server2.private:51820
PublicKey = <public key for public-server2.private>
AllowedIPs = 10.4.1.2/32
•对等节点(peer)是位于 NAT 后面的客户端,只为自己路由流量
代码语言:javascript复制[Peer]
# Name = home-server.private
Endpoint = home-server.private:51820
PublicKey = <public key for home-server.private>
AllowedIPs = 10.4.1.3/32
•对等节点(peer)是中继服务器,用来将流量转发到其他对等节点(peer)
代码语言:javascript复制[Peer]
# Name = public-server1.example-vpn.tld
Endpoint = public-server1.example-vpn.tld:51820
PublicKey = <public key for public-server1.example-vpn.tld>
# 路由整个 VPN 子网的流量
AllowedIPs = 10.4.1.1/24
PersistentKeepalive = 25
Endpoint
指定远端对等节点(peer)的公网地址。如果对等节点(peer)位于 NAT 后面或者没有稳定的公网访问地址,就忽略这个字段。通常只需要指定中继服务器的 Endpoint
,当然有稳定公网 IP 的节点也可以指定。例如:
•通过 IP 指定:
代码语言:javascript复制Endpoint = 123.123.123.123:51820
•通过域名指定:
代码语言:javascript复制Endpoint = public-server1.private:51820
AllowedIPs
允许该对等节点(peer)发送过来的 V** 流量中的源地址范围。同时这个字段也会作为本机路由表中 wg0 绑定的 IP 地址范围。如果对等节点(peer)是常规的客户端,则将其设置为节点本身的单个 IP;如果对等节点(peer)是中继服务器,则将其设置为可路由的子网范围。可以使用 ,
来指定多个 IP 或子网范围。该字段也可以指定多次。
当决定如何对一个数据包进行路由时,系统首先会选择最具体的路由,如果不匹配再选择更宽泛的路由。例如,对于一个发往 10.4.1.3
的数据包,系统首先会寻找地址为 10.4.1.3/32
的对等节点(peer),如果没有再寻找地址为 10.4.1.1/24
的对等节点(peer),以此类推。
例如:
•对等节点(peer)是常规客户端,只路由自身的流量:
代码语言:javascript复制AllowedIPs = 10.4.1.3/32
•对等节点(peer)是中继服务器,可以将流量转发到其他对等节点(peer):
代码语言:javascript复制AllowedIPs = 10.4.1.1/24
•对等节点(peer)是中继服务器,可以转发所有的流量,包括外网流量和 V** 流量:
代码语言:javascript复制AllowedIPs = 0.0.0.0/0,::/0
•对等节点(peer)是中继服务器,可以路由其自身和其他对等节点(peer)的流量:
代码语言:javascript复制AllowedIPs = 10.4.1.3/32,10.4.1.4/32
•对等节点(peer)是中继服务器,可以路由其自身的流量和它所在的内网的流量:
代码语言:javascript复制AllowedIPs = 10.4.1.3/32,192.168.1.1/24
PublicKey
对等节点(peer)的公钥,所有节点(包括中继服务器)都必须设置。可与其他对等节点(peer)共用同一个公钥。
公钥可通过命令 wg pubkey < example.key > example.key.pub
来生成,其中 example.key
是上面生成的私钥。
例如:PublicKey = somePublicKeyAbcdAbcdAbcdAbcd=
PersistentKeepalive
如果连接是从一个位于 NAT 后面的对等节点(peer)到一个公网可达的对等节点(peer),那么 NAT 后面的对等节点(peer)必须定期发送一个出站 ping 包来检查连通性,如果 IP 有变化,就会自动更新Endpoint
。
例如:
•本地节点与对等节点(peer)可直连:该字段不需要指定,因为不需要连接检查。
•对等节点(peer)位于 NAT 后面:该字段不需要指定,因为维持连接是客户端(连接的发起方)的责任。
•本地节点位于 NAT 后面,对等节点(peer)公网可达:需要指定该字段 PersistentKeepalive = 25
,表示每隔 25
秒发送一次 ping 来检查连接。
参考资料
•Quick Start - WireGuard[10]•WireGuard 教程:WireGuard 的搭建使用与配置详解 by 米开朗基杨[11]
References
[1]
WireGuard系列文章(一):什么是V**: http://ewhisper.cn/posts/32152/
[2]
WireGuard 系列文章(二):WireGuard 简介 - 快速、现代、安全的 V** 隧道: http://ewhisper.cn/posts/23685/
[3]
WireGuard 系列文章(三):WireGuard 安装: http://ewhisper.cn/posts/59274/
[4]
概念概述: https://ewhisper.cn/posts/23685
[5]
安装 WireGuard: https://ewhisper.cn/posts/59274
[6]
wg(8)
: https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8
[7]
wg(8)
: https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8
[8]
wg-quick(8)
工具: https://git.zx2c4.com/wireguard-tools/about/src/man/wg-quick.8
[9]
wg(8)
: https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8
[10]
Quick Start - WireGuard: https://www.wireguard.com/quickstart/
[11]
WireGuard 教程:WireGuard 的搭建使用与配置详解 by 米开朗基杨: https://fuckcloudnative.io/posts/wireguard-docs-practice/