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
总结:三大关键点
Table = off
:防止B的默认路由被劫持,避免失联。- 自定义路由表:精确控制A的流量走向,不影响B自身。
- 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%场景,建议收藏备用!
你也许感兴趣的:
- FFmpeg 视频处理速查表
- 最全列表: 80 多个 Linux 系统管理员必备的监控工具
- Linux程序员福音:在 Visual Studio 上用 C++ 写 Linux
- 安全专业人士最爱的19个GitHub开源项目
- 不能用谷歌翻译的痛,就用这些翻译神器来弥补吧
- 当GIF动图统治了客厅
- Java程序员必须知道的10款免费IDE编辑器
- Linux 下最为人熟知的归档/压缩工具
- .NET开发者必备的工具箱
- 10款最著名的代码(文本)编辑器
你对本文的反应是: