在云服务器使用 WireGuard 实现异地局域网互联

May 25, 2024 • 预计阅读时间 5 分钟

WireGuard 没有服务端和客户端的区别,每个设备都叫做端点(Peer),端点之间通过公钥互相验证后才能建立连接,安全性很高。

在云服务器配置 WireGuard

安装 WireGuard,根据你的系统参考官方的安装方法:

sudo apt install wireguard

生成密钥对的方法:

生成一个私钥,务必保存好不能泄露:

$ wg genkey

iKREcYbZMsJTbRecTO4yw3ObPWeROzyzaNjXXBPW2H0=

使用上一步的私钥生成公钥:

$ echo iKREcYbZMsJTbRecTO4yw3ObPWeROzyzaNjXXBPW2H0= | wg pubkey

FCvk8Z+ilYzu/eMbSzzjxJx8wKv+60R1ceCNfMD8tTo=

WireGuard 是创建一个 tun 设备(简单理解为虚拟网卡也可以)进行网络连接,所以需要使用一个和当前局域网内不一样的网段,如果不小心使用了相同的网段,会无法和局域网联通的故障。

创建一个网络配置文件,可以命名为 wg0.conf:

[Interface]
PrivateKey = iKREcYbZMsJTbRecTO4yw3ObPWeROzyzaNjXXBPW2H0=
Address = 172.16.1.1, fd01:72:16:1::1
ListenPort = 55189
MTU = 1280

172.16.1.1 就是云服务器的虚拟内网地址,这个地址段不能和系统中的 eth0 等网卡相同,否则会造成网络问题,推荐 wg0 使用一个完全不同类别的局域网段。

fd01:72:16:1::1 是虚拟的 IPv6 地址,如果当前的网络不支持 IPv6 就只使用 IPv4 的网络就行。

当然,也可以配置多个不同的网段,使用逗号隔开就行,比如 Address = 10.64.1.1, 172.16.1.1/24, fd01:72:16:1::1/64

MTU 设置为 1280 ,如果不配置默认就是 1420,CloudFlare 的 WARP 配置也是 1280。

关于 MTU 的值,对于 IPv6 网络会有一个 PMTU 黑洞的问题,如果 MTU 设置过大会造成 TCP 超时重传,现象就是在 IPv6 下网络访问慢,详情信息可以参考 CloudFlare 的这篇文章 Fixing an old hack - why we are bumping the IPv6 MTU。

加载这个配置文件,会自动创建一个 WireGuard 专用的虚拟网卡 wg0:

$ sudo wg-quick up wg0.conf

