全端口转发规则会吞掉你自己的 WireGuard 监听
宽泛的转发规则会吞掉网关自身的 WireGuard 与 SSH 监听。选择窄规则或独立的公网地址,然后测试控制通路。
一台公网网关已经在 UDP 51820 上运行 WireGuard、在 22 端口上运行 SSH,并运行一个必须能从互联网访问的应用。诱人的规则把每个端口都转发给 peer,然后就宣布完工。在 WireGuard 网关上,这条规则会捕获隧道自身的传输,把你锁在终止隧道的机器之外。对外发布是一项带控制平面例外的路由决策,而不是一行 DNAT。
公网入口与隧道入口,只能选一个
发布服务会在互联网上创建新的入口点。它不等于给 peer 授予 VPN 成员身份,因为访问者从不进入隧道,网关成为后端的公开门面。这个区别决定了规则的受众和它需要的证书。
管理界面很少属于那个位置。由已授权 VPN 客户端访问的管理页面把攻击面留在隧道内部,避免把登录表单暴露给任意扫描。公网应用端点仍然需要自己的 TLS 证书、身份验证和速率限制;加密的 WireGuard 跳并不保护访问者到网关这一段。
如果服务确实必须公开,就写下主机名、覆盖它的证书,以及应当访问它的访问者范围。这三件事随后决定规则的形状和过滤策略。它们之外的一切都是公开监听上的范围蔓延。
一个端口进,一个后端出
使用一个公网端口和一个后端服务。在这个例子里 eth0 承载公网地址 198.51.100.20,网关的隧道地址是 10.200.0.1,peer 在 10.200.0.7 上运行该应用。公网 TCP 9443 映射到 peer 的 TCP 8443:
iptables -t nat -A PREROUTING -i eth0 -d 198.51.100.20 -p tcp --dport 9443 -j DNAT --to-destination 10.200.0.7:8443
iptables -t nat -A POSTROUTING -o wg0 -d 10.200.0.7 -p tcp --dport 8443 -m conntrack --ctorigdst 198.51.100.20 --ctorigdstport 9443 -j SNAT --to-source 10.200.0.1SNAT 规则同时匹配转换后的后端和原始公网目的地址,因此同一后端服务的另一条连接留在这个映射之外。它还把访问者的地址对 peer 隐藏起来,而这个权衡正是让保留源地址的路由回程成为独立设计的原因。iptables 扩展参考记录了两个目标及其匹配选项。
转发仍然需要启用,过滤链需要为转换后的目的地址和端口以及已建立的回复放行。FORWARD 链在 DNAT 之后看到的是转换后的目的地址,所以针对公网地址写的规则匹配不到被转发的数据包。要把放行写在按后端元组上,而不是公网元组上。
peer 必须接受来自网关隧道地址的服务连接,并把回复经隧道送回。它的 AllowedIPs 必须授权它实际收到的源地址,在源地址转换下就是网关的隧道地址,而这个设计并不需要在每个 peer 上写宽泛的 0.0.0.0/0 条目。丢弃回程流量的是列表漏掉该地址的 peer,或者改为转发访问者自身地址的保留源地址设计,所以要检查 peer 真正看到的源地址,而不是你规则里的那个。
把网关自身的监听挡在规则之外
把端口匹配换成覆盖所有 TCP 和 UDP 目的地址的规则,网关自己的 WireGuard 套接字就落在里面。目的地址转换发生在机器判定数据包是否本地之前,所以 UDP 51820 可能被送达 peer,而不是送给持有所有 peer 连接的那个进程。规则加载成功,隧道却死了,这是从 peer 一侧很难读懂的故障。
SSH、监控代理以及网关上承载的任何其他服务都有同样的暴露。转发一切的规则不区分控制平面和已发布的应用,而变更后的第一次重启就是锁定变得明显的时候。兜底规则不会提醒它悄悄接管了哪个服务。你会在下一次连接失败时发现。
如果确实需要宽泛转发,就在兜底规则之前预留控制端口,或者为发布使用独立的公网地址。第二个选项更干净,因为控制地址保留自己的策略,但服务商必须提供那个地址;加一条 DNS 记录并不能分配地址。
宽泛的 TCP 和 UDP 转发也不是所有协议。ICMP、IPv6、path-MTU 反馈和外层 VPN 传输都需要自己的策略,覆盖 TCP 和 UDP 的规则把这些情况留给默认链。
先选模型,再写规则
四种形态覆盖了网关发布的大多数情况,选择取决于你运行多少服务以及你能容忍多少控制平面风险。下表从最窄到最宽排列。
| Model | What it protects | Cost | Use when |
|---|---|---|---|
| Narrow port forward | Every other listener, including the VPN | One rule per service | Few services, stable ports |
| Catch-all with reserved ports | Ports named in the exception list | Rule order becomes critical | Many services and disciplined review |
| Separate public address | Control address fully isolated | Provider must supply the address | High-value publication |
| VPN-only access | No public entry at all | Visitors need the tunnel | Admin interfaces and internal tools |
即便预计以后会有更多服务,也从窄模型开始。它最容易审计,而把一组窄规则改成经过评审的兜底规则,比事后发现宽规则抓走了哪个监听要简单。无论选哪种模型,都把规则放在防火墙负责人手里。在同样管理这些链的 UFW 或 nftables 配置旁边再套用 iptables 行,会产生一种随启动顺序变化的策略。
同时验证发布与控制通路
从已授权的外部客户端,使用获批的主机名和对其有效的证书进行测试。确认是哪个后端作了应答,然后检查无关的公网端口仍然被拒绝。关闭证书检查不算通过的 HTTPS 测试,而连到错误后端的连接比失败的连接更糟。
之后验证网关本身:连接一个 WireGuard peer,打开一个 SSH 会话,确认监控仍在报告。发布的服务可以在控制平面已坏的情况下正常工作,所以两项检查属于同一个变更窗口。重启一次以证明规则按预期顺序重新应用,然后撤下发布并确认撤除确实与添加相对应。大量启动时添加加上不完整的拆除,正是临时测试变成永久开口的方式。