WireGuard 全隧道可以把一台 Linux 服务器的 IPv4 出站流量交给另一台服务器统一转发,同时无需修改上层应用。真正容易出问题的不是隧道握手,而是默认路由切换后的 SSH 回程、NAT、防火墙和失败回滚。本文以“业务节点 A → 出口节点 B”为例,给出一套可验证、可撤销的配置方法。更多服务器维护内容可查看 VPS 教程与测评专题。

本文用于服务器互联、统一出口、测试环境隔离和远程运维等合法场景。请确保网络用途符合所在地法律、服务商条款及组织安全策略。

架构与适用环境

业务流量
   │
   ▼
节点 A(业务节点)
   │
   │ WireGuard 加密隧道
   ▼
节点 B(出口节点)
   │
   │ IPv4 Forward + NAT
   ▼
互联网

本文配置适用于:

  • Debian 12、Ubuntu 22.04/24.04,以及具备同等网络能力的 RHEL 系发行版;

  • KVM、VMware、Hyper-V 或独立服务器;

  • 两台服务器均拥有 root 或 sudo 权限;

  • B 有可用的 IPv4 公网出口,且可放行一个 UDP 端口;

  • A 的现有业务可以接受 IPv4 默认出口发生变化。

受限的 LXC、OpenVZ 容器可能没有创建 WireGuard 接口所需的 CAP_NET_ADMIN。另外,本文只接管 IPv4,不处理 IPv6。

下表使用变量表示不同服务器上的实际参数,部署时请按现场环境填写:

参数

示例值

WireGuard 接口

wg-exit

隧道网段

10.83.7.0/24

B 的隧道地址

10.83.7.1/24

A 的隧道地址

10.83.7.2/32

B 的监听端口

<WG_PORT>

B 的公网地址

<B_PUBLIC_IP>

隧道网段不能与 Docker、Kubernetes、现有 VPN 或局域网网段冲突。

修改前先看风险与回滚路径

本教程会修改内核转发、iptables 和 A 的默认路由,风险等级为 高。错误配置可能导致 SSH 中断,也可能影响 Docker 等依赖防火墙规则的服务。

开始前应完成以下准备:

  1. 为 A、B 各保留一个已登录的 SSH 会话,不要提前关闭。

  2. 确认云平台提供 Console、VNC 或串口等备用登录方式。

  3. 记录 ip -4 address、ip -4 route、ip -4 rule 和现有防火墙规则。

  4. 启动 A 的隧道前设置 180 秒自动回滚。

  5. 如果服务器运行 Docker,变更后单独验证容器网络。

还没有完成 SSH 密钥和基础防火墙配置的服务器,建议先阅读 Linux VPS 安全加固指南。

第一步:安装 WireGuard

Debian、Ubuntu:

sudo apt update
sudo apt install -y wireguard-tools iptables curl

RHEL、AlmaLinux、Rocky Linux:

sudo dnf install -y wireguard-tools iptables curl

在两台服务器上检查内核能力:

sudo modprobe wireguard
sudo ip link add wg-test type wireguard
sudo ip link delete wg-test

三条命令均无报错,说明当前环境能够创建 WireGuard 接口。

第二步:分别生成密钥

在 A、B 上分别执行:

sudo install -d -m 700 /etc/wireguard
umask 077
wg genkey | sudo tee /etc/wireguard/private.key | wg pubkey | sudo tee /etc/wireguard/public.key

读取各自公钥:

sudo cat /etc/wireguard/public.key

只交换公钥。private.key 和配置中的 PrivateKey 不能发送给其他人,也不应粘贴到聊天、邮件或工单。

第三步:配置出口节点 B

先确认 B 的公网出口网卡:

ip -4 route show default

假设结果中的网卡为 <B_WAN_INTERFACE>。开启 IPv4 转发:

echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-wireguard-forward.conf
sudo sysctl -p /etc/sysctl.d/99-wireguard-forward.conf

