WireGuard
出自 WireGuard 项目主页
- WireGuard 是一款极其简单、快速且现代的 VPN,它采用了最先进的加密技术。它的目标是比 IPsec 更快、更简单、更精简和更有用,同时避免了巨大的麻烦。它旨在比 OpenVPN 具有更高的性能。WireGuard 被设计为一个通用的 VPN,可以在嵌入式接口和超级计算机上运行,适用于许多不同的环境。最初为 Linux 内核发布,现在它是跨平台的(Windows、macOS、BSD、iOS、Android),并且可以广泛部署。
本文中使用的主要概念的粗略介绍可以在 WireGuard 的项目主页上找到。WireGuard 自 2019 年末以来已包含在 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 | dynamic | dynamic | 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 隧道。
当前的 WireGuard 配置可以通过使用 wg(8) 实用程序的 showconf
命令来保存。例如
# 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
- 要将所有流量路由通过隧道到特定对等节点,请将 默认路由 (IPv4 为
0.0.0.0/0
,IPv6 为::/0
) 添加到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] SECTION OPTIONS。 - 要将对等节点用作唯一 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
以下示例通过 keyfile 格式 .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
- 要将所有流量路由通过隧道到特定对等节点,请将 默认路由 (IPv4 为
0.0.0.0/0
,IPv6 为::/0
) 添加到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)。例如,使用 keyfile 格式
... [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 项目除了 Linux、Windows 和 MacOS 之外,还提供 iOS 和 Android 平台上的应用程序)。有关更多信息,请参阅官方项目 安装链接。
服务器
在将充当“服务器”的对等节点上,首先 启用 IPv4 转发。
如果服务器配置了公共 IP,请务必
- 在 WireGuard 将运行的指定端口上允许 UDP 流量(例如,允许
51820/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
将转发所有 IPv4 (0.0.0.0/0
) 和 IPv6 (::/0
) 流量通过 VPN。
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
network.wireguard.*
。请参阅 systemd.netdev(5) § [WIREGUARD]_SECTION_OPTIONS。修改您的 .netdev 文件以使用
PrivateKey = @network.wireguard.private.wg0 PresharedKey = @network.wireguard.psk.wg0
具有更改 IP 的端点
在解析服务器域名后,WireGuard 将不再检查 DNS 中的更改。
如果 WireGuard 服务器的 IP 地址经常因 DHCP、Dyndns、IPv6 等而更改,则任何 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 的端点恢复。
一种方法是每三十秒更新所有 WireGuard 端点一次[7],通过 systemd 计时器
/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 接口。可以通过在客户端的 Interface 部分的 WireGuard 配置中设置 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
另一种选择是回退到 MTU 为 1280
,并通过试错方法找到给定路径的合适值。
1420
及以上的 MTU 可能会导致部分链路断开,这可能被解释为防火墙或路由问题,而不是实际的 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]
部分。但是,在某些设置(例如,将 wg-quick@.service
与 NetworkManager 结合使用)中,这可能会在恢复时失败。此外,这仅适用于静态网络设置,如果网关或设备发生更改(例如,在笔记本电脑上使用以太网或 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 页面,以了解此更改的任何其他潜在副作用(如果有)。