服务器大改造(一)————Tailscale异地无感组网实践
1.碎碎念/前言
由于近期给服务器加装了硬盘,心血来潮决定把服务器上的虚机重新规划一下…而从组网方式入手是一个很好的开始————为什么要组网呢,一是直接把服务器完全暴露在公网并不安全,二是没有公网IP(硬伤啊!)在改造前,服务器中有一台Windows虚机用于挂网课、跑tailscale宣告子网路由之类的用途,正常来说是没有什么太大问题的,直到上周用于运行游戏服务器发现,好友连进来会有奇怪的丢包现象,而不经过OpenWRT旁路由就不会有这个问题,并且能拿到一个v6的路由,于是决定把Tailscale转移到旁路由(网关)上,同时在宿舍的路由(Padavan)也安装Tailscale并宣告路由,这样 两个内网下的设备就无需额外安装客户端即可相互访问了。
本来以为会很好折腾,但是,足足折腾了我一个晚上啊!!
2. 环境条件
- 内网 A (主服务器网络)
- 网关:
10.0.0.254(旁路由) - 网段:
10.0.0.0/24 - OS: OpenWRT
- 网关:
- 内网 B (宿舍网络)
- 网关:
192.168.8.1 - 网段:
192.168.8.0/24 - OS: Padavan
- 网关:
- 内网 C
- 此网络不直接参与上述两个子网的无缝互联,但目标是让内网 A 和 B 中的设备能通过内网地址访问到内网 C 中的特定设备。
- 网段:
192.168.40.0/24 - 设备 C (在内网 C 中运行 Tailscale):
192.168.40.200
首先,确保你已在两端的路由器上安装好 Tailscale。Padavan 系统通常自带 Tailscale,在 扩展功能 菜单中启用即可;对于 OpenWRT,可以参考 openwrt-tailscale-enabler 进行安装。
接着,在两台路由器上启动 Tailscale,并使用 --advertise-routes 参数来宣告各自的本地子网。添加 --accept-dns=false 参数是为了防止 Tailscale 的 DNS 设置与路由器上其他可能存在的 DNS 服务(如 AdGuard Home等)冲突。
# 子网 A (OpenWRT, 10.0.0.0/24) 启动命令:
tailscale up --advertise-routes=10.0.0.0/24 --accept-dns=false --accept-routes=true
# 子网 B (Padavan, 192.168.8.0/24) 启动命令:
tailscale up --advertise-routes=192.168.8.0/24 --accept-dns=false --accept-routes=true
对于 Padavan 路由器,请务必在后台管理的 Tailscale 设置页面中,勾选 【开启】Tailscale 自定义参数 选项,并将对应的启动命令填入输入框后应用设置。
特别注意: 不要直接通过 SSH 命令行来启动 Tailscale 并设置参数,因为这些设置很可能在路由器重启或 Web UI 配置刷新时被覆盖掉!(我在这里排查了一个小时的故障,最后才发现是 Web UI 的启动配置覆盖了我手动输入的命令导致无法访问。。)
配置完成后,你应该会发现子网 A 和 B 已经可以互相访问了(如果不行,尝试重启路由器或稍等片刻待路由表更新)。但这时遇到一个新的问题:192.168.40.200已经向tailnet宣告了自己的IP地址,为什么还是无法使用内网C的IP地址访问那台运行 Tailscale 的设备(192.168.40.200)呢?我们来分析一下数据包的流向:
- 去程: 内网 A 设备 -> 路由器 A (OpenWRT) -> Tailscale 网络 -> 设备 C (
192.168.40.200) -> 内网 C 的目标设备 - 回程: 内网 C 的目标设备 -> 设备 C (
192.168.40.200) -> ? (设备 C 缺少返回路由) -> 内网 C 的默认网关
问题在于设备 C(192.168.40.200)。因为它没有启用 --accept-routes 选项来接收来自 Tailscale 网络的路由信息,所以当它收到来自内网 A 设备的回复包时,它不知道如何将这个包路由回 Tailscale 网络。同时,数据包的源地址也没有被转换(SNAT)。最终,回复包被错误地发送到了内网 C 的默认网关,而不是通过 Tailscale 网络转发回内网 A,导致访问失败。
理论上, Tailscale 的 --snat-subnet-routes 参数应该能处理源地址转换,但在Padavan下似乎未生效(OpenWRT由于条件限制未验证),或者我的理解有偏差,这个问题后面有空的时候再看一下
有两种解决方案:
解决方案 1:在子网 B 的路由器 (Padavan) 上配置 SNAT
对需要访问内网 C 设备的流量,在 OpenWRT 路由器上添加 iptables 规则进行源地址转换,使其看起来像是由 OpenWRT 本身发起的。
# 允许内网 B (192.168.8.0/24) 访问内网 C 设备 (192.168.40.200,192.168.5.88),流量从 tailscale0 出去时做 SNAT
iptables -t nat -A POSTROUTING -s 192.168.8.0/24 -d 192.168.40.200/32 -o tailscale0 -j MASQUERADE
iptables -t nat -A POSTROUTING -s 192.168.8.0/24 -d 192.168.5.88/32 -o tailscale0 -j MASQUERADE
解决方案 2:在设备 C (192.168.40.200) 上启用–accept-routes=true
在设备 C 上启动 Tailscale 时添加 --accept-routes=true 参数即可。这样设备 C 就能学习到来自 Tailscale 网络(包括子网 A 和 B)的路由。
这样一来,子网 A 和 B 中的设备就可以通过 Tailscale 网络访问到内网 C 中的设备了。
4.性能瓶颈
不过,需要注意性能问题。在性能较弱的路由器上运行 Tailscale,通常只能满足基本的连通性(实现“从 0 到 1”的访问),无法满足大带宽场景的需要,为什么这么说呢?请看VCR:
测试 1: Tailscale 运行在 newifi 3 路由器上
[ ID] Interval Transfer Bitrate
[ 5] 0.00-1.00 sec 2.74 MBytes 23.0 Mbits/sec
[ 5] 1.00-2.00 sec 3.62 MBytes 30.4 Mbits/sec
[ 5] 2.00-3.00 sec 3.38 MBytes 28.3 Mbits/sec
[ 5] 3.00-4.00 sec 3.51 MBytes 29.5 Mbits/sec
[ 5] 4.00-5.00 sec 3.67 MBytes 30.8 Mbits/sec
[ 5] 5.00-6.00 sec 3.59 MBytes 30.1 Mbits/sec
[ 5] 6.00-7.00 sec 3.24 MBytes 27.1 Mbits/sec
[ 5] 7.00-8.00 sec 3.53 MBytes 29.6 Mbits/sec
[ 5] 8.00-9.00 sec 3.24 MBytes 27.2 Mbits/sec
[ 5] 9.00-10.00 sec 3.78 MBytes 31.7 Mbits/sec
[ 5] 10.00-10.17 sec 495 KBytes 24.4 Mbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate
[ 5] 0.00-10.17 sec 34.8 MBytes 28.7 Mbits/sec receiver
iperf Done.
**测试 2: Tailscale 运行在 PC 上 **
[ ID] Interval Transfer Bandwidth
[ 4] 0.00-1.00 sec 22.1 MBytes 186 Mbits/sec
[ 4] 1.00-2.00 sec 10.5 MBytes 88.1 Mbits/sec
[ 4] 2.00-3.00 sec 12.8 MBytes 107 Mbits/sec
[ 4] 3.00-4.00 sec 11.2 MBytes 93.9 Mbits/sec
[ 4] 4.00-5.00 sec 10.8 MBytes 90.9 Mbits/sec
[ 4] 5.00-6.00 sec 12.1 MBytes 101 Mbits/sec
[ 4] 6.00-7.00 sec 11.5 MBytes 96.4 Mbits/sec
[ 4] 7.00-8.00 sec 11.7 MBytes 98.1 Mbits/sec
[ 4] 8.00-9.00 sec 11.1 MBytes 92.7 Mbits/sec
[ 4] 9.00-10.00 sec 12.1 MBytes 102 Mbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bandwidth Retr
[ 4] 0.00-10.00 sec 129 MBytes 108 Mbits/sec 4318 sender
[ 4] 0.00-10.00 sec 126 MBytes 106 Mbits/sec receiver
iperf Done.
这是因为 Tailscale 通过加密隧道通信,需要消耗不少 CPU 资源进行加解密运算。以我的 newifi 3 为例,实测通过路由器转发的 Tailscale 速率只能达到 30 Mbps 左右。相比之下,在我的 PC 上直接运行 Tailscale 则可以轻松跑满 100 Mbps 的上行带宽。如果你对传输速度有较高要求,强烈建议在需要高速访问的终端设备(如 PC)上再单独运行一个 Tailscale 客户端(这与路由器上宣告子网路由并不冲突)。
附录
一些可能用上的排错命令,需要根据实际情况进行修改
iptables -t nat -nvL
ip route show table all | grep tailscale
tcpdump -i tailscale0 -n 'not port 22'
iptables -nvL #确保里面有ts-input和ts-forward这样的链,如果没有,用tailscale netcheck/tailscale status检查一下