WireGuard 的 API 参考指南,包括设置、配置和使用,以及示例。
所有功劳均归于 WireGuard 项目、zx2c4 和原始软件的开源贡献者,
这是我个人的非正式尝试,旨在提供更全面的文档、API 参考和示例。
这些文档、示例代码和问题跟踪器的来源:https://github.com/pirate/wireguard-docs 更好的 HTML 页面版本:https://docs.sweeting.me/s/wireguard
WireGuard 是由 Jason Donenfeld 等人用 C 语言编写的开源 VPN 解决方案,旨在解决困扰其他现代服务器到服务器 VPN 产品(如 IPSec/IKEv2、OpenVPN 或 L2TP)的许多问题。它与 Tinc 和 MeshBird 等其他现代 VPN 产品有一些相似之处,即良好的密码套件和最小的配置。截至 2020 年 1 月,它已合并到 Linux 内核 5.6 版本中,这意味着它将随大多数 Linux 系统开箱即用。
官方链接
wg
、 wg-quick
WireGuard 目标
有关示例代码和文档源,请参阅 https://github.com/pirate/wireguard-docs。
无论是生活在中国的长城后面,还是只是想在服务器之间建立一个网络,WireGuard 都是一个不错的选择,并且可以用作构建网络的“乐高积木”(与 ZFS 是用于构建文件系统的乐高积木非常相似) )。
WireGuard 不做的事情:
但是您可以在后台使用 WireGuard(例如 Tailscale 或 AltheaNet)为这些问题编写自己的解决方案。
这些是文档和示例配置中使用的演示主机名、域名、IP 地址和范围。在进行您自己的设置时,将它们替换为您的首选值。
example-vpn.dev
可以替换为您控制的任何可公开访问的域public-server1
、 public-server2
、 home-server
、 laptop
、 phone
可以更改为您的设备主机名192.0.2.1/24
、 192.0.2.3
、 192.0.2.3/32
、 2001:DB8::/64
可以替换为您首选的子网和地址(例如192.168.5.1/24
)无论您在下面的何处看到这些字符串,它们都只是用作占位符值来说明示例,没有特殊含义。
确保更改配置中的 IP 地址!这些文档中使用的块由 IETF 保留用于示例目的,并且永远不应在实际网络设置中使用。
192.0.2.0/24
(TEST-NET-1) IPv4 示例范围 RFC57372001:DB8::/32
IPv6 示例范围 RFC3849您可以使用您自己的设置所需的任何私有范围,例如10.0.44.0/24
,只需确保它们不与您的对等方所在的任何 LAN 子网范围冲突。
连接VPN的主机为自己注册一个VPN子网地址,如192.0.2.3
。它还可以选择通过以逗号分隔的 CIDR 表示法指定子网范围来路由超出其自身地址的流量。
一个可公开访问的对等点/节点,充当 NAT 后面其他 VPN 对等点中继流量的后备。反弹服务器不是一种特殊类型的服务器,它是一个普通的对等点,就像所有其他服务器一样,唯一的区别是它具有公共 IP 并打开了内核级 IP 转发,这允许它通过 VPN 反弹流量给其他客户。
查看更多信息:https://tailscale.com/blog/how-nat-traversal-works/(Tailscale 在底层使用 Wireguard)
一组独立于公共互联网的 IP,例如 192.0.2.1-255 或 192.168.1.1/24。通常位于路由器提供的 NAT 后面,例如在办公室互联网 LAN 或家庭 Wi-Fi 网络中。
一种使用“掩码”定义子网及其大小的方法,较小的掩码=子网可用的更多地址位以及范围内的更多IP。最常见的:
192.0.2.1/32
(单个 IP 地址, 192.0.2.1
)网络掩码 = 255.255.255.255
192.0.2.1/24
- 192.0.2.255
192.0.2.0
255 个 IP)网络掩码 = 255.255.255.0
192.0.2.1/16
- 192.0.255.255
192.0.0.0
65,536 个 IP)网络掩码 = 255.255.0.0
192.0.2.1/8
- 192.255.255.255
192.0.0.0
16,777,216 个 IP)网络掩码 = 255.0.0.0
0.0.0.1/0
- 255.255.255.255
之间的0.0.0.0
个 IP)网络掩码 = 0.0.0.0
2001:DB8::/64
https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing
对于刚开始使用的人来说, 192.0.2.1/32
可能看起来是一种奇怪且令人困惑的引用单个 IP 的方式。不过,这种设计很好,因为它允许对等方在需要时公开多个 IP,而不需要多个符号。只要知道在任何地方看到类似192.0.2.3/32
东西,它实际上就意味着192.0.2.3
。
具有私有 IP 的子网由位于其前面的路由器提供,进行网络地址转换,各个节点不能从互联网公开访问,而是由路由器跟踪传出连接并将响应转发到正确的内部 IP(例如标准办公网络) 、家庭 Wi-Fi 网络、免费公共 Wi-Fi 网络等)
节点的可公开访问的地址:端口,例如123.124.125.126:1234
或some.domain.tld:1234
(必须可通过公共互联网访问,通常不能是像192.0.2.1
或192.168.1.1
这样的私有 IP,除非同一子网上的其他对等方可以使用该地址直接访问它)。
单个节点的 WireGuard 私钥,通过以下方式生成: wg genkey > example.key
(永远不会离开生成它的节点)
单个节点的 WireGuard 公钥,通过以下方式生成: wg pubkey < example.key > example.key.pub
(与其他对等点共享)
域名服务器,用于将 VPN 客户端的主机名解析为 IP,而不是允许 DNS 请求泄漏到 VPN 外部并泄露流量。泄漏可通过 http://dnsleak.com 进行测试。
公共中继只是普通的 VPN 对等点,能够充当 NAT 后面的任何 VPN 客户端之间的中间中继服务器,它们可以将收到的任何 VPN 子网流量转发到系统级别的正确对等点(WireGuard 不关心这是如何发生的) ,它由内核net.ipv4.ip_forward = 1
和 iptables 路由规则处理)。
如果所有对等点均可公开访问,则您不必担心将其中一个对等点设置为中继服务器的特殊处理,只有当您有任何对等点从 NAT 后面连接时才需要这样做。
每个客户端只需在其配置中定义可公开访问的服务器/对等点,绑定到 NAT 后面其他对等点的任何流量都将进入公共中继AllowedIPs
路由中的包罗万象的 VPN 子网(例如192.0.2.1/24
),并相应地转发一旦到达中继服务器。
总之:只应配置客户端之间的直接连接,任何需要退回的连接不应定义为对等方,因为它们应首先前往退回服务器,然后从那里通过 VPN 路由回正确的客户端。
更复杂的拓扑肯定是可以实现的,但以下是典型 WireGuard 设置中使用的基本路由方法:
Endpoint
地址和端口定义可直接访问的节点,以便 WireGuard 可以直接连接到开放端口并路由 UDP 数据包,无需中间跃点。public-server2
时),定义具有硬Endpoint
的公共可访问节点和不具有硬编码端点的 NAT 节点。连接将从 NAT 客户端 -> 公共客户端打开,然后只要通过来自 NAT 客户端的传出PersistentKeepalive
ping 保持连接保持活动状态,流量就会在它们之间双向直接路由。public-server1
连接,并且只要连接有效,流量就会通过中间反弹服务器转发都保持活着。当可用时,其他对等方提供的更具体(通常也更直接)的路由将优先,否则流量将回退到最不具体的路由,并使用192.0.2.1/24
包罗万象将流量转发到反弹服务器,该流量将在其中然后由中继服务器的系统路由表 ( net.ipv4.ip_forward = 1
) 路由回 VPN 到接受该流量路由的特定对等方。如果尚未定义,WireGuard 不会自动查找最快的路由或尝试在对等点之间形成直接连接,它只是从[Peers]
中最具体的路由到最不具体的路由。
您可以通过测量 ping 时间来确定每个跃点的唯一长度,并检查以下输出,从而确定 WireGuard 对给定地址使用哪种路由方法:
wg show wg0
WireGuard 对所有流量使用加密的 UDP 数据包,它不提供数据包传送或排序的保证,因为这是由加密隧道内的 TCP 连接处理的。
进一步阅读:
WireGuard 声称其性能比大多数其他竞争 VPN 解决方案更快,但具体数字有时存在争议,并且可能取决于硬件级加速是否可用于某些加密密码。
WireGuard 的性能提升是通过在内核级别处理路由以及使用在所有内核上运行的现代密码套件来加密流量来实现的。 WireGuard 还通过使用没有交付/订购保证的 UDP 获得了显着优势(与通过 TCP 运行或实现自己的保证交付机制的 VPN 相比)。
进一步阅读:
WireGuard 使用以下协议和原语来保护流量:
WireGuard 的密码学本质上是 Trevor Perrin 的噪声框架的实例。它既现代又简单。其他所有 VPN 选项都是一团混乱的协商、握手和复杂的状态机。 WireGuard 就像 VPN 中的 Signal/Axolotl,只不过它比双棘轮消息协议更简单、更容易推理(在本例中是加密的)。基本上就是VPN软件的qmail。大约有 4000 行代码。它比竞争对手小多个数量级。
https://news.ycombinator.com/item?id=14599834
进一步阅读:
双向身份验证是通过每个对等点的简单公钥/私钥对来实现的。每个对等点在设置阶段生成这些密钥,并仅与其他对等点共享公钥。
除了每个节点的公钥/私钥之外,不需要其他证书或预共享密钥。
可以使用 Ansible 或 Kubernetes Secrets 等单独的服务在大型部署中处理密钥生成、分发和撤销。
一些有助于密钥分发和部署的服务:
如果您不想在wg0.conf
中对密钥进行硬编码,您还可以从文件或通过命令读取密钥,这使得通过第 3 方服务管理密钥变得更加容易:
[Interface]
...
PostUp = wg set %i private-key /etc/wireguard/wg0.key <(cat /some/path/%i/privkey)
从技术上讲,只要客户端没有同时使用相同的密钥连接到两个服务器,多个服务器就可以共享相同的私钥。这是合理设置的场景示例是,如果您使用循环 DNS 来平衡假装为单个服务器的两个服务器之间的连接负载。然而,大多数时候,每个对等点都应该有自己的公钥/私钥对,以便对等点无法读取彼此的流量,并且可以单独撤销。
大致流程概述:
apt install wireguard
或pkg/brew install wireguard-tools
wg genkey
+ wg pubkey
wg0.conf
WireGuard 配置文件[Interface]
在定义服务器接受地址Address = 192.0.2.1/24
路由的地址时,请确保指定整个 VPN 子网的 CIDR 范围[Peer]
使用相应的远程公钥为每个加入 VPN 的客户端创建一个对等部分wg0.conf
[Interface]
确保为不中继流量的客户端对等方仅指定一个 IP Address = 192.0.2.3/32
。[Peer]
为不在 NAT 后面的每个公共对等点创建一个对等点部分,请确保在定义充当退回服务器的远程对等点时指定整个 VPN 子网的 CIDR 范围AllowedIPs = 192.0.2.1/24
。确保为不中继流量且仅充当简单客户端的远程对等点指定单独的 IP AllowedIPs = 192.0.2.3/32
。wg-quick up /full/path/to/wg0.conf
在主中继服务器上启动 WireGuardwg-quick up /full/path/to/wg0.conf
在所有客户端上启动 WireGuardping 192.0.2.3
首先检查到AllowedIPs = 192.0.2.3/32
的对等点的直接路由,然后回退到接受 IP 的中继服务器在整个子网中 # install on Ubuntu
sudo add-apt-repository ppa:wireguard/wireguard
apt install wireguard
# install on macOS
brew install wireguard-tools
# install on FreeBSD
pkg install wireguard
# install on iOS/Android using Apple App Store/Google Play Store
# install on other systems using https://www.wireguard.com/install/#installation
# to enable the kernel relaying/forwarding ability on bounce servers
echo " net.ipv4.ip_forward = 1 " | sudo tee -a /etc/sysctl.conf
echo " net.ipv4.conf.all.proxy_arp = 1 " | sudo tee -a /etc/sysctl.conf
sudo sysctl -p /etc/sysctl.conf
# to add iptables forwarding rules on bounce servers
sudo iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i wg0 -o wg0 -m conntrack --ctstate NEW -j ACCEPT
sudo iptables -t nat -A POSTROUTING -s 192.0.2.0/24 -o eth0 -j MASQUERADE
nano wg0.conf # can be placed anywhere, must be referred to using absolute path (usually placed in /etc/wireguard/wg0.conf on most Linux systems)
# generate private key
wg genkey > example.key
# generate public key
wg pubkey < example.key > example.key.pub
wg-quick up /full/path/to/wg0.conf
wg-quick down /full/path/to/wg0.conf
# Note: you must specify the absolute path to wg0.conf, relative paths won't work
# If wg0.conf is in /etc/wireguard you can use the simpler:
wg-quick up wg0
# start/stop VPN network interface
ip link set wg0 up
ip link set wg0 down
# register/unregister VPN network interface
ip link add dev wg0 type wireguard
ip link delete dev wg0
# register/unregister local VPN address
ip address add dev wg0 192.0.2.3/32
ip address delete dev wg0 192.0.2.3/32
# register/unregister VPN route
ip route add 192.0.2.3/32 dev wg0
ip route delete 192.0.2.3/32 dev wg0
# show system LAN and WAN network interfaces
ip address show
# or if ip is not available:
ifconfig
# show system VPN network interfaces
ip link show wg0
# or
ifconfig wg0
# show WireGuard VPN interfaces
wg show all
wg show wg0
# show public IP address
ip address show eth0
# or
ifconfig eth0
# or
dig -4 +short myip.opendns.com @resolver1.opendns.com
# show VPN IP address
ip address show wg0
# show WireGuard routing table and peer connections
wg show
wg show wg0 allowed-ips
# show system routing table
ip route show table main
ip route show table local
# show system route to specific address
ip route get 192.0.2.3
要启用额外的日志记录,请运行:
modprobe wireguard
echo module wireguard +p > /sys/kernel/debug/dynamic_debug/control
要跟踪日志:
dmesg -wH
具有现代内核和安全启动的系统可能需要禁用安全启动 DKMS 签名验证以允许访问内核日志。
mokutil --disable-verification
reboot
# check that the main relay server is accessible directly via public internet
ping public-server1.example-vpn.dev
# check that the main relay server is available via VPN
ping 192.0.2.1
# check that public peers are available via VPN
ping 192.0.2.2
# check that remote NAT-ed peers are available via VPN
ping 192.0.2.3
# check that NAT-ed peers in your local LAN are available via VPN
ping 192.0.2.4
# install iperf using your preferred package manager
apt/brew/pkg/opkg install iperf
# check bandwidth over public internet to relay server
iperf -s # on public relay server
iperf -c public-server1.example-vpn.dev # on local client
# check bandwidth over VPN to relay server
iperf -s # on public relay server
iperf -c 192.0.2.1 # on local client
# check bandwidth over VPN to remote public peer
iperf -s # on remote public peer
iperf -c 192.0.2.2 # on local client
# check bandwidth over VPN to remote NAT-ed peer
iperf -s # on remote NAT-ed peer
iperf -c 192.0.2.3 # on local client
# check bandwidth over VPN to local NAT-ed peer (on same LAN)
iperf -s # on local NAT-ed peer
iperf -c 192.0.2.4 # on local client
使用 http://dnsleak.com 检查 DNS 泄漏,或通过检查查找解析器:
dig example.com A
WireGuard 配置采用 INI 语法,在通常称为wg0.conf
的文件中定义。它可以放置在系统上的任何位置,但通常放置在/etc/wireguard/wg0.conf
中。
运行任何wg-quick
命令时,配置路径被指定为参数,例如:
wg-quick up /etc/wireguard/wg0.conf
(始终指定完整的绝对路径)
配置文件名的格式必须为${name of the new WireGuard interface}.conf
。 WireGuard 接口名称通常以wg
为前缀,并从0
开始编号,但您可以使用与正则表达式^[a-zA-Z0-9_=+.-]{1,15}$
匹配的任何名称。
配置文件可以选择使用有限的wg
配置选项集,或更扩展的wg-quick
选项,具体取决于启动 WireGuard 的首选命令。这些文档建议坚持使用wg-quick
,因为它提供了更强大且用户友好的配置体验。
跳转到定义:
¶ [Interface]
¶ # Name = node1.example.tld
¶ Address = 192.0.2.3/32
¶ ListenPort = 51820
¶ PrivateKey = localPrivateKeyAbcAbcAbc=
¶ DNS = 1.1.1.1,8.8.8.8
¶ Table = 12345
¶ MTU = 1500
¶ PreUp = /bin/example arg1 arg2 %i
¶ PostUp = /bin/example arg1 arg2 %i
¶ PreDown = /bin/example arg1 arg2 %i
¶ PostDown = /bin/example arg1 arg2 %i
¶ [Peer]
¶ # Name = node2-node.example.tld
¶ AllowedIPs = 192.0.2.1/24
¶ Endpoint = node1.example.tld:51820
¶ PublicKey = remotePublicKeyAbcAbcAbc=
¶ PersistentKeepalive = 25
[Interface]
定义本地节点的 VPN 设置。
示例
[Interface]
# Name = phone.example-vpn.dev
Address = 192.0.2.5/32
PrivateKey = <private key for phone.example-vpn.dev>
[Interface]
# Name = public-server1.example-vpn.tld
Address = 192.0.2.1/24
ListenPort = 51820
PrivateKey = <private key for public-server1.example-vpn.tld>
DNS = 1.1.1.1
# Name
这只是 INI 语法中的一个标准注释,用于帮助跟踪哪个配置部分属于哪个节点,它完全被 WireGuard 忽略,并且对 VPN 行为没有影响。
注意:某些操作和应用程序会从 .conf 文件中删除所有注释,包括# Name
。如果您需要识别对等方,请考虑使用wireguard vanity key生成器,例如wireguard-vanity-keygen或wireguard-vanity-address,它允许您将主机名包含在主机的公钥中。密钥生成可能需要几分钟(4 个字符)、几小时(5 个字符)或更长时间,因此请考虑对名称较长的主机使用缩写。
Address
定义本地节点应路由流量的地址范围。根据节点是加入 VPN 子网的简单客户端还是在多个客户端之间中继流量的反弹服务器,可以将其设置为节点本身的单个 IP(使用 CIDR 表示法指定),例如 192.0.2.3/32 ),或节点可以为其路由流量的一系列 IPv4/IPv6 子网。
示例
节点是一个只为自己路由流量的客户端Address = 192.0.2.3/32
节点是一个公共反弹服务器,可以将流量中继到其他对等点
当节点充当公共反弹服务器时,它应该将其设置为可以路由流量的整个子网,而不仅仅是其自身的单个 IP。
Address = 192.0.2.1/24
Address = 192.0.2.1/24,2001:DB8::/64
ListenPort
当节点充当公共反弹服务器时,它应该对端口进行硬编码以侦听来自公共互联网的传入 VPN 连接。不充当中继的客户端不应设置此值。
示例
ListenPort = 51820
ListenPort = 7000
PrivateKey
这是本地节点的私钥,永远不会与其他服务器共享。所有节点都必须有一个私钥集,无论它们是中继流量的公共反弹服务器,还是加入 VPN 的简单客户端。
该密钥可以使用wg genkey > example.key
生成
示例
PrivateKey = somePrivateKeyAbcdAbcdAbcdAbcd=
DNS
通过 DHCP 向 VPN 客户端通告的 DNS 服务器,大多数客户端将使用此服务器通过 VPN 进行 DNS 请求,但客户端也可以在其节点上本地覆盖此值
示例
DNS = 1.1.1.1
DNS = 1.1.1.1,8.8.8.8
Table
(可选)定义用于 WireGuard 路由的路由表,大多数设置无需配置。
有两个特殊值:“off”完全禁用路由的创建,“auto”(默认值)将路由添加到默认表并启用对默认路由的特殊处理。
https://git.zx2c4.com/WireGuard/about/src/tools/man/wg-quick.8
示例
Table = 1234
MTU
可选择定义连接到对等方时使用的最大传输单元(MTU,又称数据包/帧大小),大多数设置无需配置。
MTU 是根据端点地址或系统默认路由自动确定的,这通常是明智的选择。
https://git.zx2c4.com/WireGuard/about/src/tools/man/wg-quick.8
示例
MTU = 1500
PreUp
可以选择在启动接口之前运行命令。可以多次指定此选项,命令按照它们在文件中出现的顺序执行。
示例
PreUp = ip rule add ipproto tcp dport 22 table 1234
PostUp
可以选择在接口启动后运行命令。该选项可以出现多次,就像 PreUp 一样
示例
从文件或某些命令的输出中读取配置值PostUp = wg set %i private-key /etc/wireguard/wg0.key <(some command here)
将一行记录到文件中PostUp = echo "$(date +%s) WireGuard Started" >> /var/log/wireguard.log
访问另一台服务器上的 webhook
PostUp = curl https://events.example.dev/wireguard/started/?key=abcdefg
添加一条路由到系统路由表PostUp = ip rule add ipproto tcp dport 22 table 1234
添加 iptables 规则以在 WireGuard 接口上启用数据包转发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 地址PostUp = resolvectl domain %i "~."; resolvectl dns %i 192.0.2.1; resolvectl dnssec %i yes
PreDown
(可选)在接口关闭之前运行命令。该选项可以出现多次,就像 PreUp 一样
示例
将一行记录到文件中PostDown = echo "$(date +%s) WireGuard Going Down" >> /var/log/wireguard.log
访问另一台服务器上的 webhook
PostDown = curl https://events.example.dev/wireguard/stopping/?key=abcdefg
PostDown
可以选择在接口关闭后运行命令。该选项可以出现多次,就像 PreUp 一样
示例
将一行记录到文件中PostDown = echo "$(date +%s) WireGuard Stopped" >> /var/log/wireguard.log
访问另一台服务器上的 webhook
PostDown = curl https://events.example.dev/wireguard/stopped/?key=abcdefg
删除在 WireGuard 接口上转发数据包的 iptables 规则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]
定义能够为一个或多个地址(自身和/或其他对等点)路由流量的远程对等点的 VPN 设置。对等点可以是将流量中继到其他对等点的公共反弹服务器,也可以是通过 LAN/互联网直接访问的客户端,该客户端不在 NAT 后面且仅为自身路由流量。
所有客户端都必须定义为公共退回服务器上的对等方。仅为自己路由流量的简单客户端,只需为公共中继定义对等点,以及可直接访问的任何其他节点。位于单独 NAT 后面的节点不应定义为公共服务器配置之外的对等点,因为单独 NAT 之间没有可用的直接路由。相反,NAT 后面的节点应仅将公共中继服务器和其他公共客户端定义为其对等方,并且应在接受路由并将 VPN 子网的流量反弹到远程 NAT 的公共服务器上指定AllowedIPs = 192.0.2.1/24
同行。
总之,所有节点都必须在主退回服务器上定义。在客户端服务器上,只有可从节点直接访问的对等点才应定义为该节点的对等点,必须由退回服务器中继的任何对等点都应排除在外,并由中继服务器的包罗万象的路由进行处理。
在下面文档中概述的配置中,单个服务器public-server1
充当可公开访问和 NAT 客户端混合的中继反弹服务器,并且对等点在每个节点上进行相应配置:
在public-server1
wg0.conf
(退回服务器)
[peer]
列表: public-server2
、 home-server
、 laptop
、 phone
在public-server2
wg0.conf
(简单的公共客户端)
[peer]
列表: public-server1
在home-server
wg0.conf
中(NAT 后面的简单客户端)
[peer]
列表: public-server1
、 public-server2
在laptop
wg0.conf
中(NAT 后面的简单客户端)
[peer]
列表: public-server1
、 public-server2
在phone
wg0.conf
中(NAT 后面的简单客户端)
[peer]
列表: public-server1
、 public-server2
示例
[Peer]
# Name = public-server2.example-vpn.dev
Endpoint = public-server2.example-vpn.dev:51820
PublicKey = <public key for public-server2.example-vpn.dev>
AllowedIPs = 192.0.2.2/32
[Peer]
# Name = home-server.example-vpn.dev
Endpoint = home-server.example-vpn.dev:51820
PublicKey = <public key for home-server.example-vpn.dev>
AllowedIPs = 192.0.2.3/32
[Peer]
# Name = public-server1.example-vpn.tld
Endpoint = public-server1.example-vpn.tld:51820
PublicKey = <public key for public-server1.example-vpn.tld>
# routes traffic to itself and entire subnet of peers as bounce server
AllowedIPs = 192.0.2.1/24
PersistentKeepalive = 25
# Name
这只是 INI 语法中的一个标准注释,用于帮助跟踪哪个配置部分属于哪个节点,它完全被 WireGuard 忽略,并且对 VPN 行为没有影响。
Endpoint
定义远程对等点的可公开访问的地址。对于 NAT 后面的对等点或没有稳定的可公开访问的 IP:PORT 对的对等点,应忽略此操作。通常,这只需要在主反弹服务器上定义,但也可以在具有稳定 IP 的其他公共节点上定义,例如下面示例配置中的public-server2
。
示例
Endpoint = 123.124.125.126:51820
(也支持 IPv6)Endpoint = public-server1.example-vpn.tld:51820
AllowedIPs
这定义了对等方将路由流量的 IP 范围。在简单客户端上,这通常是单个地址(简单客户端本身的 VPN 地址)。对于退回服务器,这将是中继服务器能够为其路由流量的 IP 或子网范围。可以使用逗号分隔的 IPv4 或 IPv6 CIDR 表示法指定多个 IP 和子网(从单个 /32 或 /128 地址,一直到0.0.0.0/0
和::/0
以指示发送所有内容的默认路由)通过该对等点的互联网和 VPN 流量)。该选项可以指定多次。
在决定如何路由数据包时,系统首先选择最具体的路由,然后再选择更广泛的路由。因此,对于发往192.0.2.3
的数据包,系统将首先专门查找对等广告192.0.2.3/32
,然后回退到对等广告192.0.2.1/24
或更大的范围(如0.0.0.0/0
)最后的手段。
示例
对等体是一个简单的客户端,仅接受来自/自身的流量AllowedIPs = 192.0.2.3/32
对等体是一个中继服务器,可以将 VPN 流量反弹到所有其他对等体AllowedIPs = 192.0.2.1/24
Peer 是一个中继服务器,可转发所有互联网和 VPN 流量(如代理),包括 IPv6
AllowedIPs = 0.0.0.0/0,::/0
对等体是一个中继服务器,路由到它自己和仅一个其他对等体AllowedIPs = 192.0.2.3/32,192.0.2.4/32
对等体是一个中继服务器,路由到其自身及其本地 LAN 上的所有节点AllowedIPs = 192.0.2.3/32,192.168.1.1/24
PublicKey
这是远程节点的公钥,可与所有对等点共享。所有节点都必须有一个公钥集,无论它们是中继流量的公共反弹服务器,还是加入 VPN 的简单客户端。
该密钥可以使用wg pubkey < example.key > example.key.pub
生成。 (有关如何生成私钥example.key
的信息,请参阅上文)
示例
PublicKey = somePublicKeyAbcdAbcdAbcdAbcd=
PersistentKeepalive
如果连接是从 NAT 化对等方到公共对等方,则 NAT 后面的节点必须定期发送传出 ping,以便在 NAT 路由器的连接表中保持双向连接处于活动状态。
示例
本地公共节点到远程公共节点
该值应保持未定义,因为不需要持久 ping。
本地公共节点到远程 NAT 节点
该值应保持未定义,因为保持连接活动是客户端的责任,因为如果超时,服务器无法重新打开与客户端的死连接。
本地 NAT 节点到远程公共节点PersistentKeepalive = 25
这将每 25 秒发送一次 ping,以保持本地 NAT 路由器连接表中的连接处于打开状态。
这些文档中的示例主要使用 IPv4,但 WireGuard 本身支持 IPv6 CIDR 表示法和它支持 IPv4 的所有位置的地址,只需像添加任何其他子网范围或地址一样添加它们即可。
例子
[Interface]
Address = 192.0.2.3/24, 2001:DB8::/64
[Peer]
...
AllowedIPs = 0.0.0.0/0, ::/0
如果您想通过 VPN 转发所有Internet 流量,而不仅仅是将其用作服务器到服务器子网,则可以将0.0.0.0/0, ::/0
添加到要通过管道传输的对等点的AllowedIPs
定义中您的流量通过。
即使仅转发 IPv4 流量,也请确保指定 IPv6 包罗万象,以避免在 VPN 外部泄漏 IPv6 数据包,请参阅:
https://www.reddit.com/r/WireGuard/comments/b0m5g2/ipv6_leaks_psa_for_anyone_here_using_wireguard_to/
例子
[Interface]
# Name = phone.example-vpn.dev
Address = 192.0.2.3/32
PrivateKey = <private key for phone.example-vpn.dev>
[Peer]
# Name = public-server1.example-vpn.dev
PublicKey = <public key for public-server1.example-vpn.dev>
Endpoint = public-server1.example-vpn.dev:51820
AllowedIPs = 0.0.0.0/0, ::/0
WireGuard 有时可以在 NAT 后面的两个客户端之间本机建立连接,而无需公共中继服务器,但在大多数情况下这是不可能的。仅当至少一台主机具有稳定、可公开访问的 IP 地址:可提前硬编码的端口对时,NAT 到 NAT 连接才可能实现,无论是使用通过动态 DNS 更新的 FQDN,还是使用通过动态 DNS 更新的静态公共 IP由传出数据包打开的非随机 NAT 端口,只要所有对等方都可以事先进行通信,并且一旦连接启动,它就不会改变,任何东西都可以工作。
需要提前配置已知的端口和地址,因为 WireGuard 没有可用于动态搜索其他主机的信令层或公共 STUN 服务器。 WebRTC 是一个可以动态配置两个 NAT 之间连接的协议示例,但它是通过使用带外信令服务器来检测每个主机的 IP:端口组合来实现这一点的。 WireGuard 没有这个功能,因此它只能与硬编码的Endpoint
+ ListenPort
一起使用(以及PersistentKeepalive
因此它在不活动后不会丢失)。
从 Tailscale 的 NAT 穿越圣经了解更多信息:https://tailscale.com/blog/how-nat-traversal-works/
Endpoint
。如果它们都位于 NAT 后面且没有稳定的 IP 地址,那么您需要使用动态 DNS 或其他解决方案来为至少一个对等方拥有稳定的、可公开访问的域/IPListenPort
,并且其 NAT 路由器不得进行 UDP 源端口随机化,否则返回数据包将被发送到硬编码的ListenPort
并被路由器丢弃,而不是使用由路由器分配的随机端口对传出数据包进行 NATPersistentKeepalive
,以便它们不断发送传出 ping 来保持连接在其 NAT 路由表中持久存在发送被拒绝的初始数据包,然后利用路由器现在创建的转发规则来接受响应的过程称为“UDP 打洞”。
当您发送 UDP 数据包时,路由器(通常)会创建一条临时规则,将源地址和端口映射到目标地址和端口,反之亦然。从目标地址和端口(而不是其他)返回的 UDP 数据包将传递到原始源地址和端口(而不是其他)。这就是大多数 UDP 应用程序在 NAT 后面运行的方式(例如 BitTorrent、Skype 等)。此规则将在几分钟不活动后超时,因此 NAT 后面的客户端必须定期发送传出数据包以保持其打开状态(请参阅PersistentKeepalive
)。
当两个端点都位于 NAT 或防火墙后面时,要使其发挥作用,需要两个端点大约同时向对方发送数据包。这意味着双方需要提前知道彼此的公共 IP 地址和端口号,在 WireGuard 的情况下,这是通过在wg0.conf
中对双方的预定义端口进行硬编码来实现的。
截至 2019 年,许多过去有效的旧打孔方法不再有效。一个例子是 pwnat 首创的一种新颖方法,该方法从 NAT 外部伪造 ICMP 超时响应,以将数据包返回到经过 NAT 处理的对等方,从而泄漏其自己的源端口。 NAT 到 NAT 连接两侧的硬编码 UDP 端口和公共 IP(如上所述)仍然适用于一小部分网络。一般来说,网络越“企业化”,就越不可能对公共 UDP 端口进行打孔(例如,商业公共 Wi-Fi 和蜂窝数据 NAT 通常不起作用)。
如果所有端点都位于 NAT 后面且具有严格的 UDP 源端口随机化(例如大多数蜂窝数据网络),则 NAT 到 NAT 连接是不可能的。由于双方都无法对ListenPort
进行硬编码并保证其 NAT 在传出 ping 后接受该端口上的流量,因此您无法协调对等方之间的初始打洞的端口,并且连接将失败。因此,您通常无法在 LTE/3g 网络上进行电话到电话的连接,但您也许可以在办公室或家庭拥有稳定的公共 IP 并且没有网络连接的情况下进行电话到办公室或电话到家庭的连接。不进行源端口随机化。
来自 NAT 后面的 NAT 到 NAT 连接具有严格的源端口随机化是可能的,您只需要一个信令服务器来告诉每一方对方的 IP:端口元组。以下是使用 WireGuard 实现此目的的一些实现:
许多用户报告每当动态 IP 更改时都必须重新启动 WireGuard,因为它仅在启动时解析主机名。要强制 WireGuard 更频繁地重新解析动态 DNS Endpoint
主机名,您可能需要使用PostUp
挂钩每隔几分钟或几小时重新启动 WireGuard。
您可以通过在客户端和服务器上使用 netcat 来查看打孔设置是否可行,以查看哪些端口和连接顺序可以打开双向连接:运行nc -v -u -p 51820 <address of peer2> 51820
(在peer1上)和nc -v -u -l 0.0.0.0 51820
(在peer2上),然后在两个窗口中键入以查看是否可以进行双向流量。如果无论哪个对等方发送初始数据包都不起作用,则 WireGuard 将无法在没有公共中继服务器的对等方之间工作。
NAT 到 NAT 连接通常更不稳定,并且有其他限制,这就是为什么仍然建议使用后备公共中继服务器。
例子
对等1:
[Interface]
...
ListenPort 12000
[Peer]
...
Endpoint = peer2.example-vpn.dev:12000
PersistentKeepalive = 25
对等2:
[Interface]
...
ListenPort 12000
[Peer]
...
Endpoint = peer1.example-vpn.dev:12000
PersistentKeepalive = 25
注意:本节涉及 VPN 子网内的动态对等 IP,而不是动态公共Endpoint
地址。
对等 IP 的动态分配(而不是仅具有固定对等点)正在开发中,WIP 实现可在此处获取:https://github.com/WireGuard/wg-dynamic
您还可以通过使用PostUp
在运行时从文件中读取 IP 值来自己构建动态分配系统(见下文)。
例子
[Interface]
...
PostUp = wg set %i allowed-ips /etc/wireguard/wg0.key <(some command)
https://git.zx2c4.com/wireguard-go/about/
用 Go 编写的兼容用户层 WireGuard 实现。
https://git.zx2c4.com/wireguard-rs/about/
用 Rust 编写的 WireGuard 的不完整、不安全的用户空间实现(尚未准备好供公众使用)。
https://git.zx2c4.com/wireguard-hs/about/
用 Haskell 编写的 WireGuard 的不完整、不安全的用户空间实现(未准备好供公众使用)。
https://github.com/cloudflare/boringtun
用 Rust 编写的不合规的独立 WireGuard 实现(由 CloudFlare 编写的单独分支)。请参阅 https://blog.cloudflare.com/boringtun-userspace-wireguard-rust/
特定于平台的 WireGuard 应用程序
https://git.zx2c4.com/wireguard-ios/about/
https://git.zx2c4.com/wireguard-android/about/
https://git.zx2c4.com/wireguard-windows/about/
所有用户空间实现都比在内核空间中运行的本机 C 版本慢,但通过在用户空间中运行提供了其他好处(例如更容易的容器化、兼容性等)。
这些是一些 GUI 和 CLI 工具,它们包装 WireGuard 以协助配置、部署、密钥管理和连接。
这些快捷方式的功劳在于:https://www.ericlight.com/new-things-i-didnt-know-about-wireguard.html
WireGuard 将忽略其公钥与接口私钥匹配的对等点。因此,您可以在任何地方分发单个对等点列表,并且仅在每个服务器上单独定义[Interface]
。
请参阅:https://lists.zx2c4.com/pipermail/wireguard/2018-December/003703.html
您可以将其与wg addconf
结合使用,如下所示:
每个对等点都有自己的/etc/wireguard/wg0.conf
文件,该文件仅包含其[Interface]
部分。
每个对等点还有一个共享的/etc/wireguard/peers.conf
文件,其中包含所有对等点。
wg0.conf
文件还有一个PostUp
挂钩: PostUp = wg addconf /etc/wireguard/peers.conf
。
由您决定如何共享peers.conf
,无论是通过适当的编排平台、像Dropbox这样更简单的平台,还是像Ceph这样有点狂野的平台。我不知道,但是你可以随意地乱扔一个对等部分,而不用担心它是否与界面相同,这真是太棒了。
您可以通过任意命令或从文件中读取值来设置配置值,这使得密钥管理和部署变得更加容易,因为您可以在运行时从 Kubernetes Secrets 或 AWS KMS 等第三方服务读取密钥。
请参阅:https://lists.zx2c4.com/pipermail/wireguard/2018-December/003702.html
例子
您可以通过执行以下操作来读取文件作为PrivateKey
:
PostUp = wg set %i private-key /etc/wireguard/wg0.key <(some command)
WireGuard 可以在不同程度上轻松地在 Docker 中运行。在最简单的情况下,可以将--privileged
和--cap-add=all
参数添加到 docker 命令中以启用内核模块的加载。
设置可能会变得有些复杂,并且高度依赖于您想要实现的目标。您可以让 WireGuard 本身在容器中运行并向主机公开网络接口,也可以让 WireGuard 在主机上运行以向特定容器公开接口。
请参阅下面的 Docker 容器vpn_test
通过 WireGuard 中继服务器路由其所有流量的示例。
version : ' 3 '
services :
wireguard :
image : linuxserver/wireguard
ports :
- 51820:51820/udp
cap_add :
- NET_ADMIN
- SYS_MODULE
volumes :
- /lib/modules:/lib/modules
- ./wg0.conf:/config/wg0.conf:ro
wg0.conf
:
[Interface]
# Name = relay1.wg.example.com
Address = 192.0.2.1/24
ListenPort = 51820
PrivateKey = oJpRt2Oq27vIB5/ UVb7BRqCwad2YMReQgH5tlxz8YmI =
DNS = 1.1.1.1,8.8.8.8
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT ; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT ; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
[Peer]
# Name = peer1.wg.example.com
PublicKey = I+hXRAJOG/UE2IQvIHsou2zTgkUyPve2pzvHTnd/ 2Gg =
AllowedIPs = 192.0.2.2/32
在此示例中,来自speedtest
容器内部的所有流量都将通过wireguard VPN。要仅路由某些流量,请将下面wg0.conf
中的0.0.0.0/0
替换为您想要通过 VPN 路由的子网范围。
docker-compose.yml
:
version : ' 3 '
services :
wireguard :
image : linuxserver/wireguard
cap_add :
- NET_ADMIN
- SYS_MODULE
volumes :
- /lib/modules:/lib/modules
- ./wg0.conf:/config/wg0.conf:ro
vpn_test :
image : curlimages/curl
entrypoint : curl -s http://whatismyip.akamai.com/
network_mode : ' service:wireguard '
wg0.conf
:
[Interface]
# Name = peer1.wg.example.com
Address = 192.0.2.2/32
PrivateKey = YCW76edD4W7nZrPbWZxPZhcs32CsBLIi1sEhsV/ sgk8 =
DNS = 1.1.1.1,8.8.8.8
[Peer]
# Name = relay1.wg.example.com
Endpoint = relay1.wg.example.com:51820
PublicKey = zJNKewtL3gcHdG62V3GaBkErFtapJWsAx+ 2um0c0B1s =
AllowedIPs = 192.0.2.1/24,0.0.0.0/0
PersistentKeepalive = 21
有关更多详细信息,请参阅下面的进一步阅读:Docker 部分。
有关更详细的说明,请参阅上面的快速入门指南和 API 参考。您还可以在此处下载完整的示例设置:https://github.com/pirate/wireguard-example。
建议更改:https://github.com/pirate/wireguard-docs/issues