确认输出为 net.ipv4.ip_forward = 1,然后创建 /etc/wireguard/wg-exit.conf:

[Interface]
Address = 10.83.7.1/24
ListenPort = <WG_PORT>
PrivateKey = <B_PRIVATE_KEY>
MTU = 1420

PostUp = iptables -C FORWARD -i %i -j ACCEPT 2>/dev/null || iptables -A FORWARD -i %i -j ACCEPT; iptables -C FORWARD -o %i -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || iptables -A FORWARD -o %i -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -C POSTROUTING -o <B_WAN_INTERFACE> -j MASQUERADE 2>/dev/null || iptables -t nat -A POSTROUTING -o <B_WAN_INTERFACE> -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT 2>/dev/null || true; iptables -D FORWARD -o %i -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || true; iptables -t nat -D POSTROUTING -o <B_WAN_INTERFACE> -j MASQUERADE 2>/dev/null || true

[Peer]
PublicKey = <A_PUBLIC_KEY>
AllowedIPs = 10.83.7.2/32

配置中的占位符必须全部替换。<WG_PORT> 应是实际放行的 UDP 端口,<B_WAN_INTERFACE> 则必须是 B 当前的公网出口网卡。

设置权限并启动:

sudo chmod 600 /etc/wireguard/wg-exit.conf
sudo wg-quick up wg-exit
sudo wg show wg-exit

此时还没有来自 A 的握手属于正常现象。若 B 还配置了云安全组、UFW 或 firewalld,需要同步放行 <WG_PORT>/udp。

第四步:配置业务节点 A

先记录 A 的公网地址、默认网关和出口网卡:

ip -4 -o address show scope global
ip -4 route show default
ip -4 rule show

创建 /etc/wireguard/wg-exit.conf:

[Interface]
Address = 10.83.7.2/32
PrivateKey = <A_PRIVATE_KEY>
MTU = 1420
PostUp = ip -4 rule delete from <A_PUBLIC_IP>/32 lookup main priority 100 2>/dev/null || true; ip -4 rule add from <A_PUBLIC_IP>/32 lookup main priority 100
PostDown = ip -4 rule delete from <A_PUBLIC_IP>/32 lookup main priority 100 2>/dev/null || true

[Peer]
PublicKey = <B_PUBLIC_KEY>
Endpoint = <B_PUBLIC_IP>:<WG_PORT>
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

AllowedIPs = 0.0.0.0/0 会让 wg-quick 使用策略路由接管 IPv4 默认出口;PersistentKeepalive = 25 适合节点位于 NAT 或有状态防火墙之后、又需要长期保持可达的场景。WireGuard 官方同时指出,多数不经过 NAT 的节点并不需要 Keepalive。

这里额外加入源地址策略:以 A 原公网地址为源地址的回复继续查询主路由表,从而保留公网 SSH 的回程路径。如果某个业务程序显式绑定了 A 的公网地址,它也可能因此绕过隧道,部署后必须按实际业务验证。

设置文件权限:

sudo chmod 600 /etc/wireguard/wg-exit.conf

第五步:带自动回滚启动 A

先注册一个 180 秒后自动关闭隧道的临时任务:

sudo systemd-run --on-active=180 --unit=wireguard-rollback /usr/bin/wg-quick down wg-exit

再启动隧道:

sudo wg-quick up wg-exit

如果路由配置错误并导致 SSH 中断,计时结束后系统会自动执行 wg-quick down wg-exit。没有备用控制台时,不要省略这一步。

第六步:分层验证

不要只检查公网 IP。应按照“接口 → 握手 → 隧道地址 → 出口 → SSH → DNS → 业务”的顺序验证。

1. 检查接口与握手

在 A、B 上分别执行:

sudo wg show wg-exit

应看到非空的 latest handshake,并且 transfer 计数随测试增加。

2. 检查隧道地址

在 A 上执行:

ping -c 3 10.83.7.1

3. 检查 IPv4 出口

curl -4 --max-time 10 https://api.ipify.org
echo

