跳转至

WireGuard 服务器端配置指南

状态: ✅ 已完成

客户端信息

  • 客户端公钥: GGPfzpN4Mf5acZrsJmQf8cRO93uUoJhsAdIitvv2mmM=
  • 虚拟网络 IP: 192.168.0.100/32
  • 客户端类型: 动态 IP 客户端(需要 PersistentKeepalive)

添加客户端 Peer 配置

步骤 1: 编辑服务器端配置文件

在每个服务器上(cab4, cab5, cab6),编辑 WireGuard 配置文件:

sudo nano /etc/wireguard/wg0.conf

步骤 2: 添加客户端 Peer 配置

在配置文件的 [Peer] 部分添加以下内容:

[Peer]
PublicKey = GGPfzpN4Mf5acZrsJmQf8cRO93uUoJhsAdIitvv2mmM=
AllowedIPs = 192.168.0.100/32
# 注意:客户端是动态IP,不需要配置 Endpoint

步骤 3: 重启 WireGuard 服务

sudo systemctl restart wg-quick@wg0

步骤 4: 验证配置

# 查看 WireGuard 状态
sudo wg show

# 应该能看到新添加的 peer,显示类似:
# peer: GGPfzpN4Mf5acZrsJmQf8cRO93uUoJhsAdIitvv2mmM=
#   allowed ips: 192.168.0.100/32

nftables 防火墙配置(已验证方案)

关键配置要求

服务器使用 nftables 防火墙时,必须drop 规则之前添加 WireGuard 相关规则,否则连接无法建立。

已验证的配置方案(使用 handle 9)

重要:在所有服务器上,handle 9 对应 ct state established,related accept,这个位置稳定且安全。

PostUp 配置(单行格式)

PostUp = nft add table ip nat; nft add chain ip nat postrouting { type nat hook postrouting priority 100 \; }; nft add rule ip nat postrouting oifname "eno1" masquerade; nft add table ip filter; nft add chain ip filter forward { type filter hook forward priority 0 \; }; nft add rule ip filter forward iifname "wg0" accept; nft add rule ip filter forward oifname "eno1" ct state related,established accept; nft add rule ip filter forward oifname "eno1" ip saddr 192.168.0.0/24 accept; nft -a list chain inet filter input 2>/dev/null | grep "udp dport 51820" | awk '{print $NF}' | xargs -r -I {} nft delete rule inet filter input handle {} 2>/dev/null || true; nft -a list chain inet filter input 2>/dev/null | grep "iifname \"wg0\"" | awk '{print $NF}' | xargs -r -I {} nft delete rule inet filter input handle {} 2>/dev/null || true; nft insert rule inet filter input handle 9 udp dport 51820 accept; nft insert rule inet filter input handle 9 iifname "wg0" accept

PostDown 配置(单行格式)

PostDown = nft delete table ip nat; nft delete table ip filter; nft -a list chain inet filter input 2>/dev/null | grep "udp dport 51820" | awk '{print $NF}' | xargs -r -I {} nft delete rule inet filter input handle {} 2>/dev/null || true; nft -a list chain inet filter input 2>/dev/null | grep "iifname \"wg0\"" | awk '{print $NF}' | xargs -r -I {} nft delete rule inet filter input handle {} 2>/dev/null || true

规则执行顺序

配置后,规则执行顺序应该是:

1. iif "lo" accept (handle 8)
2. udp dport 51820 accept ← WireGuard 端口规则
3. iifname "wg0" accept ← WireGuard 接口规则
4. ct state established,related accept (handle 9)
5. ... 其他规则
6. drop (handle 24/25)

验证防火墙规则

# 检查规则是否正确添加(推荐命令)
sudo nft list chain inet filter input | grep -E "(51820|wg0|established)" -A 1 -B 1

# 应该看到:
# udp dport 51820 accept
# iifname "wg0" accept
# ct state established,related accept

检测防火墙设置效果

配置完成后,使用以下命令检测防火墙规则是否正确:

# 检测防火墙规则位置和效果
sudo nft list chain inet filter input | grep -E "(51820|wg0|established)" -A 1 -B 1

预期输出示例

        iif "lo" accept
        udp dport 51820 accept
        iifname "wg0" accept
        ct state established,related accept
        ct state invalid drop

检查要点

  • udp dport 51820 accept 必须在 ct state established,related accept 之前
  • iifname "wg0" accept 必须在 ct state established,related accept 之前
  • ✅ 两个规则都必须在 drop 规则之前
  • ❌ 如果规则在 drop 之后,说明配置失败,需要重新配置

手动添加规则(临时测试)

如果需要临时测试,可以手动添加:

