在云服务器使用 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 配置,必须是云服务器的公网 IPwg0 监听的端口号,这样在 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 配置