Blog
自建 WireGuard VPN:打通家里与云端网络
家里光猫在运营商后面,没有稳定公网 IP,端口映射也反复被回收。我想要的很具体:出差时能摸到家里 NAS;云上的几个小服务能和家里互通;手机流量下不要裸奔管理口。
WireGuard 我试过「每台设备直连家里」和「VPS 当枢纽」两种。最终选枢纽:家宽 NAT 再怎么变,只要家里有一条主动连出去的隧道,外网就能经 VPS 绕回来。这篇文章按架构决策写——先地址、再策略、最后才是配置细节。
决策一:枢纽拓扑,而不是全互联
全互联意味着每台 peer 都要知道其他 peer 的 Endpoint。家宽没有稳定入口时,笔记本和手机根本不知道「此刻家里的公网是谁」。
枢纽模型把问题收成一句:所有人只认识 VPS。VPS 有固定 IP、开 UDP 51820、负责转发。lab-core 主动连出去,挂 PersistentKeepalive = 25,运营商 NAT 映射不会冷掉。
代价是多一跳延迟,以及 VPS 成为单点。家庭场景我接受:VPS 月费几块到几十,比和 CGNAT 搏斗便宜。以后要高可用,再考虑双 hub 或 Headscale,现在不预支复杂度。
有人问为什么不直接上商业组网产品。可以,但我想把路由和密钥握在自己配置文件里,坏了能用文本解释清楚。学习成本换的是可审计,不是情怀表演。
决策二:地址表先于任何 conf 文件
没有地址表,后面全是玄学。我在纸上先画:
| 角色 | 隧道地址 | 备注 |
|---|---|---|
| VPS hub | 10.66.0.1/24 | 公网入口,开转发 |
| 家里 lab-core | 10.66.0.10 | 主动连 hub,可带局域网路由 |
| 笔记本 | 10.66.0.20 | 出差用 |
| 手机 | 10.66.0.30 | 随时改配置 |
局域网仍是 192.168.1.0/24。隧道段和家里局域网不要重叠,否则路由表会跟你打架。我见过有人隧道也用 192.168.1.0/24,ping 通假目标、真服务永远超时,查了一整天。
密钥每台一对,私钥只留在本机。生成时:
umask 077
wg genkey | tee /etc/wireguard/privatekey | wg pubkey > /etc/wireguard/publickey
公钥进 git 可以,私钥进 git 等于没私钥。地址表和公钥对照表贴在笔记首页。
决策三:AllowedIPs 是策略,不是填空
很多人把 AllowedIPs 当成「对方是谁」的标签。它其实是两件事叠在一起:哪些源地址允许从这条 peer 进来,以及本机要把哪些目的网段丢进这条隧道。
VPS 上 lab-core 那一段 peer:
[Peer]
# lab-core
PublicKey = <lab-pubkey>
AllowedIPs = 10.66.0.10/32, 192.168.1.0/24
含义是:认 lab-core 的隧道 IP;同时,发往家里局域网的包也交给它。手机如果只写 10.66.0.0/24,就只进隧道网段;要摸 192.168.1.10,得加上局域网段,并且回程要想清楚。
回程我更常用 lab-core 做 SNAT:家里设备看到的源是 lab-core 局域网地址,不用在每台 IoT 上教默认路由。精确放行比 AllowedIPs = 0.0.0.0/0 省心——后者一开,DNS 和分流立刻变成另一场战争,还容易误判「WireGuard 坏了」。
决策四:转发与伪装写在接口生命周期里
枢纽 /etc/wireguard/wg0.conf 骨架:
[Interface]
Address = 10.66.0.1/24
ListenPort = 51820
PrivateKey = <hub-private>
PostUp = sysctl -w net.ipv4.ip_forward=1
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT
PostUp = iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
把转发和 NAT 绑在 wg-quick 的 PostUp/PostDown,重启隧道规则跟着走,少一种「人肉 iptables 忘了删」的漂移。云厂商安全组要单独放 51820/udp,和系统防火墙是两道闸,别只信一边。
家里那端 Endpoint 指 VPS,PersistentKeepalive = 25 写死。移动网络切换时偶发握手变慢,keepalive 比你手动 wg 敲一遍可靠。
分阶段上线:先 peer,再局域网
第一周我只验证 peer 之间 ping 10.66.0.x。wg show 里能看到 latest handshake,再谈访问 192.168.1.10。
握手对不上时,我按固定顺序想,而不是乱改配置:
wg show有没有 handshake——没有就是 UDP 不通或密钥错。- VPS 安全组 / 云防火墙有没有 51820/udp。
- 两端公钥是否拷反、是否多了换行空格。
- 时钟差是否离谱(偶发),先
timedatectl。 - AllowedIPs 是否把回程吞掉。
MTU 也常见:某些网络 1420 比默认更稳,手机热点下尤其明显。表现是「握手有了,大包传不动」。先小包 ping,再 scp 一个大文件,能把问题拆开。
和 Tunnel 的边界写进架构说明
Cloudflare Tunnel 负责「把某个 HTTP 服务安全露到公网」;WireGuard 负责「我就是要进内网」。两者不是互相替代:Tunnel 不给你任意端口的二层感,WG 不帮你做全球 Anycast 和 WAF。
Peer 超过七八个,手写 conf 会烦。可以上 wg-easy 或以后迁 Headscale,家庭规模我仍手写,配置进 git(去掉私钥)。私钥用密码管理器或仅本机权限文件,不进仓库、不进聊天记录。
架构文档首页只保留三样:地址表、每台公钥指纹(或短前缀)、AllowedIPs 意图说明(「仅隧道」还是「含局域网」)。新人加设备时照表填,比翻一堆 conf 注释安全。
把枢纽当「网络胶水」,而不是「第二个全家桶路由器」。地址表清晰、keepalive 稳定、AllowedIPs 克制,这张网就能用很久。决策写清楚了,配置只是附录。