# 在 handle 9 之前插入(推荐,更稳定)
sudo nft insert rule inet filter input handle 9 udp dport 51820 accept
sudo nft insert rule inet filter input handle 9 iifname "wg0" accept

重要注意事项

  1. 规则顺序至关重要:WireGuard 规则必须在 drop 之前,否则流量会被丢弃
  2. 使用 handle 9 更稳定handle 9 在所有服务器上都是 established,related accept,比 drop handle 更稳定
  3. 删除重复规则:PostUp 中先删除可能存在的重复规则,避免规则累积
  4. PostDown 清理:确保 PostDown 删除添加的规则,避免重启后规则重复

完整服务器端配置示例

cab4 服务器配置示例

[Interface]
PrivateKey = <服务器私钥>
Address = 192.168.0.1/24, 192.168.0.101/32
ListenPort = 51820
PostUp = nft add table ip nat; nft add chain ip nat postrouting { type nat hook postrouting priority 100 \; }; nft add rule ip nat postrouting oifname "eno1" masquerade; nft add table ip filter; nft add chain ip filter forward { type filter hook forward priority 0 \; }; nft add rule ip filter forward iifname "wg0" accept; nft add rule ip filter forward oifname "eno1" ct state related,established accept; nft add rule ip filter forward oifname "eno1" ip saddr 192.168.0.0/24 accept; nft -a list chain inet filter input 2>/dev/null | grep "udp dport 51820" | awk '{print $NF}' | xargs -r -I {} nft delete rule inet filter input handle {} 2>/dev/null || true; nft -a list chain inet filter input 2>/dev/null | grep "iifname \"wg0\"" | awk '{print $NF}' | xargs -r -I {} nft delete rule inet filter input handle {} 2>/dev/null || true; nft insert rule inet filter input handle 9 udp dport 51820 accept; nft insert rule inet filter input handle 9 iifname "wg0" accept
PostDown = nft delete table ip nat; nft delete table ip filter; nft -a list chain inet filter input 2>/dev/null | grep "udp dport 51820" | awk '{print $NF}' | xargs -r -I {} nft delete rule inet filter input handle {} 2>/dev/null || true; nft -a list chain inet filter input 2>/dev/null | grep "iifname \"wg0\"" | awk '{print $NF}' | xargs -r -I {} nft delete rule inet filter input handle {} 2>/dev/null || true

[Peer]
# 其他客户端...
PublicKey = <其他客户端公钥>
AllowedIPs = <其他客户端IP>/32

[Peer]
# 新客户端:pengxin
PublicKey = GGPfzpN4Mf5acZrsJmQf8cRO93uUoJhsAdIitvv2mmM=
AllowedIPs = 192.168.0.100/32

cab5 服务器配置示例

[Interface]
PrivateKey = <服务器私钥>
Address = 192.168.0.2/24, 192.168.0.102/32
ListenPort = 51820
PostUp = nft add table ip nat; nft add chain ip nat postrouting { type nat hook postrouting priority 100 \; }; nft add rule ip nat postrouting oifname "eno1" masquerade; nft add table ip filter; nft add chain ip filter forward { type filter hook forward priority 0 \; }; nft add rule ip filter forward iifname "wg0" accept; nft add rule ip filter forward oifname "eno1" ct state related,established accept; nft add rule ip filter forward oifname "eno1" ip saddr 192.168.0.0/24 accept; nft -a list chain inet filter input 2>/dev/null | grep "udp dport 51820" | awk '{print $NF}' | xargs -r -I {} nft delete rule inet filter input handle {} 2>/dev/null || true; nft -a list chain inet filter input 2>/dev/null | grep "iifname \"wg0\"" | awk '{print $NF}' | xargs -r -I {} nft delete rule inet filter input handle {} 2>/dev/null || true; nft insert rule inet filter input handle 9 udp dport 51820 accept; nft insert rule inet filter input handle 9 iifname "wg0" accept
PostDown = nft delete table ip nat; nft delete table ip filter; nft -a list chain inet filter input 2>/dev/null | grep "udp dport 51820" | awk '{print $NF}' | xargs -r -I {} nft delete rule inet filter input handle {} 2>/dev/null || true; nft -a list chain inet filter input 2>/dev/null | grep "iifname \"wg0\"" | awk '{print $NF}' | xargs -r -I {} nft delete rule inet filter input handle {} 2>/dev/null || true

[Peer]
# 其他客户端...
PublicKey = <其他客户端公钥>
AllowedIPs = <其他客户端IP>/32

[Peer]
# 新客户端:pengxin
PublicKey = GGPfzpN4Mf5acZrsJmQf8cRO93uUoJhsAdIitvv2mmM=
AllowedIPs = 192.168.0.100/32

故障排查

常见问题诊断

