
机房 A 在云上,有公网地址。机房 B 在办公室的角落里,一台 NAS 藏在家用宽带后面,没有固定 IP,也进不来。两边的内网互相看不见,而你需要让它们像同一个交换机下的两台机器。
很多人第一反应是端口映射。家用宽带的公网地址会变,运营商还可能根本不给公网地址,映射做不成。WireGuard 解决的就是这个问题:让两端都主动往外连,谁也不需要被连。
下面这套配置在 Ubuntu 24.04(内核 6.8)与 Debian 12(内核 6.1)上跑过,wireguard-tools 版本 1.0.20210914,内核模块随内核自带,不需要装 DKMS 包。所有值都写全,照抄能通,但坑必须提前知道。
1. 先把拓扑定死
本文的拓扑是三节点:云端 VPS 作为中心,办公室 NAS 作为分支,一台笔记本作为出差时的移动端。中心节点必须有公网地址,其余两个都可以在 NAT 后面。
云端 VPS wg0: 10.66.0.1/24 公网 203.0.113.10:51820
办公室 NAS wg0: 10.66.0.2/24 内网 192.168.50.0/24
移动笔记本 wg0: 10.66.0.3/24 无固定地址
目标:三方互通,且 VPS 能访问 192.168.50.0/24
地址段选 10.66.0.0/24 是有意的。避开 10.0.0.0/24 和 192.168.0.0/24,是因为太多家用路由器默认占着这两段,撞上之后路由会指向错误的地方。这类冲突排查起来极费时间,因为现象看起来像「隧道不通」。
安装只有一条命令,官方源里就有,不需要加任何第三方仓库。Ubuntu 与 Debian 拿的是同一个包:
apt update
apt install -y wireguard-tools
wg --version
modinfo wireguard | head -5
第二条命令确认内核模块在。如果 modinfo 报找不到模块,说明内核太旧或被裁过,需要装 linux-modules-extra 对应的包。这一步不确认,后面 wg-quick up 会直接失败,报错信息还很不直观。
2. 生成三套密钥,别偷懒复制
WireGuard 用非对称密钥做身份,每台机器一对,公钥交换,私钥不出本机。三台机器必须三套密钥,把同一套复制到两台机器上,握手会互相顶掉,表现为「连上一秒又断」。
三台机器各执行一遍,不要图省事在一台上生成三套。路径固定放 /etc/wireguard,权限 600:
umask 077
wg genkey > /etc/wireguard/private.key
wg pubkey < /etc/wireguard/private.key > /etc/wireguard/public.key
wg genpsk > /etc/wireguard/preshared.key
cat /etc/wireguard/private.key
cat /etc/wireguard/public.key
umask 077 是关键。少了这一行,私钥会以 644 落盘,任何本地用户都能读走,等于把整条隧道送人。wireguard-tools 在读取时会检查权限,权限过宽直接拒绝启动,这是个好的设计。
预共享密钥(PSK)是可选的一层。它的价值不在加密强度,而在抗量子:将来某天公钥算法被攻破,PSK 仍然挡着。三台机器用同一个 PSK 即可,同样通过带外方式传过去。
3. 中心节点的配置
2026 年的 Linux 侧基本不用手写 wg0.conf 的 PostUp 了,但内核转发仍然要开。转发的开关和隧道是两件事,隧道通了不代表包能走过去。
cat > /etc/sysctl.d/99-wg.conf <<'EOF'
net.ipv4.ip_forward = 1
net.ipv4.conf.all.src_valid_mark = 1
EOF
sysctl --system
src_valid_mark 是给策略路由用的。在某些开启了 rp_filter 严格模式的发行版上,不回填这个值,回程包会被当成本地欺骗丢掉。
主配置文件只有三段,PrivateKey 换成 VPS 自己的那个值:
[Interface]
Address = 10.66.0.1/24
ListenPort = 51820
PrivateKey = <VPS 私钥>
MTU = 1420
[Peer]
# 办公室 NAS
PublicKey = <NAS 公钥>
PresharedKey = <PSK>
AllowedIPs = 10.66.0.2/32, 192.168.50.0/24
[Peer]
# 移动笔记本
PublicKey = <笔记本公钥>
PresharedKey = <PSK>
AllowedIPs = 10.66.0.3/32
注意 NAS 那一行的 AllowedIPs 写了两个网段。第一个是隧道地址,第二个是 NAS 背后的真实内网;少了第二个,VPS 知道 NAS 在哪,却不知道 192.168.50.0/24 该往哪儿送。
启动和开机自启是两条命令,只做第一条,重启之后隧道就没了。systemd 单元由 wg-quick 自动生成:
systemctl enable --now wg-quick@wg0
wg show
ip route show table all | grep 192.168.50
第二条命令的输出里应该出现一条指向 wg0 的路由。没有这条路由,说明 AllowedIPs 里的网段没被 wg-quick 装进路由表,问题在配置而不在防火墙。
4. 分支节点:NAT 后面那一端
NAS 侧不需要开转发,除非要让整个办公室都走隧道。它的配置更短,但有一个字段不能省:
[Interface]
Address = 10.66.0.2/24
PrivateKey = <NAS 私钥>
MTU = 1420
[Peer]
PublicKey = <VPS 公钥>
PresharedKey = <PSK>
Endpoint = 203.0.113.10:51820
AllowedIPs = 10.66.0.0/24
PersistentKeepalive = 25
PersistentKeepalive 是这段配置里唯一一个「看起来可省、实际不能省」的字段。NAT 设备会在几十秒到几分钟内丢弃没有流量的映射表项,隧道随即静默失效,而 wg show 仍然显示接口是 up 的。
25 秒是官方文档给的经验值,够短,也不至于打出无谓流量。只有 NAT 后面那一端需要写,中心节点不要写——中心节点写它,等于主动去猜一个自己不需要维持的映射。
如果希望整个办公室网段都能访问云端,把 AllowedIPs 改成 10.66.0.0/24, 192.168.50.0/24 并在 NAS 上开 ip_forward,同时在办公室路由器上加一条静态路由指向 NAS。这一步不是 WireGuard 的职责,是普通的路由工作,忘了它,办公室里的其他机器永远只能看着 NAS 一个人上网。
5. 四个必然踩到的坑
坑一:把 AllowedIPs 当防火墙用。它不是访问控制列表,它同时决定「哪些包进隧道」和「哪些源地址的包被接受」。写成 0.0.0.0/0 的客户端会把默认路由抢走,本机所有流量都进隧道,包括你正在用的 SSH,会话当场断。
坑二:MTU 1420 在 PPPoE 环境下偏大。典型表现是小包 ping 得通、SSH 能连上,但一执行 apt update 或拉镜像就卡住不动。把 Interface 段的 MTU 降到 1380,或者 1360,问题立刻消失。
坑三:只配了一边的 AllowedIPs。WireGuard 是双向选择,A 允许发给 B 的网段,B 也必须允许接收来自该网段的包。常见现象是单向通:A 能 ping B,B ping 不回 A,因为回程包在 B 的出站规则里被丢掉了。
坑四:防火墙的 FORWARD 链默认 DROP。握手成功,wg show 显示 latest handshake 只有几秒前,但 ping 不通。装了 Docker 的机器尤其容易中招,因为 Docker 会往 FORWARD 链里插自己的规则,顺序一变,你的 ACCEPT 就到了 DROP 后面。
iptables -I FORWARD -i wg0 -j ACCEPT
iptables -I FORWARD -o wg0 -j ACCEPT
iptables -t nat -A POSTROUTING -s 10.66.0.0/24 -o eth0 -j MASQUERADE
第三条只在需要让隧道内的地址访问公网时加。如果只是三方互访,MASQUERADE 是不必要的,加了反而会让日志里所有来源都变成 VPS 的地址。
6. 验收:分三层看
- 第一层看握手:wg show 里每个 peer 都要有 latest handshake,时间在 3 分钟内。没有握手,问题在密钥、Endpoint 或 UDP 端口被挡。
- 第二层看隧道地址:从 VPS ping 10.66.0.2,通说明隧道本身没问题。
- 第三层看背后网段:从 VPS ping 192.168.50.10,通说明 AllowedIPs 与转发都对。
- 第四层看大包:curl 一个几兆的文件,能完整下载说明 MTU 没问题。
四层里任何一层断了,排查方向都不同。最常见的误判是把第二层通过当成全部通过,然后花两小时去查防火墙,实际是 AllowedIPs 少写了一个网段。
7. 目录与权限,最后检查一遍
/etc/wireguard/
├── wg0.conf 600 root:root
├── private.key 600 root:root
├── public.key 644 root:root
└── preshared.key 600 root:root
wg-quick 会在启动时把配置里的密钥读进内核,配置文件本身留在磁盘上。权限错了不会报错,只会安静地留着风险,所以每次改完配置顺手看一眼 ls -l。
另外,配置里出现明文私钥是正常做法,不要为了「安全」去搞环境变量替换。WireGuard 的配置解析器不做变量展开,写进去就当成密钥内容的一部分,症状是握手一直失败,而日志里什么也没有。
写在最后
这套东西最反直觉的地方在于:它没有「连接」这个状态。WireGuard 不握手就没有会话,有包要发才握手,安静的时候它什么都不做。所以用它排查问题的思路,和用 OpenVPN 完全相反。
也正因为如此,它把大量工作交回给了操作系统本身:路由表、转发开关、防火墙链。这些是 Linux 三十年前就有的东西,比任何 VPN 自己的抽象都更可靠,也更难糊弄。大部分「WireGuard 不通」的问题,最后都落在 iptables 和 ip_route 上,而不在 WireGuard 里。
工具越薄,越考验你对底下的东西熟不熟。这不是缺点,是把复杂度从黑盒里搬到了明处。
你现在几台机器之间是怎么连的?有没有遇到过握手正常但大文件传到一半卡死的情况?

评论 (0)