WireGuard异地组网
Ubuntu 20.04 环境下WireGuard实现异地组网。
VPC环境
京东云(同VPC异子网)
# 内网IP
# 网关节点为:JD1
192.168.0.3 JD1(子网一,IPv4 CIDR:192.168.0.0/20)
192.168.16.3 JD2(子网二,IPv4 CIDR:192.168.16.0/24)
# 公网IP
114.67.83.188 JD1
114.67.108.200 JD2
# MTU
JD1 eth0 MTU = 1450
JD2 eth0 MTU = 1500
华为云(同VPC同子网)
# 内网IP
# 网关节点为:HW1
192.168.0.234 HW1(IPv4 CIDR:192.168.0.0/24)
192.168.0.98 HW2(IPv4 CIDR:192.168.0.0/24)
# 公网IP
123.60.142.90 HW1
123.60.152.146 HW2
# MTU
HW1 eth0 MTU = 1500
HW2 eth0 MTU = 1500
检查/etc/hosts
修改hostname并立即生效
$ hostname -F /etc/hostname
将hostname配到/etc/hosts中
$ hostname
192.168.0.3 JD1
192.168.16.3 JD2
192.168.0.234 HW1
192.168.0.98 HW2
安装WireGuard
apt update
apt install -y wireguard
# 子网网关节点才需要
sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward = 1/g' /etc/sysctl.conf
sed -i 's/#net.ipv6.conf.all.forwarding=1/net.ipv6.conf.all.forwarding = 1/g' /etc/sysctl.conf
sysctl -p
# 生成 私钥、公钥
$ wg genkey | sudo tee /etc/wireguard/privatekey | wg pubkey | sudo tee /etc/wireguard/publickey
# 查看 私钥、公钥
$ cat /etc/wireguard/privatekey
$ cat /etc/wireguard/publickey
# 查看 {eth0}
$ ip -o -4 route show to default | awk '{print $5}'
WireGuard配置
中继网关
Host Name:JD1
内网ip:192.168.0.3
外网ip:114.67.83.188
外网通信端口:20486
WireGuard监听端口:20486
$ nano /etc/wireguard/wg0.conf
[Interface]
Address = 192.168.0.3
MTU = 1370
SaveConfig = false
ListenPort = 20486
PrivateKey = {JD1_SERVER_PRIVATE_KEY}
PostUp = route add -net 192.168.16.0/24 gw 192.168.0.1 dev eth0
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
[Peer]
PublicKey = {HW1_SERVER_PUBLIC_KEY}
AllowedIPs = 192.168.0.234, 192.168.0.98
客户端
Host Name:HW1
内网ip:192.168.0.234
中继网关:114.67.83.188:20486
$ nano /etc/wireguard/wg0.conf
[Interface]
Address = 192.168.0.234
MTU = 1370
PrivateKey = {HW1_SERVER_PRIVATE_KEY}
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
[Peer]
PublicKey = {JD1_SERVER_PUBLIC_KEY}
Endpoint = 114.67.83.188:20486
AllowedIPs = 192.168.0.3, 192.168.16.3
PersistentKeepalive = 15
wstunnel
https://github.com/erebe/wstunnel
在udp受限的网络环境下,一种基于 WebSocket 的兼容方案。
WebSocket 是独立的、创建在 TCP 上的协议。
Websocket 通过HTTP/1.1 协议的101状态码进行握手。
下载并上传wstunnel-x64-linux
$ wget https://renlm.gitee.io/download/wstunnel/wstunnel-x64-linux
mv wstunnel-x64-linux /usr/local/bin/
chmod +x /usr/local/bin/wstunnel-x64-linux
ln -s /usr/local/bin/wstunnel-x64-linux /usr/local/bin/wstunnel
Server
Host Name:JD1
内网ip:192.168.0.3
外网ip:114.67.83.188
外网通信端口:20486
WireGuard监听端口:51820
$ vi /etc/systemd/system/wstunnel.service
$ systemctl enable wstunnel
$ systemctl start wstunnel
$ systemctl status wstunnel
$ systemctl restart wstunnel
$ systemctl stop wstunnel
[Unit]
Description=Tunnel WG UDP over websocket
After=network.target
[Service]
Type=simple
User=nobody
ExecStart=/usr/local/bin/wstunnel -q --server ws://0.0.0.0:20486 --restrictTo=127.0.0.1:51820
Restart=no
[Install]
WantedBy=multi-user.target
$ nano /etc/wireguard/wg0.conf
[Interface]
Address = 192.168.0.3
MTU = 1350
SaveConfig = false
ListenPort = 51820
PrivateKey = {JD1_SERVER_PRIVATE_KEY}
PostUp = route add -net 192.168.16.0/24 gw 192.168.0.1 dev eth0
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
[Peer]
PublicKey = {HW1_SERVER_PUBLIC_KEY}
AllowedIPs = 192.168.0.234, 192.168.0.98
Client
Host Name:HW1
内网ip:192.168.0.234
中继网关:114.67.83.188:20486
$ vi /etc/systemd/system/wstunnel.service
$ systemctl enable wstunnel
$ systemctl start wstunnel
$ systemctl status wstunnel
$ systemctl restart wstunnel
$ systemctl stop wstunnel
[Unit]
Description=Tunnel WG UDP over websocket
After=network.target
[Service]
Type=simple
User=nobody
ExecStart=/usr/local/bin/wstunnel -q --udp --udpTimeoutSec -1 -L 127.0.0.1:51820:127.0.0.1:51820 ws://114.67.83.188:20486
Restart=no
[Install]
WantedBy=multi-user.target
$ nano /etc/wireguard/wg0.conf
[Interface]
Address = 192.168.0.234
MTU = 1350
PrivateKey = {HW1_SERVER_PRIVATE_KEY}
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
[Peer]
PublicKey = {JD1_SERVER_PUBLIC_KEY}
Endpoint = 127.0.0.1:51820
AllowedIPs = 192.168.0.3, 192.168.16.3
PersistentKeepalive = 15
ufw防火墙
如果开启,则需要允许udp、tcp访问
WireGuard使用udp协议
wstunnel使用tcp协议
$ ufw status
$ ufw allow 20486/udp
$ ufw allow 20486/tcp
启动服务
检查安全组是否放行了外网访问端口(udp/tcp)
WireGuard使用udp协议(放行20486端口自定义UDP)
wstunnel使用tcp协议(放行20486端口自定义TCP)
$ chmod 600 /etc/wireguard/{privatekey,wg0.conf}
$ systemctl enable wg-quick@wg0.service
$ systemctl start wg-quick@wg0.service
$ systemctl status wg-quick@wg0.service
$ systemctl restart wg-quick@wg0.service
$ systemctl stop wg-quick@wg0.service
$ systemctl disable wg-quick@wg0.service
$ wg
局域网互通
相同子网(HW2)
添加静态路由,将访问ip转发到局域网内的WireGuard Server/Client
$ cd /etc/netplan/
$ netplan --debug apply
$ route -n
network:
version: 2
renderer: NetworkManager
ethernets:
eth0:
dhcp4: true
routes: # 路由表
- to: 192.168.0.3/32
via: 192.168.0.234 # 网关
- to: 192.168.16.3/32
via: 192.168.0.234 # 网关
不同子网(JD2)
JD1节点新增弹性网卡(Ubuntu 20.04)
多网卡节点作为 网关,每个网卡需分配在不同的子网
例:JD1作为 网关,绑定了两张网卡,可在两个子网之间作为通信的桥梁
网卡一(主):192.168.0.3,子网一 IPv4 CIDR:192.168.0.0/20
网卡二(副):192.168.16.6,子网二 IPv4 CIDR:192.168.16.0/24
$ ip a
$ vi /etc/netplan/eth1.yaml
network:
version: 2
renderer: networkd
ethernets:
eth1:
addresses: # 弹性网卡IP地址
- 192.168.16.6/24
dhcp4: no
routes: # 路由表
- to: 0.0.0.0/0
via: 192.168.16.1 # 默认网关
table: 1000
- to: 192.168.16.6
via: 0.0.0.0
scope: link
table: 1000
routing-policy: # 路由策略
- from: 192.168.16.6
table: 1000
$ netplan --debug apply
$ ping 192.168.0.3
$ ping 192.168.16.6
查询JD1主卡默认网关,将副卡路由到主卡的默认网关
$ route -n
放入WireGuard配置文件中,随WireGuard启动
$ route add -net 192.168.16.0/24 gw 192.168.0.1 dev eth0
JD2添加静态路由,将访问ip转发到局域网内的WireGuard Server/Client
即JD1副网卡的内网ip:192.168.16.6
$ cd /etc/netplan/
$ netplan --debug apply
$ route -n
# This is the network config written by 'subiquity'
network:
renderer: networkd
version: 2
ethernets:
eth0:
dhcp4: yes
dhcp-identifier: mac
routes: # 路由表
- to: 192.168.0.234/32
via: 192.168.16.6 # 网关
- to: 192.168.0.98/32
via: 192.168.16.6 # 网关
测试
云主机的安全组入站规则放行了ICMP协议后才能被ping
# JD1、JD2节点
$ ping 192.168.0.98
$ ping 192.168.0.234
# HW1、HW2节点
$ ping 192.168.0.3
$ ping 192.168.16.3
注意事项
MTU 设置
默认情况下,MTU会根据端点地址或系统默认路由自动确定 。
网络中各个节点MTU需要保持一致,JD1 eth0 MTU = 1450,其它机器都是1500,我们需要手动调整 。
同时在K8s集群中需要根据各个节点网卡的MTU参数对网络插件(Calico)的MTU值进行调整 。
如果使用wstunnel,因为额外包装了一层TCP协议,MTU值要再减20 。
详情请参考:Rancher中MTU 设置 。
配置项说明
[Interface]
定义当前节点的配置
Address
定义当前节点应该对哪个地址范围进行路由。
如果是常规的客户端,则将其设置为节点本身的单个 IP(使用 CIDR 指定,例如 192.168.168.10/32);
如果是中继服务器,则将其设置为可路由的子网范围。
例如:
常规客户端,只路由自身的流量:Address = 192.168.168.10/32
中继服务器,可以将流量转发到其他节点(peer):Address = 192.168.168.1/24
MTU
可选项,用于指定接口的最大传输单元MTU。
默认情况下,MTU会根据端点地址或系统默认路由自动确定。
如果有特殊需求,可以手工指定MTU的值,一般用于减少报文在传输过程中被分片。
SaveConfig
可选项,用于设置在关闭Wireguard接口时,是否将当前状态保存到配置文件中。
默认未配置,如果需要启用此功能,需要设置为true。
ListenPort
当前节点是中继服务器时,需要通过该参数指定端口来监听传入 网关 连接,默认端口号是51820。
常规客户端不需要此选项。
注意在系统防火墙和服务器安全组中放行该端口,大部分连不通都是端口原因。
PrivateKey
当前节点的私钥,所有节点(包括中继服务器)都必须设置。
不可与其他服务器共用。
PostUp
启动 接口之前运行的命令。这个选项可以指定多次,按顺序执行。
PostDown
停止 接口之后运行的命令。这个选项可以指定多次,按顺序执行。
[Peer]
定义对等节点(其他节点)的配置。可以有多个。
中继服务器必须将所有的节点(除了自身节点)定义为对等节点(peer)。
其他的节点只需定义中继服务器作为对等节点(peer)。
Endpoint
指定远端对等节点(peer)的公网地址。
PublicKey
对等节点(peer)的公钥,所有节点(包括中继服务器)都必须设置。
AllowedIPs
如果对等节点(peer)是常规的客户端,则将其设置为节点本身的单个 IP;
如果对等节点(peer)是中继服务器,则将其设置为可路由的子网范围。
可以使用,来指定多个 IP 或子网范围。
该字段也可以指定多次。
PersistentKeepalive
定期发送一个出站 ping 包来检查连通性,如果 IP 有变化,就会自动更新Endpoint。
维持连接是客户端(连接的发起方)的责任。