1. 客户端显示 0 B received

症状:客户端 wg show 显示所有 peer 都是 0 B received, XXX B sent

原因:服务器端防火墙规则缺失或位置错误

解决方案

# 检查服务器端防火墙规则
sudo nft list chain inet filter input | grep -E "(51820|wg0|drop)"

# 如果缺少规则,手动添加
sudo nft insert rule inet filter input handle 9 udp dport 51820 accept
sudo nft insert rule inet filter input handle 9 iifname "wg0" accept

# 验证规则位置
sudo nft list chain inet filter input | grep -E "(51820|wg0|established)" -A 1 -B 1

2. 规则在 drop 之后(无效)

症状:规则存在但连接不通

原因:规则添加在 drop 之后,永远不会被执行

解决方案

# 检查规则位置
sudo nft list chain inet filter input | grep -E "(51820|wg0|drop)" -A 1 -B 1

# 如果规则在 drop 之后,需要删除并重新添加
# 先删除
sudo nft -a list chain inet filter input | grep "udp dport 51820" | awk '{print $NF}' | xargs -I {} sudo nft delete rule inet filter input handle {}
sudo nft -a list chain inet filter input | grep "iifname \"wg0\"" | awk '{print $NF}' | xargs -I {} sudo nft delete rule inet filter input handle {}

# 在 handle 9 之前重新添加
sudo nft insert rule inet filter input handle 9 udp dport 51820 accept
sudo nft insert rule inet filter input handle 9 iifname "wg0" accept

3. 规则重复累积

症状:每次重启后规则重复添加

原因:PostDown 没有正确删除规则

解决方案

  • 确保 PostDown 包含删除规则的命令
  • 或者在 PostUp 中先删除可能存在的规则

快速命令参考

WireGuard 管理

# 查看配置
sudo cat /etc/wireguard/wg0.conf

# 查看状态
sudo wg show

# 重启服务
sudo systemctl restart wg-quick@wg0

# 检查端口
sudo ss -ulnp | grep 51820

nftables 防火墙管理

# 查看 input 链
sudo nft list chain inet filter input

# 查看带 handle 的规则
sudo nft -a list chain inet filter input

# 查找特定规则
sudo nft list chain inet filter input | grep -E "(51820|wg0)"

# 手动添加规则(在 handle 9 之前)
sudo nft insert rule inet filter input handle 9 udp dport 51820 accept
sudo nft insert rule inet filter input handle 9 iifname "wg0" accept

# 删除规则(需要知道 handle)
sudo nft -a list chain inet filter input | grep "udp dport 51820" | awk '{print $NF}' | xargs -I {} sudo nft delete rule inet filter input handle {}

客户端配置信息

macOS 安装 WireGuard

方法一:使用 Homebrew(推荐)

# 安装 WireGuard 工具
brew install wireguard-tools

# 验证安装
wg --version

方法二:使用 Mac App Store

  1. 打开 Mac App Store
  2. 搜索 "WireGuard"
  3. 安装官方 WireGuard 应用

注意:使用 Mac App Store 版本时,配置文件的路径和启动方式可能不同。

生成密钥对

# 创建配置目录
mkdir -p ~/.wireguard

# 生成密钥对
cd ~/.wireguard
wg genkey | tee privatekey | wg pubkey > publickey

# 查看公钥(需要发送给服务器管理员)
cat publickey

客户端配置示例

[Interface]
PrivateKey = <客户端私钥>
Address = 192.168.0.100/32

[Peer]
# cab4
PublicKey = jLSYsezLxQ2n4uuTvCJYIktBNy1RiPLzxr0WrjiYFiQ=
Endpoint = 167.114.208.35:51820
AllowedIPs = 192.168.0.1/32, 192.168.0.101/32
PersistentKeepalive = 25

[Peer]
# cab5
PublicKey = s1LYdLBpNsb6NmCI3csTPD4jxms/IiEhF50WL9puvGI=
Endpoint = 167.114.208.45:51820
AllowedIPs = 192.168.0.2/32, 192.168.0.102/32
PersistentKeepalive = 25

客户端管理命令(macOS)

# 启动 WireGuard
sudo wg-quick up ~/.wireguard/wg0.conf

# 停止 WireGuard
sudo wg-quick down wg0
# 或
sudo wg-quick down utun6

# 查看状态
sudo wg show

重要提示

  • 动态 IP 客户端:客户端 IP 不固定,使用 PersistentKeepalive = 25 保持连接
  • 服务器端不需要 Endpoint:客户端配置中需要指定服务器的 Endpoint,但服务器端不需要配置客户端的 Endpoint
  • macOS 接口名称:macOS 上 WireGuard 接口可能是 utun6 而不是 wg0,这是正常的