WireGuard

出自 Arch Linux 中文维基

這篇文章或章節的翻譯不反映原文。

原因:翻譯已經過期,請閱讀英文頁面中的內容。(在 Talk:WireGuard# 中討論)

引用自 WireGuard 項目主頁:

WireGuard 是一種極其簡單但快速且現代的 VPN,它利用了最先進的加密技術。它的目標是比 IPsec 更快、更簡單、更精簡和更有用,同時避免令人頭疼的問題。其旨在提供比 OpenVPN 更高的性能。WireGuard 被設計為在嵌入式接口和超級計算機等上運行的通用 VPN,適用於許多不同的環境。雖然最初僅支持 Linux,但現在可以跨平台(Windows、macOS、BSD、iOS、Android)廣泛部署。

本文中的主要概念在 WireGuard 項目主頁上有粗略的介紹。2019 年底以後,Linux 內核中包含 WireGuard。

安裝[編輯 | 編輯原始碼]

安裝 wireguard-tools,其提供了用戶空間實用程序。

另外,如果 Peer 公鑰可用,也可以藉助其他網絡管理器的 WireGuard 支持。詳見#持久化配置

圖形客戶端[編輯 | 編輯原始碼]

  • Qomui — OpenVPN GUI,具有高級功能,且支持多個後端。
https://github.com/corrad1nho/qomui || qomuiAUR

命令行工具[編輯 | 編輯原始碼]

  • wg_tool — 用於管理服務器和用戶 wireguard 配置的工具。
https://github.com/gene-git/wg_tool || wg_toolAUR
https://git.flu0r1ne.net/wg2nd/about || wg2ndAUR

使用[編輯 | 編輯原始碼]

以下命令展示了如何在兩個對等節點之間建立一條使用以下設置的基本的隧道:

外部(公共)地址 內部 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
提示:對等節點可使用相同的 UDP 端口。

外部地址應該已經存在。例如,如果 ICMP 回顯請求未被阻止,則對等節點 A 應該能夠通過 ping 通對等點 B 的公共 IP 地址,反之亦然。

內部地址將是使用 ip(8) 實用程序手動創建或通過網絡管理軟件創建的新地址,這些地址將在新的 WireGuard 網絡內部使用。以下示例使用 10.0.0.0/24 和 fdc9:281f:04d7:9ee9::/64 作為內部網絡。 IP 地址中的 /24/64CIDR

生成密鑰[編輯 | 編輯原始碼]

為每個對等節點創建公鑰和私鑰。如果要連接很多節點,可以考慮 vanity keypair 個性化 Base64 編碼的公鑰字符串,參見#Vanity keys

生成私鑰:

$ (umask 0077; wg genkey > peer_A.key)
注意: 建議僅允許所有者讀寫。以上命令使用子 shell 臨時改變 umask,從而確保只有所有者可訪問(有讀寫權限)。

生成公鑰:

$ 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

Vanity keys[編輯 | 編輯原始碼]

Currently, WireGuard does not support comments or attaching human-memorable names to keys. This makes identifying the key's owner difficult particularly when multiple keys are in use. One solution is to generate a public key that contains some familiar characters (perhaps the first few letters of the owner's name or of the hostname etc.), wireguard-vanity-addressAUR does this.

For example:

$ 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=

這篇文章或章節的翻譯不反映原文。

