很多做开发的人迟早会碰到一个问题:你在公司或者家里有台机器,外面想访问,但你没有公网 IP。这个问题的解决方案不少,我之前试过 frp、试过 ZeroTier,也用过一段时间 Tailscale。最后折腾来折腾去,还是自己用 WireGuard 搭了一套,稳定跑了大半年没出过事。今天把整个过程和踩过的坑写下来,给有同样需求的人参考。
为什么最后选了 WireGuard
先说我之前用过的几个方案各自的问题。
frp 需要一台有公网 IP 的服务器做中转,配置项多,每次加一个端口就要改一遍配置文件,而且 frp 本身走的是明文隧道,不加密的话心里不踏实。
ZeroTier 和 Tailscale 属于同一类产品,优点是开箱即用,缺点是依赖它们的服务器做打洞协调。如果打洞失败就会走中转,延迟直接飙到 200ms 以上。而且 Tailscale 免费版只支持 100 台设备,对于团队来说不太够用。
WireGuard 是 Linux 内核原生支持的 VPN 协议,代码量只有几千行,比 OpenVPN 轻量得多。它走的是 UDP,延迟低,配置也比 frp 简单。最重要的一点:它是点对点的,不需要中转服务器,只要两端能通 UDP 就行。
我的环境
- 服务端:一台阿里云 ECS(CentOS 9,有公网 IP)
- 客户端:家里一台 Ubuntu 22.04 的开发机,以及一台 Windows 笔记本
- 目的:在外面能直接 SSH 到家里的机器,访问家里的 Web 服务
服务端配置
安装 WireGuard:
# CentOS/RHEL
sudo dnf install -y epel-release elrepo-release
sudo dnf install -y kmod-wireguard wireguard-tools
# Ubuntu/Debian
sudo apt install -y wireguard
生成密钥对:
wg genkey | tee /etc/wireguard/server_private.key | wg pubkey > /etc/wireguard/server_public.key
chmod 600 /etc/wireguard/server_private.key
编辑配置文件 /etc/wireguard/wg0.conf:
[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = <服务端私钥>
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
[Peer]
PublicKey = <客户端公钥>
AllowedIPs = 10.0.0.2/32
启动:
sudo systemctl enable --now wg-quick@wg0
客户端配置
同样生成密钥对,然后编辑 /etc/wireguard/wg0.conf:
[Interface]
Address = 10.0.0.2/24
PrivateKey = <客户端私钥>
DNS = 8.8.8.8
[Peer]
PublicKey = <服务端公钥>
Endpoint = <服务端公网IP>:51820
AllowedIPs = 10.0.0.0/24
PersistentKeepalive = 25
启动后用 ping 10.0.0.1 测试,通了就说明隧道建立成功。
踩过的几个坑
坑一:IP 转发没开
这是我第一次配的时候犯的低级错误。服务端必须开启 IP 转发,否则客户端能 ping 通服务端,但服务端不会帮你转发流量。
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p
坑二:防火墙忘了放行 UDP 51820
WireGuard 走的是 UDP 协议,不是 TCP。我一开始在阿里云安全组里只放了 TCP 51820,死活连不上,排查了半小时才发现。
firewall-cmd --permanent --add-port=51820/udp
firewall-cmd --reload
阿里云控制台的安全组也要同步加规则。
坑三:MTU 问题导致部分网站打不开
WireGuard 默认 MTU 是 1420,但如果你的物理网络 MTU 更小(比如 PPPoE 拨号一般是 1492),隧道套隧道就会超限。表现为 ping 通但 HTTP 请求卡住。
解决办法是在 wg0.conf 的 [Interface] 段加一行:
MTU = 1280
1280 是一个保守值,基本不会出问题。如果你网络环境干净,可以试 1380 或 1400。
坑四:NAT 后面的客户端要加 PersistentKeepalive
如果你的客户端在 NAT 路由器后面(家里网络基本都是),不加 PersistentKeepalive = 25 的话,过几分钟 UDP 映射就会被路由器回收,隧道就断了。这个值表示每 25 秒发一次心跳包,保持 NAT 映射活着。
坑五:Windows 客户端的 DNS 不生效
Windows 版 WireGuard 有个已知问题:配置里的 DNS = 8.8.8.8 有时候不生效,导致隧道通了但域名解析还是走本地 DNS。解决办法是用 WireGuard 安装时自带的 resolve-dns.ps1 脚本,或者在连接后手动改一下网络适配器的 DNS 设置。
最终效果
跑了大半年,延迟稳定在 30-50ms(取决于你和服务器的物理距离),比 Tailscale 打洞失败时的中转方案好太多。SSH 连接、Web 服务访问、文件传输都没问题。唯一需要注意的是 WireGuard 本身不提供认证机制,安全性完全依赖密钥。所以私钥文件权限一定要设好(chmod 600),不要泄露。
如果你的需求只是简单的内网穿透,不需要跑全设备的 VPN,WireGuard 是目前最轻量、最稳定的方案之一。配置过程确实比 Tailscale 多了几步,但换来的是完全自主可控,不用担心第三方服务挂掉或者收费涨价。
评论一下?