WireGuard
来自 WireGuard 项目主页
- WireGuard 是一个极其简单但快速且现代的 VPN,它利用了最先进的密码学技术。它的目标是比 IPsec 更快、更简单、更精简、更有用,同时避免了大量的麻烦。它旨在比 OpenVPN 具有明显更高的性能。WireGuard 被设计为通用 VPN,可在嵌入式接口和超级计算机上运行,适用于许多不同的情况。最初为 Linux 内核发布,现在它是跨平台的(Windows、macOS、BSD、iOS、Android)并且可以广泛部署。
本文中使用的主要概念的粗略介绍可以在 WireGuard 项目主页上找到。自 2019 年末以来,WireGuard 已包含在 Linux 内核中。
安装
安装 wireguard-tools 软件包以获取用户空间实用程序。
或者,各种网络管理器都提供对 WireGuard 的支持,前提是对等密钥可用。有关详细信息,请参阅 #持久化配置。
图形客户端
- wireguird — 用于 WireGuard 的 Linux GTK GUI 客户端。
命令行工具
- wg_tool — 用于管理服务器和用户 wireguard 配置的工具。
- wg-client — 具有命令行和 GUI 的 Linux 客户端。
- wg2nd — 一种将 WireGuard 配置从 wg-quick(8) 格式转换为与 systemd-networkd 兼容的配置的工具。
用法
以下命令演示了如何在两个或多个对等点之间使用以下设置建立基本隧道
外部(公共)地址 | 内部 IP 地址 | 端口 | ||||
---|---|---|---|---|---|---|
域名 | IPv4 地址 | IPv6 地址 | IPv4 地址 | IPv6 地址 | ||
对等点 A | 198.51.100.101 | 2001:db8:a85b:70a:ffd4:ec1b:4650:a001 | 10.0.0.1/24 | fdc9:281f:04d7:9ee9::1/64 | UDP/51871 | |
对等点 B | peer-b.example | 203.0.113.102 | 2001:db8:40f0:147a:80ad:3e88:f8e9:b002 | 10.0.0.2/24 | fdc9:281f:04d7:9ee9::2/64 | UDP/51902 |
对等点 C | 动态 | 动态 | 10.0.0.3/24 | fdc9:281f:04d7:9ee9::3/64 | UDP/51993 |
外部地址应已存在。例如,如果未阻止 ICMP 回显请求,则对等点 A 应该能够通过其公共 IP 地址 ping 对等点 B,反之亦然。
内部地址将是新地址,可以使用 ip(8) 实用程序或网络管理软件手动创建,这些地址将在新的 WireGuard 网络内部使用。以下示例将使用 10.0.0.0/24 和 fdc9:281f:04d7:9ee9::/64 作为内部网络。IP 地址中的 /24
和 /64
是 CIDR。
密钥生成
为每个对等点创建私钥和公钥。如果连接数十个对等点,可以选择考虑使用个性化密钥对来个性化 Base64 编码的公钥字符串。请参阅 #个性化密钥。
要创建私钥,请运行
$ (umask 0077; wg genkey > peer_A.key)
要创建公钥
$ wg pubkey < peer_A.key > peer_A.pub
或者,一次性完成所有操作
$ wg genkey | (umask 0077 && tee peer_A.key) | wg pubkey > peer_A.pub
还可以生成预共享密钥,以添加额外的对称密钥密码层,混合到已经存在的公钥密码系统中,以实现后量子抗性。应为每个对等点对生成预共享密钥,并且不应重复使用。例如,三个互连的对等点 A、B 和 C 将需要三个单独的预共享密钥,每个对等点对一个。
使用以下命令为每个对等点对生成预共享密钥(确保也为此使用 umask 0077
)
$ wg genpsk > peer_A-peer_B.psk $ wg genpsk > peer_A-peer_C.psk $ wg genpsk > peer_B-peer_C.psk
个性化密钥
目前,WireGuard 不支持注释或将人类可记忆的名称附加到密钥。这使得识别密钥的所有者变得困难,尤其是在使用多个密钥时。一种解决方案是生成包含一些熟悉字符(可能是所有者姓名或主机名的前几个字母等)的公钥,wireguard-vanity-address,或者也可以使用 wicuvanityAUR 来做到这一点。
例如
$ wireguard-vanity-address --in 8 leslie
searching for 'leslie' in pubkey[0..10], one of every 214748364 keys should match one core runs at 2.69e6 keys/s, CPU cores available: 16 est yield: 5.0 seconds per key, 200.10e-3 keys/s hit Ctrl-C to stop private wEoVMj92P+E3fQXVf9IixWJqpCqcnP/4OfvrB1g3zmY= public LEsliEny+aMcWcRbh8Qf414XsQHSBOAFk3TaEk/aSD0= private EAOwlGGqpHVbZ9ehaCspdBJt+lkMcCfkwiA5T5a4JFs= public VlesLiEB5BFd//OD2ILKXviolfz+hodG6uZ+XjoalC8= private UDWG4VWI+RzAGzNSnlC+0X4d3nk9goWPs/NRC5tX524= public 9lESlieIFOlJFV6dG7Omao2WS+amWgshDdBYn8ahRjo=
手动配置
对等点设置
对等点 A 设置
在此示例中,对等点 A 将侦听 UDP 端口 51871,并将接受来自对等点 B 和 C 的连接。
# ip link add dev wg0 type wireguard # ip addr add 10.0.0.1/24 dev wg0 # ip addr add fdc9:281f:04d7:9ee9::1/64 dev wg0 # wg set wg0 listen-port 51871 private-key /path/to/peer_A.key # wg set wg0 peer PEER_B_PUBLIC_KEY preshared-key /path/to/peer_A-peer_B.psk endpoint peer-b.example:51902 allowed-ips 10.0.0.2/32,fdc9:281f:04d7:9ee9::2/128 # wg set wg0 peer PEER_C_PUBLIC_KEY preshared-key /path/to/peer_A-peer_C.psk allowed-ips 10.0.0.3/32,fdc9:281f:04d7:9ee9::3/128 # ip link set wg0 up
PEER_X_PUBLIC_KEY
应该是 peer_X.pub
的内容。
关键字 allowed-ips
是将路由到对等点的地址列表。请务必至少指定一个包含 WireGuard 连接的内部 IP 地址的地址范围。
对等点 B 设置
# ip link add dev wg0 type wireguard # ip addr add 10.0.0.2/24 dev wg0 # ip addr add fdc9:281f:04d7:9ee9::2/64 dev wg0 # wg set wg0 listen-port 51902 private-key /path/to/peer_B.key # wg set wg0 peer PEER_A_PUBLIC_KEY preshared-key /path/to/peer_A-peer_B.psk endpoint 198.51.100.101:51871 allowed-ips 10.0.0.1/32,fdc9:281f:04d7:9ee9::1/128 # wg set wg0 peer PEER_C_PUBLIC_KEY preshared-key /path/to/peer_B-peer_C.psk allowed-ips 10.0.0.3/32,fdc9:281f:04d7:9ee9::3/128 # ip link set wg0 up
对等点 C 设置
# ip link add dev wg0 type wireguard # ip addr add 10.0.0.3/24 dev wg0 # ip addr add fdc9:281f:04d7:9ee9::3/64 dev wg0 # wg set wg0 listen-port 51993 private-key /path/to/peer_C.key # wg set wg0 peer PEER_A_PUBLIC_KEY preshared-key /path/to/peer_A-peer_C.psk endpoint 198.51.100.101:51871 allowed-ips 10.0.0.1/32,fdc9:281f:04d7:9ee9::1/128 # wg set wg0 peer PEER_B_PUBLIC_KEY preshared-key /path/to/peer_B-peer_C.psk endpoint peer-b.example:51902 allowed-ips 10.0.0.2/32,fdc9:281f:04d7:9ee9::2/128 # ip link set wg0 up
附加路由
要建立比点对点更复杂的连接,需要进行额外的设置。
点对站点
要访问对等点的网络,请在应能够连接到它的对等点的配置中的 allowed-ips
中指定网络子网。例如 allowed-ips 10.0.0.2/32,fdc9:281f:04d7:9ee9::2/128,192.168.35.0/24,fd7b:d0bd:7a6e::/64
。
确保还使用 ip-route(8) 设置 路由表。例如
# ip route add 192.168.35.0/24 dev wg0 # ip route add fd7b:d0bd:7a6e::/64 dev wg0
站点对点
如果目的是将设备连接到具有 WireGuard 对等点的网络,请在每个设备上设置路由,以便它们知道可以通过该设备访问对等点。
之后,在网络中的其他设备将通过其连接到 WireGuard 对等点的对等点上启用 IP 转发。
站点对站点
要连接两个(或多个)网络,请在所有站点上应用 #点对站点 和 #站点对点。
通过 WireGuard 路由所有流量
要通过对等点路由所有流量,请将 AllowedIPs 设置为所有已知的 IP 地址,即 "AllowedIPs = 0.0.0.0/0, ::0"
在一个简单的 wg-quick 配置中,它看起来像这样
对等点 B 设置
/etc/wireguard/wg0.conf
[Interface] Address = 10.0.0.2/24, fdc9:281f:04d7:9ee9::2/64 PrivateKey = DEADBEEF DNS = 10.0.0.12 [Peer] PublicKey = PEER_C_PUBLIC_KEY AllowedIPs = 0.0.0.0/0, ::/0 Endpoint = 10.1.2.3:52180
更多解释和一些 python 代码来计算如何排除范围可以在这里找到。[2]
DNS
要使用对等点作为 DNS 服务器,请将其 WireGuard 隧道 IP 地址添加到 /etc/resolv.conf。例如,要使用对等点 B 作为 DNS 服务器
/etc/resolv.conf
nameserver fdc9:281f:04d7:9ee9::2 nameserver 10.0.0.2
基本检查
不带参数调用 wg(8) 命令将快速概述当前配置。
例如,当对等点 A 已配置时,我们能够看到其身份及其关联的对等点
# wg
interface: wg0 public key: UguPyBThx/+xMXeTbRYkKlP0Wh/QZT3vTLPOVaaXTD8= private key: (hidden) listening port: 51871 peer: 9jalV3EEBnVXahro0pRMQ+cHlmjE33Slo9tddzCVtCw= endpoint: 203.0.113.102:51902 allowed ips: 10.0.0.2/32, fdc9:281f:04d7:9ee9::2 peer: 2RzKFbGMx5g7fG0BrWCI7JIpGvcwGkqUaCoENYueJw4= endpoint: 192.0.2.103:51993 allowed ips: 10.0.0.3/32, fdc9:281f:04d7:9ee9::3
此时,可以到达隧道的终点。如果对等点不阻止 ICMP 回显请求,请尝试 ping 对等点以测试它们之间的连接。
使用 ICMPv4
$ ping 10.0.0.2
使用 ICMPv6
$ ping fdc9:281f:04d7:9ee9::2
在对等点之间传输一些数据后,wg
实用程序将显示其他信息
# wg
interface: wg0 public key: UguPyBThx/+xMXeTbRYkKlP0Wh/QZT3vTLPOVaaXTD8= private key: (hidden) listening port: 51871 peer: 9jalV3EEBnVXahro0pRMQ+cHlmjE33Slo9tddzCVtCw= endpoint: 203.0.113.102:51902 allowed ips: 10.0.0.2/32, fdc9:281f:04d7:9ee9::2 latest handshake: 5 seconds ago transfer: 1.24 KiB received, 1.38 KiB sent peer: 2RzKFbGMx5g7fG0BrWCI7JIpGvcwGkqUaCoENYueJw4= allowed ips: 10.0.0.3/32, fdc9:281f:04d7:9ee9::3
持久化配置
可以使用 wg-quick@.service
实现持久化配置,该服务随 wireguard-tools 提供,或者使用网络管理器。支持 WireGuard 的网络管理器是 systemd-networkd、netctl[3]、NetworkManager 和 ConnMan[4]。
- netctl 依赖于 wg(8)(来自 wireguard-tools)和
/etc/wireguard/interfacename.conf
配置文件来建立 WireGuard 连接。 - ConnMan 对 WireGuard 的支持非常有限。它只能连接到一个对等点。[5]
wg-quick
wg-quick(8) 使用来自 /etc/wireguard/interfacename.conf
的配置文件配置 WireGuard 隧道。
可以通过使用 wg(8) 实用程序的 showconf
命令来保存当前的 WireGuard 配置。例如
# wg showconf wg0 > /etc/wireguard/wg0.conf
要使用配置文件启动隧道,请使用
# wg-quick up interfacename
或使用 systemd 服务—wg-quick@interfacename.service
。要在启动时启动隧道,启用该单元。
- 使用 wg-quick 配置 WireGuard 接口的用户应确保没有其他 网络管理 软件尝试管理它。要使用 NetworkManager 并且不使用它配置 WireGuard 接口,请参阅 #路由周期性重置。
- wg-quick 向配置文件格式添加了其他配置选项,从而使其与 wg(8) § 配置文件格式 不兼容。有关相关配置值,请参阅 wg-quick(8) § 配置 手册页。可以使用
wg-quick strip
生成与 wg 兼容的配置文件。 - wg-quick 没有提供指示 resolvconf 将 WireGuard 接口设置为私有的方法。即使指定了搜索域,来自系统的所有 DNS 查询(而不仅仅是那些与搜索域匹配的查询)都将发送到 WireGuard 配置中设置的 DNS 服务器。
对等点 A 设置
/etc/wireguard/wg0.conf
[Interface] Address = 10.0.0.1/24, fdc9:281f:04d7:9ee9::1/64 ListenPort = 51871 PrivateKey = PEER_A_PRIVATE_KEY [Peer] PublicKey = PEER_B_PUBLIC_KEY PresharedKey = PEER_A-PEER_B-PRESHARED_KEY AllowedIPs = 10.0.0.2/32, fdc9:281f:04d7:9ee9::2/128 Endpoint = peer-b.example:51902 [Peer] PublicKey = PEER_C_PUBLIC_KEY PresharedKey = PEER_A-PEER_C-PRESHARED_KEY AllowedIPs = 10.0.0.3/32, fdc9:281f:04d7:9ee9::3/128
- 要通过隧道将所有流量路由到特定对等点,请将默认路由 (
0.0.0.0/0
用于 IPv4,::/0
用于 IPv6) 添加到AllowedIPs
。例如AllowedIPs = 0.0.0.0/0, ::/0
。wg-quick 将自动处理设置正确的路由和 fwmark[6],以便网络仍然可以正常工作。 - 要使用对等点作为 DNS 服务器,请在
[Interface]
部分中设置DNS = wireguard_internal_ip_address_of_peer
。搜索域也可以使用DNS =
选项设置。用逗号分隔列表中的所有值。
对等点 B 设置
/etc/wireguard/wg0.conf
[Interface] Address = 10.0.0.2/24, fdc9:281f:04d7:9ee9::2/64 ListenPort = 51902 PrivateKey = PEER_B_PRIVATE_KEY [Peer] PublicKey = PEER_A_PUBLIC_KEY PresharedKey = PEER_A-PEER_B-PRESHARED_KEY AllowedIPs = 10.0.0.1/32, fdc9:281f:04d7:9ee9::1/128 Endpoint = 198.51.100.101:51871 [Peer] PublicKey = PEER_C_PUBLIC_KEY PresharedKey = PEER_B-PEER_C-PRESHARED_KEY AllowedIPs = 10.0.0.3/32, fdc9:281f:04d7:9ee9::3/128
对等点 C 设置
/etc/wireguard/wg0.conf
[Interface] Address = 10.0.0.3/24, fdc9:281f:04d7:9ee9::3/64 ListenPort = 51993 PrivateKey = PEER_C_PRIVATE_KEY [Peer] PublicKey = PEER_A_PUBLIC_KEY PresharedKey = PEER_A-PEER_C-PRESHARED_KEY AllowedIPs = 10.0.0.1/32, fdc9:281f:04d7:9ee9::1/128 Endpoint = 198.51.100.101:51871 [Peer] PublicKey = PEER_B_PUBLIC_KEY PresharedKey = PEER_B-PEER_C-PRESHARED_KEY AllowedIPs = 10.0.0.2/32, fdc9:281f:04d7:9ee9::2/128 Endpoint = peer-b.example:51902
systemd-networkd
systemd-networkd 原生支持设置 WireGuard 接口。systemd.netdev(5) § 示例 手册页中提供了一个示例。
Domains=~.
) 将阻止端点的 DNS 解析。除非对等域被配置为在特定的网络链接上解析。对等点 A 设置
/etc/systemd/network/99-wg0.netdev
[NetDev] Name=wg0 Kind=wireguard Description=WireGuard tunnel wg0 [WireGuard] ListenPort=51871 PrivateKey=PEER_A_PRIVATE_KEY [WireGuardPeer] PublicKey=PEER_B_PUBLIC_KEY PresharedKey=PEER_A-PEER_B-PRESHARED_KEY AllowedIPs=10.0.0.2/32 AllowedIPs=fdc9:281f:04d7:9ee9::2/128 Endpoint=peer-b.example:51902 [WireGuardPeer] PublicKey=PEER_C_PUBLIC_KEY PresharedKey=PEER_A-PEER_C-PRESHARED_KEY AllowedIPs=10.0.0.3/32 AllowedIPs=fdc9:281f:04d7:9ee9::3/128
/etc/systemd/network/99-wg0.network
[Match] Name=wg0 [Network] Address=10.0.0.1/24 Address=fdc9:281f:04d7:9ee9::1/64
- 要使用对等点作为 DNS 服务器,请使用
DNS=
选项在 .network 文件中指定其 WireGuard 隧道的 IP 地址。对于搜索域,请使用Domains=
选项。有关详细信息,请参阅 systemd.network(5) § [NETWORK] 部分选项。 - 要使用对等点作为唯一 DNS 服务器,请在 .network 文件的
[Network]
部分中设置DNSDefaultRoute=true
和Domains=~
。 - 要路由其他子网,请将它们作为
[Route]
部分添加到 .network 文件中。例如
/etc/systemd/network/99-wg0.network
... [Route] Destination=192.168.35.0/24 Scope=link [Route] Destination=fd7b:d0bd:7a6e::/64 Scope=link
# chown root:systemd-network /etc/systemd/network/99-wg*.netdev # chmod 0640 /etc/systemd/network/99-wg*.netdev
对等点 B 设置
/etc/systemd/network/99-wg0.netdev
[NetDev] Name=wg0 Kind=wireguard Description=WireGuard tunnel wg0 [WireGuard] ListenPort=51902 PrivateKey=PEER_B_PRIVATE_KEY [WireGuardPeer] PublicKey=PEER_A_PUBLIC_KEY PresharedKey=PEER_A-PEER_B-PRESHARED_KEY AllowedIPs=10.0.0.1/32 AllowedIPs=fdc9:281f:04d7:9ee9::1/128 Endpoint=198.51.100.101:51871 [WireGuardPeer] PublicKey=PEER_C_PUBLIC_KEY PresharedKey=PEER_B-PEER_C-PRESHARED_KEY AllowedIPs=10.0.0.3/32 AllowedIPs=fdc9:281f:04d7:9ee9::3/128
/etc/systemd/network/99-wg0.network
[Match] Name=wg0 [Network] Address=10.0.0.2/24 Address=fdc9:281f:04d7:9ee9::2/64
对等点 C 设置
/etc/systemd/network/99-wg0.netdev
[NetDev] Name=wg0 Kind=wireguard Description=WireGuard tunnel wg0 [WireGuard] ListenPort=51993 PrivateKey=PEER_C_PRIVATE_KEY [WireGuardPeer] PublicKey=PEER_A_PUBLIC_KEY PresharedKey=PEER_A-PEER_C-PRESHARED_KEY AllowedIPs=10.0.0.1/32 AllowedIPs=fdc9:281f:04d7:9ee9::1/128 Endpoint=198.51.100.101:51871 [WireGuardPeer] PublicKey=PEER_B_PUBLIC_KEY PresharedKey=PEER_B-PEER_C-PRESHARED_KEY AllowedIPs=10.0.0.2/32 AllowedIPs=fdc9:281f:04d7:9ee9::2/128 Endpoint=peer-b.example:51902
/etc/systemd/network/99-wg0.network
[Match] Name=wg0 [Network] Address=10.0.0.3/24 Address=fdc9:281f:04d7:9ee9::3/64
systemd-networkd:通过 WireGuard 路由所有流量
在此示例中,对等点 B 连接到具有公共 IP 地址的对等点 A。对等点 B 通过 WireGuard 隧道路由其所有流量,并使用对等点 A 处理 DNS 请求。
对等点 A 设置
/etc/systemd/network/99-wg0.netdev
[NetDev] Name=wg0 Kind=wireguard Description=WireGuard tunnel wg0 [WireGuard] ListenPort=51871 PrivateKey=PEER_A_PRIVATE_KEY [WireGuardPeer] PublicKey=PEER_B_PUBLIC_KEY PresharedKey=PEER_A-PEER_B-PRESHARED_KEY AllowedIPs=10.0.0.2/32
/etc/systemd/network/99-wg0.network
[Match] Name=wg0 [Network] Address=10.0.0.1/24
假定使用 ufw,但 iptables 可以通过使用 服务器配置 部分中概述的规则来执行相同的操作
$ ufw route allow in on wg0 out on enp5s0
/etc/ufw/before.rules
*nat :POSTROUTING ACCEPT [0:0] -A POSTROUTING -s 10.0.0.0/24 -o enp5s0 -j MASQUERADE COMMIT
对等点 B 设置
/etc/systemd/network/99-wg0.netdev
[NetDev] Name=wg0 Kind=wireguard Description=WireGuard tunnel wg0 [WireGuard] ListenPort=51902 PrivateKey=PEER_B_PRIVATE_KEY FirewallMark=0x8888 [WireGuardPeer] PublicKey=PEER_A_PUBLIC_KEY PresharedKey=PEER_A-PEER_B-PRESHARED_KEY AllowedIPs=0.0.0.0/0 Endpoint=198.51.100.101:51871
/etc/systemd/network/50-wg0.network
[Match] Name=wg0 [Network] Address=10.0.0.2/24 DNS=10.0.0.1 DNSDefaultRoute=true Domains=~. [RoutingPolicyRule] FirewallMark=0x8888 InvertRule=true Table=1000 Priority=10 # Exempt the endpoint IP address so that wireguard can still connect to it. [RoutingPolicyRule] To=198.51.100.101/32 Priority=5 [Route] Destination=0.0.0.0/0 Table=1000
豁免特定地址
为了免除特定地址(例如专用 LAN 地址)通过 WireGuard 隧道路由,请将它们添加到另一个优先级更高的 RoutingPolicyRule。
/etc/systemd/network/50-wg0.network
... [RoutingPolicyRule] To=192.168.0.0/24 Priority=9 ...
特定用户的路由
可能需要仅为特定用户(例如 transmission 用户)通过隧道路由 WAN 流量,以便将隧道用于 torrent 流量。
/etc/systemd/network/99-wg0.network
... [RoutingPolicyRule] Table=8677 User=transmission Priority=30001 Family=both [RoutingPolicyRule] Table=main User=transmission SuppressPrefixLength=0 Priority=30000 Family=both ...
/etc/systemd/network/99-wg0.netdev
... [WireGuard] PrivateKey='PEER_PRIVATE_KEY' RouteTable=8677 ...
Netctl
Netctl 原生支持设置 WireGuard 接口。一组典型的 WireGuard netctl 配置文件如下所示
对等点 A 设置
/etc/netctl/wg0
Description="WireGuard tunnel on peer A" Interface=wg0 Connection=wireguard WGConfigFile=/etc/wireguard/wg0.conf IP=static Address=('10.0.0.1/24')
/etc/wireguard/wg0.conf
[Interface] ListenPort = 51871 PrivateKey = PEER_A_PRIVATE_KEY [Peer] PublicKey = PEER_B_PUBLIC_KEY AllowedIPs = 10.0.0.2/32 Endpoint = peer-b.example:51902 [Peer] PublicKey = PEER_C_PUBLIC_KEY AllowedIPs = 10.0.0.3/32
对等点 B 设置
/etc/netctl/wg0
Description="WireGuard tunnel on peer B" Interface=wg0 Connection=wireguard WGConfigFile=/etc/wireguard/wg0.conf IP=static Address=('10.0.0.2/24')
/etc/wireguard/wg0.conf
[Interface] ListenPort = 51902 PrivateKey = PEER_B_PRIVATE_KEY [Peer] PublicKey = PEER_A_PUBLIC_KEY AllowedIPs = 10.0.0.1/32 Endpoint = peer-a.example:51871 [Peer] PublicKey = PEER_C_PUBLIC_KEY AllowedIPs = 10.0.0.3/32
对等点 C 设置
/etc/netctl/wg0
Description="WireGuard tunnel on peer C" Interface=wg0 Connection=wireguard WGConfigFile=/etc/wireguard/wg0.conf IP=static Address=('10.0.0.3/24')
/etc/wireguard/wg0.conf
[Interface] ListenPort = 51993 PrivateKey = PEER_C_PRIVATE_KEY [Peer] PublicKey = PEER_A_PUBLIC_KEY AllowedIPs = 10.0.0.1/32 Endpoint = peer-a.example:51871 [Peer] PublicKey = PEER_B_PUBLIC_KEY AllowedIPs = 10.0.0.2/32 Endpoint = peer-b.example:51902
然后根据需要在每个参与的对等点上启动和/或启用 wg0 接口,即
# netctl start wg0
要使用 WireGuard 和 Netctl 实现持久化的站点到对等点、对等点到站点或站点到站点类型的连接,只需将适当的 Routes=
行添加到 netctl 配置文件中,并将此网络添加到 WireGuard 配置文件中的 AllowedIPs
,例如 /etc/netctl/wg0
中的 Routes=('192.168.10.0/24 dev wg0')
和 /etc/wireguard/wg0.conf
中的 AllowedIPs=10.0.0.1/32, 192.168.10.0/24
,然后不要忘记启用 IP 转发。
NetworkManager
NetworkManager 原生支持设置 WireGuard 接口。有关 NetworkManager 中 WireGuard 用法的所有详细信息,请阅读 Thomas Haller 的博客文章—NetworkManager 中的 WireGuard。
# nmcli connection import type wireguard file /etc/wireguard/wg0.conf
以下示例通过密钥文件格式 .nmconnection 文件配置 WireGuard。有关语法和可用选项的说明,请参阅 nm-settings-keyfile(5) 和 nm-settings(5)。
对等点 A 设置
/etc/NetworkManager/system-connections/wg0.nmconnection
[connection] id=wg0 type=wireguard interface-name=wg0 [wireguard] listen-port=51871 private-key=PEER_A_PRIVATE_KEY private-key-flags=0 [wireguard-peer.PEER_B_PUBLIC_KEY] endpoint=peer-b.example:51902 preshared-key=PEER_A-PEER_B-PRESHARED_KEY preshared-key-flags=0 allowed-ips=10.0.0.2/32;fdc9:281f:04d7:9ee9::2/128; [wireguard-peer.PEER_C_PUBLIC_KEY] preshared-key=PEER_A-PEER_C-PRESHARED_KEY preshared-key-flags=0 allowed-ips=10.0.0.3/32;fdc9:281f:04d7:9ee9::3/128; [ipv4] address1=10.0.0.1/24 method=manual [ipv6] address1=fdc9:281f:04d7:9ee9::1/64 method=manual
- 要通过隧道将所有流量路由到特定对等点,请将默认路由 (
0.0.0.0/0
用于 IPv4,::/0
用于 IPv6) 添加到wireguard-peer.PEER_X_PUBLIC_KEY.allowed-ips
。例如wireguard-peer.PEER_B_PUBLIC_KEY.allowed-ips=0.0.0.0/0;::/0;
。自 NetworkManager 1.20.0 起,WireGuard 连接支持默认路由的特殊处理。 - 要使用对等点作为 DNS 服务器,请使用
ipv4.dns
和ipv6.dns
设置指定其 WireGuard 隧道的 IP 地址。搜索域可以使用ipv4.dns-search=
和ipv6.dns-search=
选项指定。有关更多详细信息,请参阅 nm-settings(5)。例如,使用密钥文件格式
... [ipv4] ... dns=10.0.0.2; dns-search=corp; ... [ipv6] ... dns=fdc9:281f:04d7:9ee9::2; dns-search=corp; ...
要使用对等点作为唯一 DNS 服务器,请设置负 DNS 优先级(例如 dns-priority=-1
)并将 ~.
添加到 dns-search=
设置。
对等点 B 设置
/etc/NetworkManager/system-connections/wg0.nmconnection
[connection] id=wg0 type=wireguard interface-name=wg0 [wireguard] listen-port=51902 private-key=PEER_B_PRIVATE_KEY private-key-flags=0 [wireguard-peer.PEER_A_PUBLIC_KEY] endpoint=198.51.100.101:51871 preshared-key=PEER_A-PEER_B-PRESHARED_KEY preshared-key-flags=0 allowed-ips=10.0.0.1/32;fdc9:281f:04d7:9ee9::1/128; [wireguard-peer.PEER_C_PUBLIC_KEY] preshared-key=PEER_B-PEER_C-PRESHARED_KEY preshared-key-flags=0 allowed-ips=10.0.0.3/32;fdc9:281f:04d7:9ee9::3/128; [ipv4] address1=10.0.0.2/24 method=manual [ipv6] address1=fdc9:281f:04d7:9ee9::2/64 method=manual
对等点 C 设置
/etc/NetworkManager/system-connections/wg0.nmconnection
[connection] id=wg0 type=wireguard interface-name=wg0 [wireguard] listen-port=51993 private-key=PEER_C_PRIVATE_KEY private-key-flags=0 [wireguard-peer.PEER_A_PUBLIC_KEY] endpoint=198.51.100.101:51871 preshared-key=PEER_A-PEER_C-PRESHARED_KEY preshared-key-flags=0 allowed-ips=10.0.0.1/32;fdc9:281f:04d7:9ee9::1/128; [wireguard-peer.PEER_B_PUBLIC_KEY] endpoint=peer-b.example:51902 preshared-key=PEER_B-PEER_C-PRESHARED_KEY preshared-key-flags=0 allowed-ips=10.0.0.2/32;fdc9:281f:04d7:9ee9::2/128; [ipv4] address1=10.0.0.3/24 method=manual [ipv6] address1=fdc9:281f:04d7:9ee9::3/64 method=manual
特定用例:VPN 服务器
本节的目的是设置 WireGuard “服务器”和通用“客户端”,以实现通过加密和安全隧道访问服务器/网络资源,如 OpenVPN 和其他。 “服务器”在 Linux 上运行,“客户端”可以在任意数量的平台上运行(WireGuard 项目在 iOS 和 Android 平台上以及 Linux、Windows 和 MacOS 上提供应用程序)。有关更多信息,请参阅官方项目安装链接。
服务器
在将充当“服务器”的对等点上,首先启用 IPv4 转发。
如果服务器配置了公共 IP,请务必
- 允许在 WireGuard 将运行的指定端口(例如,允许
51820/UDP
上的流量)上的 UDP 流量。 - 如果防火墙的转发策略未包含在接口本身的 WireGuard 配置
/etc/wireguard/wg0.conf
中,请设置转发策略。下面的示例应具有 iptables 规则并按原样工作。
如果服务器位于 NAT 之后,请务必将 WireGuard 将运行的指定端口(例如,51820/UDP
)从路由器转发到 WireGuard 服务器。
密钥生成
按照 #密钥生成 中的说明,为服务器和每个客户端生成密钥对。
服务器配置
创建“服务器”配置文件
/etc/wireguard/wg0.conf
[Interface] Address = 10.200.200.1/24 ListenPort = 51820 PrivateKey = SERVER_PRIVATE_KEY # substitute eth0 in the following lines to match the Internet-facing interface # the FORWARD rules will always be needed since traffic needs to be forwarded between the WireGuard # interface and the other interfaces on the server. # if the server is behind a router and receives traffic via NAT, specify static routing back to the # 10.200.200.0/24 subnet, the NAT iptables rules are not needed but the FORWARD rules are needed. # if the server is behind a router and receives traffic via NAT but one cannot specify static routing back to # 10.200.200.0/24 subnet, both the NAT and FORWARD iptables rules are needed. 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 [Peer] # foo PublicKey = PEER_FOO_PUBLIC_KEY PresharedKey = PRE-SHARED_KEY AllowedIPs = 10.200.200.2/32 [Peer] # bar PublicKey = PEER_BAR_PUBLIC_KEY PresharedKey = PRE-SHARED_KEY AllowedIPs = 10.200.200.3/32
可以根据需要在同一格式中列出其他对等点(“客户端”)。每个对等点都需要设置 PublicKey
。但是,指定 PresharedKey
是可选的。
请注意,Address
的网络掩码为 /24
,而 AllowedIPs
上的客户端为 /32
。客户端仅使用其 IP,服务器仅发回其各自的地址。
可以使用 wg-quick(8) 手动管理接口,或者使用通过 systemctl(1) 管理的 systemd 服务。
可以使用 wg-quick up wg0
分别通过 启动 以及可能通过 wg-quick@interface.service
启用 接口来启动接口,例如 wg-quick@wg0.service
。要关闭接口,请使用 wg-quick down wg0
分别 停止 wg-quick@interface.service
。
客户端配置
创建相应的“客户端”配置文件
foo.conf
[Interface] Address = 10.200.200.2/32 PrivateKey = PEER_FOO_PRIVATE_KEY DNS = 10.200.200.1 [Peer] PublicKey = SERVER_PUBLICKEY PresharedKey = PRE-SHARED_KEY Endpoint = my.ddns.example.com:51820 AllowedIPs = 0.0.0.0/0, ::/0
bar.conf
[Interface] Address = 10.200.200.3/32 PrivateKey = PEER_BAR_PRIVATE_KEY DNS = 10.200.200.1 [Peer] PublicKey = SERVER_PUBLICKEY PresharedKey = PRE-SHARED KEY Endpoint = my.ddns.example.com:51820 AllowedIPs = 0.0.0.0/0, ::/0
使用全捕获 AllowedIPs = 0.0.0.0/0, ::/0
将通过 VPN 转发所有 IPv4 (0.0.0.0/0
) 和 IPv6 (::/0
) 流量。
NetworkManager-wait-online.service
,systemd-networkd 的用户可能需要启用 systemd-networkd-wait-online.service
以等待设备准备好联网,然后再尝试 WireGuard 连接。测试隧道
一旦隧道建立,就可以使用 netcat 通过隧道发送流量,以测试吞吐量、CPU 使用率等。在隧道的一端,以监听模式运行 nc
,在另一端,将来自 /dev/zero
的一些数据通过管道输送到发送模式的 nc
中。
在下面的示例中,端口 2222 用于流量传输(如果使用防火墙,请确保允许端口 2222 上的流量)。
在隧道的一端监听流量
$ nc -vvlnp 2222
在隧道的另一端发送一些流量
$ dd if=/dev/zero bs=1024K count=1024 | nc -v 10.0.0.203 2222
可以使用 wg
直接监控状态。
# wg
interface: wg0 public key: UguPyBThx/+xMXeTbRYkKlP0Wh/QZT3vTLPOVaaXTD8= private key: (hidden) listening port: 51820 peer: 9jalV3EEBnVXahro0pRMQ+cHlmjE33Slo9tddzCVtCw= preshared key: (hidden) endpoint: 192.168.1.216:53207 allowed ips: 10.0.0.0/0 latest handshake: 1 minutes, 17 seconds ago transfer: 56.43 GiB received, 1.06 TiB sent
提示与技巧
以加密形式存储私钥 (wg-quick)
可能需要以加密形式存储私钥,例如通过使用 pass。只需将 WireGuard 配置文件中 [Interface]
下的 PrivateKey
行替换为
PostUp = wg set %i private-key <(su user -c "export PASSWORD_STORE_DIR=/path/to/your/store/; pass WireGuard/private-keys/%i")
其中 *user* 是感兴趣的 Linux 用户名。有关更多详细信息,请参阅 wg-quick(8) 手册页。
或者,可以使用 systemd-creds。这对于创建绑定到系统 TPM 的加密私钥非常有用。有关更多详细信息,请参阅 systemd-creds(1)。
首先,创建一个加密凭证
# echo -n your_wg_private_key | systemd-creds --tpm2-device=auto encrypt - /etc/credstore.encrypted/wg-private-key.cred
最后,将 WireGuard 配置文件中 [Interface]
下的 PrivateKey
行替换为
PostUp = wg set %i private-key <(systemd-creds decrypt /etc/credstore.encrypted/wg-private-key.cred)
使用 systemd 凭证存储私钥 (systemd-networkd)
您可以使用 systemd-creds 以加密方式存储您的私钥。
# echo -n your_wg_private_key | systemd-creds encrypt - /etc/credstore.encrypted/network.wireguard.private.wg0 # echo -n your_pre_shared_key | systemd-creds encrypt - /etc/credstore.encrypted/network.wireguard.psk.wg0
修改您的 *.netdev* 文件以使用
PrivateKey = @network.wireguard.private.wg0 PresharedKey = @network.wireguard.psk.wg0
IP 地址会变化的端点
在解析服务器域名后,WireGuard 将不再检查 DNS 的更改。
如果 WireGuard 服务器由于 DHCP、Dyndns、IPv6 等原因频繁更改其 IP 地址,则任何 WireGuard 客户端都将失去连接,直到通过类似 `wg set "$INTERFACE" peer "$PUBLIC_KEY" endpoint "$ENDPOINT"` 的命令更新其端点为止。
另请注意,如果端点地址将要更改(例如,当迁移到新的提供商/数据中心时),仅更新 DNS 是不够的,因此在任何基于 DNS 的设置上定期运行 reresolve-dns 可能会有意义。
幸运的是,wireguard-tools 提供了一个示例脚本 `/usr/share/wireguard-tools/examples/reresolve-dns/reresolve-dns.sh`,该脚本解析 WG 配置文件并自动重置端点地址。
需要定期运行 `/usr/share/wireguard-tools/examples/reresolve-dns/reresolve-dns.sh /etc/wireguard/wg.conf`,以从已更改 IP 的端点恢复。
一种方法是通过 systemd 计时器每三十秒更新所有 WireGuard 端点一次[7]
/etc/systemd/system/wireguard_reresolve-dns.timer
[Unit] Description=Periodically reresolve DNS of all WireGuard endpoints [Timer] OnCalendar=*:*:0/30 [Install] WantedBy=timers.target
/etc/systemd/system/wireguard_reresolve-dns.service
[Unit] Description=Reresolve DNS of all WireGuard endpoints Wants=network-online.target After=network-online.target [Service] Type=oneshot ExecStart=/bin/sh -c 'for i in /etc/wireguard/*.conf; do /usr/share/wireguard-tools/examples/reresolve-dns/reresolve-dns.sh "$i"; done'
之后 启用 并 启动 `wireguard_reresolve-dns.timer`
生成二维码
如果客户端是手机等移动设备,则可以使用 qrencode 生成客户端的配置二维码并在终端中显示它
$ qrencode -t ansiutf8 -r client.conf
启用调试日志
当在支持动态调试的内核上使用 Linux 内核模块时,可以通过运行以下命令将调试信息写入内核环缓冲区(可以使用 dmesg 和 journalctl 查看)
# modprobe wireguard # echo module wireguard +p > /sys/kernel/debug/dynamic_debug/control
重新加载对端(服务器)配置
如果 WireGuard 对端(主要是服务器)在其配置中添加或删除了其他对端,并希望在不停止任何活动会话的情况下重新加载配置,则可以执行以下命令来完成此操作
# wg syncconf ${WGNET} <(wg-quick strip ${WGNET})
其中 `$WGNET` 是 WireGuard 接口名称或配置基本名称,例如 `wg0`(对于服务器)或 `client`(对于客户端,不带 *.conf* 扩展名)。
`wg-quick@.service` 的用户可以直接 重新加载 该服务。
针对某些公共 Wi-Fi 网络似乎阻止 WireGuard 连接的解决方法
某些 Wi-Fi 网络可以配置为主动识别和阻止 WireGuard 的握手,从而阻止初始连接并阻止安全隧道的建立。
此策略适用于阻止 *新的* WireGuard 连接,但对于 *现有* 连接无效。因此,要在这样的网络上使用 WireGuard,只需在加入 Wi-Fi 网络之前通过蜂窝网络连接到 WireGuard 对端,从而允许在主动阻止发生之前进行握手。当设备从蜂窝网络过渡到 Wi-Fi 时,WireGuard 将保持此隧道打开。
故障排除
路由定期重置
NetworkManager 的用户应确保它 未管理 WireGuard 接口。例如,创建以下配置文件
/etc/NetworkManager/conf.d/unmanaged.conf
[keyfile] unmanaged-devices=type:wireguard
DNS 解析失败
当通过 WireGuard 接口隧道传输所有流量时,连接可能会在一段时间后或建立新连接时看似丢失。这可能是由于 网络管理器 或 DHCP 客户端覆盖了 `/etc/resolv.conf` 造成的。
默认情况下,*wg-quick* 使用 *resolvconf* 注册新的 DNS 条目(来自配置文件中的 `DNS` 关键字)。这会给不使用 *resolvconf* 的 网络管理器 和 DHCP 客户端带来问题,因为它们会覆盖 `/etc/resolv.conf`,从而删除 wg-quick 添加的 DNS 服务器。
解决方案是使用支持 resolvconf 的网络软件。
NetworkManager 的用户应该知道它默认不使用 resolvconf。建议使用 systemd-resolved。如果这是不可取的,请 安装 openresolv 并配置 NetworkManager 以使用它:NetworkManager#使用 openresolv。
调整 MTU 值
Wireguard 默认的最大传输单元 (MTU) 值为 `1420`。
由于 MTU 值过低(低于 `1280`),wg-quick 可能无法创建 WireGuard 接口。这可以通过在客户端 WireGuard 配置文件的 Interface 部分中设置 MTU 值来解决。
foo.config
[Interface] Address = 10.200.200.2/24 MTU = 1420 PrivateKey = PEER_FOO_PRIVATE_KEY DNS = 10.200.200.1
根据您的网络情况,较低的 MTU 值也可能使您的 WireGuard 连接正常工作。
在某些情况下,较大的 MTU 值可能会由于沿途不可靠的 路径 MTU 发现 (PMTU) 而导致连接不稳定或断断续续。这可能会导致 ICMP ping 由于其数据包大小较小而工作正常,但大多数 TCP 连接由于完全利用 MTU 大小而失败的情况。例如,IPv6 连接比 IPv4 具有更高的数据包开销,因此在相同的 MTU 值下,可能会更早发生分片。
值得检查对等方和涉及的其他路由器上的链路 MTU 大小,以确定最小值。
# ip link show
5: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1400 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/none
另一种选择是回退到 `1280` 的 MTU,并通过试错法为给定路径找到合适的值。
MTU 为 `1420` 及以上可能会导致部分链接断开,这可能被解释为防火墙或路由问题,而不是实际的 MTU 大小问题。
密钥长度或格式不正确
为避免以下错误,请将密钥值放在配置文件中,而不是密钥文件的路径。
# wg-quick up wg0
[#] ip link add wg0 type wireguard [#] wg setconf wg0 /dev/fd/63 Key is not the correct length or format: `/path/example.key' Configuration parsing error [#] ip link delete dev wg0
无法在 NAT/防火墙后建立持久连接
默认情况下,WireGuard 对端在不需要通信时保持静默,因此位于 NAT 和/或 防火墙 后的对端可能无法从其他对端访问,直到它们自己联系其他对端(或连接可能超时)。在位于 NAT 和/或防火墙后的对端的 `[Peer]` 设置中添加 `PersistentKeepalive = 25` 可以确保连接保持打开状态。
要通过命令行临时设置持久保持活动设置,请运行以下命令
# wg set wg0 peer public_key persistent-keepalive 25
环路路由
将端点 IP 添加到允许的 IP 列表后,内核将尝试将握手发送到所述设备绑定,而不是使用原始路由。这会导致握手尝试失败。
作为一种解决方法,需要使用以下命令手动添加到端点的正确路由
# ip route add endpoint_ip via gateway dev network_interface
例如,对于标准 LAN 设置中上面的对端 B
# ip route add 203.0.113.102 via 192.168.0.1 dev eth0
为了使此路由持久化,可以将命令作为 `PostUp = ip route ...` 添加到 `wg0.conf` 的 `[Interface]` 部分。但是,在某些设置(例如,结合 NetworkManager 使用 `wg-quick@.service`)中,这可能会在恢复时失败。此外,这仅适用于静态网络设置,如果网关或设备发生更改(例如,在笔记本电脑上使用以太网或 Wi-Fi),则会失败。
使用 NetworkManager,更灵活的解决方案是使用调度器脚本启动 WireGuard。以 root 身份创建
/etc/NetworkManager/dispatcher.d/50-wg0.sh
#!/bin/sh case $2 in up) wg-quick up wg0 ip route add <endpoint ip> via $IP4_GATEWAY dev $DEVICE_IP_IFACE ;; pre-down) wg-quick down wg0 ;; esac
如果尚未运行,请启动并启用 `NetworkManager-dispatcher.service`。另请确保 NetworkManager 未管理 `wg0` 的路由,请参阅 #路由定期重置。
使用 systemd-networkd 时,睡眠后连接丢失
systemd 版本 253 引入了在从挂起状态恢复时重新配置网络接口的方式的更改[8]。这样做会导致由 systemd-networkd 管理的网络连接丢失与 wireguard 接口的连接。除非配置了终止开关,否则这会冒着在从挂起状态恢复后暴露公共 IP 地址的风险。要解决此问题,请取消注释 `/etc/systemd/networkd.conf` 中的 `ManageForeignRoutingPolicyRules` 并将其值更改为 `no`。[9]
完整查看 systemd-networkd 页面,以了解此更改的任何其他潜在副作用(如果有)。