构建内容
一个运行 WireGuard 的实例,为每个客户端分配一个私有 IPv4 地址、一个来自您自己的 /48 的路由 IPv6 地址,以及一个位于隧道内部的解析器,因此 DNS 查询不会走与其余流量不同的路径。防火墙在双向默认丢弃。仅对隧道接口启用转发,并且仅出站。
已在 AMS-01 的 R-4 上使用 Debian 13 进行测试。WireGuard 是单流且内核态的,因此在突破多个千兆位之前,更多核心对您没有帮助。更重要的是站点:选择离您实际位置最近的站点,因为您在这里增加的每一毫秒都会增加到每个数据包上。
开始之前
- 一个已部署的实例和通过 SSH 的 root 访问权限。
- 在控制面板中启用 IPv6 /48 附加功能。包含的 /64 可用于单个客户端,但单个 /64 中的每客户端子网意味着代理邻居发现,那是一种爱好而不是配置。
- 指向实例的主机名。下面的所有内容都使用
vpn.example.com。 - 这里的每个
2001:db8:地址都是文档空间。将前缀替换为实例页面上显示的前缀。
1. 软件包和内核设置
apt update && apt full-upgrade -y
apt install -y wireguard-tools nftables unbound qrencode
ip -br link最后一条命令会打印您的对外接口名称。在我们的 KVM 镜像上,它是 ens3;如果您的不同,请在下面所有地方替换它。现在进行内核设置:
cat > /etc/sysctl.d/99-wireguard.conf <<EOF
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
net.ipv6.conf.ens3.accept_ra = 2
net.ipv4.conf.all.rp_filter = 1
EOF
sysctl --systemaccept_ra = 2 这一行是人们容易忘记的。启用 IPv6 转发会使内核停止接受路由器通告,默认路由会在十分钟内消失,机器在 v6 上失去联系,但仍响应 v4。将其设置为 2 可以在转发主机上继续接受通告。
2. 密钥
install -d -m 700 /etc/wireguard
umask 077
wg genkey | tee /etc/wireguard/server.key | wg pubkey > /etc/wireguard/server.pub
wg genkey | tee /etc/wireguard/laptop.key | wg pubkey > /etc/wireguard/laptop.pub
wg genpsk > /etc/wireguard/laptop.psk预共享密钥在此构建中不是可选项。它不需要额外成本,每个配置中只有一行,它是使隧道不仅今天安全,而且面对现在记录流量以备将来解密的对手仍保持安全的区别。
3. 服务器接口
编写 /etc/wireguard/wg0.conf,在标记处粘贴密钥内容:
[Interface]
Address = 10.7.0.1/24, 2001:db8:1a2b:7::1/64
ListenPort = 51820
PrivateKey = <contents of /etc/wireguard/server.key>
MTU = 1420
[Peer]
# laptop
PublicKey = <contents of /etc/wireguard/laptop.pub>
PresharedKey = <contents of /etc/wireguard/laptop.psk>
AllowedIPs = 10.7.0.2/32, 2001:db8:1a2b:7::2/128在服务器端,AllowedIPs 是路由表,不是权限列表。为每个对等方提供其确切拥有的地址,不要更宽,否则两个客户端会争夺相同的路由,失败者将停止接收数据包。
chmod 600 /etc/wireguard/wg0.conf4. 隧道内的解析器
将客户端指向公共解析器会抵消很大一部分意义。Unbound 已经安装;给它 /etc/unbound/unbound.conf.d/tunnel.conf:
server:
interface: 10.7.0.1
interface: 2001:db8:1a2b:7::1
access-control: 10.7.0.0/24 allow
access-control: 2001:db8:1a2b:7::/64 allow
do-ip6: yes
prefetch: yes
hide-identity: yes
hide-version: yes
qname-minimisation: yesUnbound 在隧道存在之前将无法启动,因为那些地址尚未启动。正确排序而不是与之对抗:
systemctl edit unbound[Unit]
[email protected]
[email protected]5. 防火墙
完全替换 /etc/nftables.conf:
flush ruleset
table inet filter {
chain input {
type filter hook input priority filter; policy drop;
ct state established,related accept
ct state invalid drop
iif lo accept
ip protocol icmp accept
ip6 nexthdr icmpv6 accept
tcp dport 22 accept
udp dport 51820 accept
iifname "wg0" udp dport 53 accept
iifname "wg0" tcp dport 53 accept
}
chain forward {
type filter hook forward priority filter; policy drop;
ct state established,related accept
iifname "wg0" oifname "ens3" accept
iifname "wg0" oifname "wg0" drop
}
chain output {
type filter hook output priority filter; policy accept;
}
}
table ip nat {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 10.7.0.0/24 oifname "ens3" masquerade
}
}注意缺少什么:没有 IPv6 的 NAT 表。客户端使用自己的地址从您的 /48 出去,这正是首先采用 /48 的全部原因。iifname "wg0" oifname "wg0" drop 行阻止对等方相互访问,除非您有意构建网状网络,否则您需要这样。
systemctl enable --now nftables
nft list ruleset | head -206. 启动
systemctl enable --now wg-quick@wg0
systemctl restart unbound
wg show wg07. 客户端
[Interface]
PrivateKey = <contents of /etc/wireguard/laptop.key>
Address = 10.7.0.2/24, 2001:db8:1a2b:7::2/64
DNS = 10.7.0.1
MTU = 1420
[Peer]
PublicKey = <contents of /etc/wireguard/server.pub>
PresharedKey = <contents of /etc/wireguard/laptop.psk>
Endpoint = vpn.example.com:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25对于手机,在服务器上将其转换为二维码并拍摄终端:
qrencode -t ansiutf8 < /root/laptop.conf在 Debian 或 Ubuntu 客户端上,DNS = 行需要安装 openresolv,否则 wg-quick 会打印警告并静默保留旧解析器。这是隧道完美工作但泄露每个查询的最常见原因。
验证
四个检查,按顺序。任何失败都会告诉您回到哪个步骤。
# on the server, after connecting the client
wg show wg0 latest-handshakes
wg show wg0 transfer最近两分钟内的握手时间戳和两个方向的非零计数器意味着密码学和路由都正常。
# on the client
ping -c3 10.7.0.1
ping -c3 2001:db8:1a2b:7::1
dig @10.7.0.1 paragonvps.com AAAA +short第三条命令证明隧道解析器正在应答。如果超时,Unbound 在 wg0 存在之前启动;重新启动它。
最后一个检查是唯一证明您的流量从您认为的地方离开的检查,并且需要第二台机器。任何其他实例都可以,任何城市:
# on the second instance
nc -lv 9101
# on the client, tunnel up
curl -m5 -4 http://second.example.com:9101/
curl -m5 -6 http://second.example.com:9101/监听器打印每个连接的源地址。您的 v4 尝试应从 WireGuard 服务器到达,因为它已被伪装。v6 尝试应从客户端自己的隧道地址(在您的 /48 内)到达,未被修改,这就是 routed 的含义,而 proxied 则不是。
出错时
| 症状 | 原因 | 修复 |
|---|---|---|
| 握手成功,但没有流量通过 | 转发关闭,或转发链丢弃 | sysctl net.ipv4.ip_forward,然后重新阅读转发链 |
| 小请求正常,大下载挂起 | MTU 和路径发现 | 将两个配置都降低到 MTU = 1380 并重试 |
| IPv6 在启动后约十分钟失效 | 转发终止了路由器通告 | 在对外接口上设置 accept_ra = 2 |
| DNS 在隧道外解析 | 客户端忽略了 DNS = | 在客户端上安装 openresolv |
| 重启后一切消失 | 单元从未启用 | systemctl enable wg-quick@wg0 nftables unbound |
从这里,合理的下一步是在另一个区域添加第二个端点,以及一个监控堆栈,告诉您其中一个何时停止响应。两者都在 指南 中有说明;网络页面 解释了边缘在流量到达您之前对其进行的处理。