[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 172.16.1.1/24 dev wg0
[#] ip -6 address add fd01:72:16:1::1/64 dev wg0
[#] ip link set mtu 1280 up dev wg0

到这里,云服务器上就配置好了一个 Peer 。

还需要开启转发 /etc/sysctl.d/10-ip-forward.conf:

net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1

执行 sysctl -p /etc/sysctl.d/10-ip-forward.conf 使得配置生效。

在局域网终端配置 WireGuard

如果终端机器是 Mac ,那么可以直接从 App Store 下载到官方的 WireGuard 客户端

安装好 WireGuard 客户端后,同样需要先创建一个密钥对,然后编辑配置文件,添加云服务器的 Peer

[Interface]
PrivateKey = 6PIoPNSZkMYp9dneVks4aZxYKoXK0yjEapcAgMDUEHU=
Address = 172.16.1.2

[Peer]
PublicKey = FCvk8Z+ilYzu/eMbSzzjxJx8wKv+60R1ceCNfMD8tTo=
AllowedIPs = 172.16.1.1/24
Endpoint = 12.12.12.12:55189
PersistentKeepalive = 15

这里的 172.16.1.2 就是 Mac 端使用的虚拟内网地址,和云服务器同一个网段。

底下的 Peer 就是云服务器的公钥和它的虚拟内网地址,这里多了一个 Endpoint 配置,必须是云服务器的公网 IP 和 wg0 监听的端口号,这样在 Mac 上连接 172.16.1.1 的时候,就等同于连接到 Endpoint 指向的 IP 和端口,当然 Endpoint 也可以是域名,当使用域名的时候,需要在 Interface 里设置 DNS 地址。

PersistentKeepalive 是保持心跳的时间间隔,这里设置为 15s ,避免长时间没有连接导致连接断开。

在云服务器配置 Peer

在云服务器的 wg0.conf 里,还需要增加 Mac 端的 Peer,这样才可以互相访问:

[Interface]
PrivateKey = iKREcYbZMsJTbRecTO4yw3ObPWeROzyzaNjXXBPW2H0=
Address = 172.16.1.1
ListenPort = 55189

[Peer]
PublicKey = s5ZkNXzMblHnPWb3mRIbcNtnDzMqapJisbVaLL1ERGo=
AllowedIPs = 172.16.1.2/24
PersistentKeepalive = 15

Peer 的配置就是 Mac 端的公钥和虚拟内网 IP ,这里没有 Endpoint 的信息,因为 Mac 端没有固定 IP 和域名。

因为没有 Endpoint ,所以只能由 Mac 端主动发起连接到云服务器,然后云服务器才能和 Mac 端通讯。

多个 Peer 端的配置

如果还有第三、第四个 Peer 端,就需要在云服务器的 wg0.conf 里增加多个 [Peer] 区段。

...

[Peer]
PublicKey = AD9Jn6xokLmTBLSSkduUDir7OSJHN7egBjkLJANAGGs=
AllowedIPs = 172.16.1.3

[Peer]
PublicKey = AjhflDGDSk9a6jw/HE4dZBfCyKkN/NOYllRaag5BeAs=
AllowedIPs = 172.16.1.4

AllowedIPs 需要写成 172.16.1.4/32 而不能是 172.16.1.4/24 ,否则同一个局域网内的不同 Peer 会连不上云服务器。

常见问题

确保云服务器的防火墙放行了 wg0 的监听端口,WireGuard 使用的是 UDP 协议,设置端口放行规则的时候需要注意。

每个 Peer 的 [Interface] MTU 配置需要一致。

如果使用 IPv6 连接,需要确保云服务器和局域网内都已经正确配置了 IPv6 的支持。

关于安全性

使用 psk 可以提高和端点之间的连接安全性。

生成一个预共享密钥:

$ wg genpsk

JRGdWhHESe7MPDkwZDYZg3J5loOYo4bn9CPwfhMaQcw=

在端点的 [Peer] 中添加生成的 psk:

[Peer]
PresharedKey = JRGdWhHESe7MPDkwZDYZg3J5loOYo4bn9CPwfhMaQcw=

两边的端点都使用一样的 psk 才能正常连接。

https://www.wireguard.com/protocol/

通过中转实现异地局域网内机器互相访问

  • Peer C:一台云服务器,有公网 IP
  • Peer A:局域网机器,没有公网 IP
  • Peer B:局域网机器,没有公网 IP

Peer A 和 Peer B 是两台异地局域网内的机器并且不可能有公网 IP,现在需要它们可以互相访问。

这个场景需要通过 Peer C 做流量中转,才可以让 Peer A 和 Peer B 互相通讯。

关于 [Interface] 中的 Address:

  • 掩码使用 /32 或者直接指定明确的 IP 地址

关于 [Peer] 中的 AllowedIPs:

  • 用于指定哪些 IP 或者地址段可以通过这个 Peer
  • 对于终端端点,配置里的 Peer 是中转服务器,应该指定一个地址段,才能通过这个 Peer 中转访问到其他 Peer
  • 对于中转服务器,配置里面的 Peer 是单独的终端端点,应该指定它的虚拟 IP 地址,掩码是 /32 或者不写掩码

具体例子看下面的配置:

Peer C 是作为中转服务器,虚拟 IP 是 172.16.1.1:

[Interface]
PrivateKey = {PRIVATE_KEY}
Address = 172.16.1.1
ListenPort = 55189
MTU = 1280
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]
PublicKey = {PUBLIC_KEY}
AllowedIPs = 172.16.1.2

[Peer]
PublicKey = {PUBLIC_KEY}
AllowedIPs = 172.16.1.3

Peer A 是终端端点,虚拟 IP 是 172.16.1.2

[Interface]
PrivateKey = {PRIVATE_KEY}
Address = 172.16.1.2
MTU = 1280

[Peer]
PublicKey = {PUBLIC_KEY}
AllowedIPs = 172.16.1.0/24
Endpoint = {PEER_C_PUBLIC_IP}:55189
PersistentKeepalive = 15

Peer B 是终端端点,虚拟 IP 是 172.16.1.3

[Interface]
PrivateKey = {PRIVATE_KEY}
Address = 172.16.1.3
MTU = 1280

[Peer]
PublicKey = {PUBLIC_KEY}
AllowedIPs = 172.16.1.0/24
Endpoint = {PEER_C_PUBLIC_IP}:55189
PersistentKeepalive = 15

配置要点

  • Peer C 的 [Interface] 需要配置 IP 伪装,把 wg0 发出的流量都伪装成 eth0 的流量,才能达到中转的效果。
  • Peer A 和 Peer B 的 AllowedIPs ,必须都是 172.16.1.0/24 才能保证流量可以转发到 Peer C。

当 Peer A 在连接 Peer B 的时候,因为目标 IP 地址属于 172.16.1.0/24 的范围,所以流量会被转发给 Peer C,这样就实现了异地局域网的互相访问。

Peer A 在本地开启一个监听 HTTP 服务 0.0.0.0:1313 ,在 Peer B 就可以通过 http://172.16.1.2:1313 访问到 Peer A 开启的 HTTP 服务。

使用 systemd 创建自启动服务

适用于 Debain 以及使用 systemd 作为服务管理的 Linux 发行版。

  1. 创建一个 wg0 的服务配置:

    $ sudo systemctl enable [email protected]
    
    Created symlink /etc/systemd/system/multi-user.target.wants/[email protected] -> /lib/systemd/system/[email protected].
    
  2. 创建 wg0.conf 配置文件:

    wg0.conf 必须放在 /etc/wireguard/,因为 wireguard-tools 是读取这个路径下的 wgX.conf 配置。

    设置配置文件的访问权限为 600:

    sudo chmod 600 /etc/wireguard/wg0.conf
    
  3. 使修改后的配置文件后生效:

    sudo systemctl daemon-reload
    
  4. 启动 wg0:

    sudo systemctl start wg-quick@wg0
    
WireGuard
版权声明:如果转发请带上本文链接和注明来源。

lvv.me

iOS/macOS Developer

为 sudo 命令设置不一样的 $PATH

Clang 编译 Apple 全平台的 triple 和 sysroot 配置