返回值应为 B 的公网出口地址。

4. 检查路由和 DNS

ip -4 rule show
ip -4 route show table all
getent ahostsv4 wireguard.com

5. 新建 SSH 连接

保留原会话,在本地另开终端重新连接 A。只有新连接也能正常登录,才说明公网管理路径没有被破坏。

6. 验证真实业务

重新建立应用的长连接,再从应用本身检查出口和可用性。已经建立的 TCP 连接不会因为路由变化自动迁移到新路径。

全部验证通过后取消回滚,并设置两端开机自启:

sudo systemctl stop wireguard-rollback.timer
sudo systemctl reset-failed wireguard-rollback.service
sudo systemctl enable wg-quick@wg-exit

常见问题与最小排查路径

没有握手

依次检查:

sudo systemctl status wg-quick@wg-exit
sudo wg show wg-exit
sudo ss -lunp

常见原因是 B 的 UDP 端口未放行、Endpoint 写错、双方公钥填反,或者 B 的接口没有启动。

有握手但无法访问公网

重点检查 B:

sysctl net.ipv4.ip_forward
sudo iptables -S FORWARD
sudo iptables -t nat -S POSTROUTING
ip -4 route show default

通常是 ip_forward 未生效、NAT 出口网卡写错或 FORWARD 链被其他规则拦截。服务器使用 nftables、UFW、firewalld 或 Docker 时,不要同时盲目叠加多套防火墙规则。

能访问 IP,但域名解析失败

cat /etc/resolv.conf
getent ahostsv4 wireguard.com
resolvectl status

127.0.0.53 是常见的本地 systemd-resolved Stub,不应为它添加公网静态路由。优先修复系统原有 DNS 链路,不要直接覆盖 /etc/resolv.conf。

部分网站超时

先使用 tracepath 或逐步降低 MTU 验证 Path MTU 问题。可以从 1420 调整到 1380,每次只改一个值并重新测试,不建议直接套用极低 MTU。

IPv6 出口不一致

本文只配置 0.0.0.0/0,因此只接管 IPv4。A 的 IPv6 仍可能使用原出口。需要统一双栈出口时,必须同时设计 B 的 IPv6 转发、路由和防火墙,不能只在 A 上加入 ::/0。

完整回滚方案

回滚 A

sudo wg-quick down wg-exit
sudo systemctl disable wg-quick@wg-exit
sudo ip -4 rule delete from <A_PUBLIC_IP>/32 lookup main priority 100 2>/dev/null || true
sudo cp /etc/wireguard/wg-exit.conf /etc/wireguard/wg-exit.conf.backup
sudo rm -f /etc/wireguard/wg-exit.conf

重启依赖出口连接的应用,然后验证:

ip -4 route show
ip -4 rule show
curl -4 --max-time 10 https://api.ipify.org

回滚 B

sudo wg-quick down wg-exit
sudo systemctl disable wg-quick@wg-exit
sudo cp /etc/wireguard/wg-exit.conf /etc/wireguard/wg-exit.conf.backup
sudo rm -f /etc/wireguard/wg-exit.conf
sudo rm -f /etc/sysctl.d/99-wireguard-forward.conf
sudo sysctl --system

如果 B 运行 Docker,检查容器网络;发现异常再重启 Docker 和依赖应用:

sudo systemctl restart docker
docker compose up -d

最后确认原出口、防火墙和业务均已恢复。

结论

WireGuard 双服务器全隧道的核心不是写出两份配置,而是控制默认路由变化带来的影响。安全的实施顺序应是:先记录现状和备用入口,再配置 B 的转发与 NAT,最后在 A 上带自动回滚启用全隧道,并逐层验证握手、出口、SSH、DNS 和业务。

如果目标只是让多台设备互访,而不是统一默认出口,可以参考 Tailscale 与 Headscale 私有组网实践;如果需要从公网安全访问内网 Web 服务,可以继续阅读 Cloudflare Tunnel 发布内网服务指南。

参考资料