WireGuard 中转服务器搭建日记:从踩坑到完美解决方案

今天遇到一个上网问题。假设有三台电脑:

  • A(Windows客户端):在内网,不能直接上外网,可怜兮兮的。
  • B(Ubuntu中转服务器):也在内网,但能通过WireGuard连到C。
  • C(Ubuntu出口服务器):可以自由上网,是我们的”大门”。

目标很简单:让A通过B中转,最终走C出去上网,同时不影响B本身的远程管理(比如SSH)。听起来不难,但实际配置时踩了不少坑,今天就来记录一下。


初探WireGuard,中转服务器配置

目标:让B既能接受A的连接,又能把流量转给C

一开始我以为,只要在B上装个WireGuard,然后配两个[Peer](一个给A,一个给C)就行了。于是,我写了这样的配置:

# /etc/wireguard/wg0.conf
[Interface]
Address = 10.0.0.2/24
ListenPort = 51820
PrivateKey = <B的私钥>

[Peer]
# A的配置
PublicKey = <A的公钥>
AllowedIPs = 10.0.0.3/32

[Peer]
# C的配置
PublicKey = <C的公钥>
AllowedIPs = 0.0.0.0/0  # 所有流量都转给C
Endpoint = <C的公网IP>:51820
PersistentKeepalive = 25

看起来没问题,对吧?但重启WireGuard后,B服务器突然失联了!SSH直接断开,再也连不上!

元素周期表

坑1:AllowedIPs = 0.0.0.0/0 让 WireGuard 劫持了默认网卡eth0

原来,当B配置AllowedIPs = 0.0.0.0/0时,WireGuard会偷偷修改默认路由,把所有流量(包括SSH)都强行塞进wg0隧道。

结果

  • B的SSH流量也被送进WireGuard,但C并没有正确路由回来,导致B的管理连接直接挂了!
  • 唯一的恢复方法:通过VNC或物理控制台重启服务器,太坑了!

解决方案
在B的配置里加Table = off,禁止WireGuard乱改路由:

[Interface]
...
Table = off  # 关键!不让WireGuard动我的路由表

这样,B的默认路由就不会被劫持,SSH依然走物理网卡!


流量控制,确保A的流量全走C

目标:A的流量必须全部转发C,不能从B溜出去

虽然AllowedIPs = 0.0.0.0/0能让A的流量全走C,但B本身也可能有别的网络需求(比如更新软件包),不能把所有流量都塞给C。

于是,我决定用自定义路由表来精确控制:

# 创建自定义路由表
echo "100 wg_tunnel" >> /etc/iproute2/rt_tables

# 添加路由规则
ip route add default via 10.0.0.1 dev wg0 table wg_tunnel
ip rule add from 10.0.0.2 lookup wg_tunnel

原理

  • 来自10.0.0.2(B的WireGuard IP)的流量,走wg_tunnel路由表,默认网关指向C(10.0.0.1)。
  • B的其他流量(如SSH)依然走默认路由,不受影响。

坑2:C的AllowedIPs必须包含A的IP!

本以为这样就行了,但A还是无法上网。排查发现,C的配置里只允许B的IP(10.0.0.2),没加A的IP(10.0.0.3)

# C的配置(错误示范)
[Peer]
PublicKey = <B的公钥>
AllowedIPs = 10.0.0.2/32  # 漏了A的IP!

结果

  • A→B→C的流量能过去,但C的返回流量不知道该怎么回给A,直接丢了!

修复方法
在C的AllowedIPs里加上A的IP:

[Peer]
PublicKey = <B的公钥>
AllowedIPs = 10.0.0.2/32, 10.0.0.3/32  # 现在A和B都能通了!

最终稳定版配置

经过两天的折腾,终于搞定了稳定可用的方案。

B服务器的最终配置

[Interface]
Address = 10.0.0.2/24
ListenPort = 51820
PrivateKey = <B的私钥>
Table = off  # 禁止WireGuard改路由

# 自定义路由表(让A的流量走C)
//先要手工创建自定义路由表 wg_tunnel
// echo "100 wg_tunnel" >> /etc/iproute2/rt_tables 
PostUp = ip route add default via 10.0.0.1 dev wg0 table wg_tunnel
PostUp = ip rule add from 10.0.0.2 lookup wg_tunnel

[Peer]
# A的配置
PublicKey = <A的公钥>
AllowedIPs = 10.0.0.3/32

[Peer]
# C的配置
PublicKey = <C的公钥>
AllowedIPs = 0.0.0.0/0
Endpoint = <C的公网IP>:51820
PersistentKeepalive = 25


总结:三大关键点

  1. Table = off:防止B的默认路由被劫持,避免失联。
  2. 自定义路由表:精确控制A的流量走向,不影响B自身。
  3. C的AllowedIPs要包含A的IP:否则返回流量无法路由。

现在,A可以安心上网了,B的管理连接也稳如老狗。WireGuard虽然轻量,但配置灵活度极高,稍不注意就会踩坑。希望这篇博客能帮到有类似需求的你!

WireGuard 常用命令

1. 服务管理命令

# 启动WireGuard接口(wg0是配置文件名)
sudo wg-quick up wg0

# 停止WireGuard接口
sudo wg-quick down wg0

# 查看运行状态(类似ifconfig)
sudo wg show
# 示例输出:
# interface: wg0
#   public key: xxxxxxxxxxxxx
#   private key: (hidden)
#   listening port: 51820

2. 密钥生成与管理

# 生成私钥(保存好!)
wg genkey | tee privatekey

# 从私钥生成公钥
wg pubkey < privatekey > publickey

# 生成预共享密钥(可选,增强安全性)
wg genpsk > presharedkey

3. 连接状态监控

# 实时查看流量统计(每秒刷新)
watch -n 1 sudo wg show wg0 transfer

# 查看详细对等体信息
sudo wg show wg0 peers

# 检查最近握手时间(判断是否在线)
sudo wg show | grep "latest handshake"

4. 网络诊断命令

# 测试WireGuard接口连通性
ping 10.0.0.1  # 测试对端IP

# 检查路由表(确认流量走向)
ip route show table all | grep wg0

# 抓包分析(调试用)
sudo tcpdump -i wg0 -n

5. 配置文件操作

# 重载配置(不中断现有连接)
sudo wg syncconf wg0 <(wg-quick strip wg0)

# 检查配置语法
sudo wg-quick strip wg0 | wg -config /dev/stdin

小贴士:生产环境建议搭配systemd自动管理:

sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0

这些命令覆盖了WireGuard日常管理的90%场景,建议收藏备用!

你也许感兴趣的:

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注