原因:以下翻譯已經過期,請閱讀英文頁面中的內容。(在 Talk:WireGuard# 中討論)

在 peer 上生成公鑰和私鑰:

$ wg genkey | tee privatekey | wg pubkey > publickey

下面的指令會演示如何以表中的配置建立一條兩個 peer 之間的隧道

Peer A Peer B
公網地址 10.10.10.1/24 10.10.10.2/24
內網地址 10.0.0.1/24 10.0.0.2/24
wireguard 監聽端口 UDP/4857 UDP/3981

Peer 應當已經擁有公網地址。例如,peer A 應當能夠通過 ping 10.10.10.2 ping 通 peer B,反之亦然。內部地址是由下文 ip 命令創建的新地址,並且將在 WireGuard 網絡中共享。IP地址中 /24 的含義詳見 CIDR

Peer A 配置[編輯 | 編輯原始碼]

這個 peer 將監聽 UDP 端口 48574,通過將 peer B 的公鑰與其內部和外部 IP 地址關聯,接受來自 peer B 的連接。

# ip link add dev wg0 type wireguard
# ip link set dev wg0 mtu 1420
# ip addr add 10.0.0.1/24 dev wg0
# wg set wg0 listen-port 4857 private-key ./privatekey
# wg set wg0 peer [Peer B public key] persistent-keepalive 25 allowed-ips 10.0.0.2/32 endpoint 10.10.10.2:3981
# ip link set wg0 up

[Peer B public key] 的格式應當如同 EsnHH9m6RthHSs+sd9uM6eCHe/mMVFaRh93GYadDDnM=allowed-ips 是 peer A 能夠向之發送流量的地址列表。allowed-ips 0.0.0.0/0 將允許向任意地址發送流量。

Peer B 配置[編輯 | 編輯原始碼]

如同 Peer A,只不過 wireguard 守護監聽 UDP 端口 39814 並且只接受 peer A 的連接

# ip link add dev wg0 type wireguard
# ip link set dev wg0 mtu 1420
# ip addr add 10.0.0.2/24 dev wg0
# wg set wg0 listen-port 3981 private-key ./privatekey
# wg set wg0 peer [Peer A public key] persistent-keepalive 25 allowed-ips 10.0.0.1/32 endpoint 10.10.10.1:4857
# ip link set wg0 up

基本檢查[編輯 | 編輯原始碼]

不帶任何參數使用 wg 命令可以快速查看當前的配置。

例如,當 peer A 配置好之後,我們可以看見它的身份和與之關聯的 peers。

 peer-a$ wg
 interface: wg0
   public key: UguPyBThx/+xMXeTbRYkKlP0Wh/QZT3vTLPOVaaXTD8=
   private key: (hidden)
   listening port: 4857
 
 peer: 9jalV3EEBnVXahro0pRMQ+cHlmjE33Slo9tddzCVtCw=
   endpoint: 10.10.10.2:3981
   allowed ips: 10.0.0.2/32

此時我們可以 ping 通隧道的另一端:

 peer-a$ ping 10.0.0.2

配置持久化[編輯 | 編輯原始碼]

配置可以通過 showconf 來保存

# wg showconf wg0 > /etc/wireguard/wg0.conf
# wg setconf wg0 /etc/wireguard/wg0.conf

示例 peer 配置[編輯 | 編輯原始碼]

/etc/wireguard/wg0.conf
[Interface]
PrivateKey = [CLIENT PRIVATE KEY]
MTU = 1420

[Peer]
PublicKey = [SERVER PUBLICKEY]
AllowedIPs = 10.0.0.0/24, 10.123.45.0/24, 1234:4567:89ab::/48
Endpoint = [SERVER ENDPOINT]:5182
PersistentKeepalive = 25

配置一個 VPN 服務器[編輯 | 編輯原始碼]

WireGuard 自帶一個快速創建和銷毀 VPN 服務器的工具,wg-quick。注意這裡使用的配置文件不是一個能被 wg setconf 有效的配置文件,並且你可能至少要把 eth0 改成你實際使用的。

服務器[編輯 | 編輯原始碼]

/etc/wireguard/wg0server.conf
[Interface]
Address = 10.0.0.1/24  # This is the virtual IP address, with the subnet mask we will use for the VPN
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
ListenPort = 5182
PrivateKey = [SERVER PRIVATE KEY]
MTU = 1420

[Peer]
PublicKey = [CLIENT PUBLIC KEY]
AllowedIPs = 10.0.0.2/32  # 這表示客戶端只有一個 IP。

要使 iptables 規則生效,啟用 IPv4 轉發:

# sysctl net.ipv4.ip_forward=1

永久保留這項改變,向 /etc/sysctl.d/99-sysctl.conf 添加 net.ipv4.ip_forward = 1

使用 wg-quick up wg0server 啟用 Interface,wg-quick down wg0server 用以關閉

客戶端 (轉發所有流量)[編輯 | 編輯原始碼]

/etc/wireguard/wg0.conf
[Interface]
Address = 10.0.0.2/24  # The client IP from wg0server.conf with the same subnet mask
PrivateKey = [CLIENT PRIVATE KEY]
DNS = 10.0.0.1
MTU = 1420

[Peer]
PublicKey = [SERVER PUBLICKEY]
AllowedIPs = 0.0.0.0/0, ::0/0
Endpoint = [SERVER ENDPOINT]:5182
PersistentKeepalive = 25

使用 wg-quick up wg0 來啟用 Interface, 使用 wg-quick down wg0 來關閉。

使用 systemctl enable wg-quick@wg0 來自動啟動。

如果你使用 NetworkManager, 可能有必要啟用 NetworkManager-wait-online.service systemctl enable NetworkManager-wait-online.service

或者你使用的是 systemd-networkd, 啟用 systemd-networkd-wait-online.service systemctl enable systemd-networkd-wait-online.service

等待所有設備就緒再嘗試 WireGuard 連接

使用技巧[編輯 | 編輯原始碼]

以加密的形式存儲私鑰[編輯 | 編輯原始碼]

以加密的形式存儲私鑰可能是可以實現的,例如通過使用 pass。只需將配置文件中[Interface]下的 PrivateKey 一行替換為。

 PostUp = wg set %i private-key <(su user -c "export PASSWORD_STORE_DIR=/path/to/your/store/; pass WireGuard/private-keys/%i")

where user is your username. See the `wg-quick(8)` man page for more details.

將其中的user替換成你的用戶名。更多細節請參見 `wg-quick(8)` man 頁面。

疑難解答[編輯 | 編輯原始碼]

本文或本節需要翻譯。要貢獻翻譯,請訪問簡體中文翻譯團隊

附註: 請提供模板的第一個位置參數以更詳細的指示。(在 Talk:WireGuard# 中討論)

路由定期被重置[編輯 | 編輯原始碼]

NetworkManager 用戶應確保其未管理 WireGuard 接口。例如,創建以下配置文件:

/etc/NetworkManager/conf.d/unmanaged.conf
[keyfile]
unmanaged-devices=type:wireguard

DNS 無法解析[編輯 | 編輯原始碼]

When tunneling all traffic through a WireGuard interface, the connection can become seemingly lost after a while or upon new connection. This could be caused by a network manager or DHCP client overwriting /etc/resolv.conf.

By default wg-quick uses resolvconf to register new DNS entries (from the DNS keyword in the configuration file). This will cause issues with network managers and DHCP clients that do not use resolvconf, as they will overwrite /etc/resolv.conf thus removing the DNS servers added by wg-quick.

The solution is to use networking software that supports resolvconf.

注意: Users of systemd-resolved should make sure that systemd-resolvconf is installed.

Users of NetworkManager should know that it does not use resolvconf by default. It is recommended to use systemd-resolved. If this is undesirable, install openresolv and configure NetworkManager to use it: NetworkManager#Use openresolv.

MTU 過低[編輯 | 編輯原始碼]

Due to too low MTU (lower than 1280), wg-quick may have failed to create the WireGuard interface. This can be solved by setting the MTU value in WireGuard configuration in Interface section on client.

foo.config
[Interface]
Address = 10.200.200.2/24
MTU = 1420
PrivateKey = PEER_FOO_PRIVATE_KEY
DNS = 10.200.200.1

密鑰長度或格式錯誤[編輯 | 編輯原始碼]

To avoid the following error, put the key value in the configuration file and not the path to the key file.

# 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 或防火牆後建立持久連接[編輯 | 編輯原始碼]

By default, WireGuard peers remain silent while they do not need to communicate, so peers located behind a NAT and/or firewall may be unreachable from other peers until they reach out to other peers themselves (or the connection may time out). Adding PersistentKeepalive = 25 to the [Peer] settings of a peer located behind a NAT and/or firewall can ensure that the connection remains open.

To temporarily set the persistent-keepalive setting via command line, run the following command:

# wg set wg0 peer public_key persistent-keepalive 25

循環路由[編輯 | 編輯原始碼]

Adding the endpoint IP to the allowed IPs list, the kernel will attempt to send handshakes to said device binding, rather than using the original route. This results in failed handshake attempts.

As a workaround, the correct route to the endpoint needs to be manually added using

# ip route add endpoint_ip via gateway dev network_interface

E.g. for peer B from above in a standard LAN setup:

# ip route add 203.0.113.102 via 192.168.0.1 dev eth0

To make this route persistent, the command can be added as PostUp = ip route ... to the [Interface] section of wg0.conf. However, on certain setups (e.g. using wg-quick@.service in combination with NetworkManager) this might fail on resume. Furthermore, this only works for a static network setup and fails if gateways or devices change (e.g. using Ethernet or Wi-Fi on a laptop).

Using NetworkManager, a more flexible solution is to start WireGuard using a dispatcher script. As root, create

/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

If not already running, start and enable NetworkManager-dispatcher.service. Also make sure that NetworkManager is not managing routes for wg0, see #Routes are periodically reset.

使用 systemd-networkd 時睡眠導致連接丟失[編輯 | 編輯原始碼]

本文或本章節可能需要合併到systemd-networkd

附註: Might reach more people on the dedicated page.(在 Talk:WireGuard#Merge proposal of Connection lost after sleep using systemd-networkd 中討論)

systemd version 253 introduced a change in how network interfaces are reconfigured when resuming from a suspended state[1]. In doing so, network connections managed by systemd-networkd will lose connection to the wireguard interface. Unless a kill switch is configured, this risks exposing the public IP address after resuming from suspend. To fix this, uncomment and change the value to no for ManageForeignRoutingPolicyRules in /etc/systemd/networkd.conf. [2]

參見[編輯 | 編輯原始碼]