SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 更新于 2026-08-26

如何在 VPS 上运行 Tailscale 子网路由器

在 VPS 上向 tailnet 通告私有网段,涵盖路由审批、重启后仍生效的 IP 转发,以及 Linux 客户端必须设置的 --accept-routes 标志。

Tailscale 子网路由器的作用

Tailscale 子网路由器是一台向 tailnet 广播整个私有 IP 地址范围的计算机,因此 tailnet 中的每台设备都可以访问该范围内的地址,即使其中没有任何设备运行 Tailscale。tailnet 是您的私有 Tailscale 网络,即登录同一账户或组织的设备集合。人们常将其与出口节点混淆,但出口节点的作用正好相反。它会将设备的所有流量通过 VPS 发出,因此 VPS 会成为该设备访问公网的路由。

每句话说明一个要点。子网路由器让 tailnet 可以访问一个私有网络。出口节点改变公网流量的出口位置。如果您需要后者,请改为阅读如何在 VPS 上运行 Tailscale 出口节点。它们使用不同的标志;一台 VPS 可以同时承担两种角色,但二者解决的问题不同,故障方式也不同。

VPS 需要子网路由器的场景

常见情况是,服务商已经为您提供了一个私有网络。您的 VPS 有一个公网地址,以及位于私有网段上的第二个网络接口;该网段中的其他服务器完全没有公网地址,例如位于 10.0.0.20 的数据库和位于 10.0.0.30 的备份目标。将 Tailscale 部署到其中一台 VPS 上,通告 10.0.0.0/24,您的笔记本电脑就可以直接访问这些私有地址。网段中的其他配置无需更改,数据库仍然没有公网地址。如果您只需要访问该网段中某台服务器的一个 Web 应用和一个端口,那么通告整个地址范围就超出了实际需求,此时可以改用 Tailscale serve 为该单个端口提供 HTTPS。同样的原理也适用于有意仅绑定到 localhost 的守护进程,例如在 systemd 下以无头模式运行的 dsh。此时,VPS 上的 tailnet 地址可以替代原本为了访问其 UI 而需要保持开启的 SSH 隧道。

另一种情况是 VPS 另一侧的网络。例如,位于自身路由器后面的家庭或办公室 LAN(局域网),或者由无法运行 Tailscale 的设备组成的机架,如受管交换机或固件受限的旧 NAS。该网络中的一台 Linux 主机可以作为整个网络的子网路由器。在家庭环境中,这台主机通常是运行在现有虚拟化主机上的小型 VM。在决定服务应位于隧道的哪一端之前,应先理清家庭 Proxmox 主机与租用 VPS 的成本对比

这两种情况有一个共同要求。子网路由器必须已经能够通过自身的路由表和防火墙访问它所通告的地址范围。Tailscale 不会建立这条连接。它只负责将流量传送到路由器,再交给内核进行转发。

先安装 Tailscale,并首先检查本地路由

curl -fsSL https://tailscale.com/install.sh | sh

该脚本会检测发行版、添加 Tailscale 软件包仓库、安装 tailscale 命令和 tailscaled 守护进程,然后启用服务。使用 systemctl is-active tailscaled 进行确认;该命令应输出 active

在执行其他操作前,先确认 VPS 可以访问您计划发布的网络。

ip route show
ping -c3 10.0.0.20

ip route show 必须在实际网络接口上列出该私有网段,例如 10.0.0.0/24 dev enp7s0 proto kernel scope link src 10.0.0.5。如果此处 ping 失败,说明 VPS 无法直接访问路由器本身,任何 Tailscale 选项都无法修复此问题。原因是 VPS 的网络配置有误,或目标主机上的防火墙阻止了访问。请先修复该问题,因为后续所有测试都依赖于此。

启用 IP 转发,并让设置在重启后保持有效

除非启用了转发,否则 Linux 计算机会丢弃所有目标地址不是本机的数据包。转发其他计算机的数据包是子网路由器的核心职责,因此这一步不能省略。

echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
sudo sysctl -p /etc/sysctl.d/99-tailscale.conf

使用 sysctl net.ipv4.ip_forward 检查该设置,该命令应输出 net.ipv4.ip_forward = 1

很多人只能部分完成这一步。sudo sysctl -w net.ipv4.ip_forward=1 会立即生效,但会在下一次启动时丢失。因此,子网路由器可能连续运行数周,却在内核升级后重启的第二天早上停止工作。令人困惑的是,表面上没有任何异常。tailscale status 仍会显示节点在线,管理控制台仍会显示路由已批准,客户端也仍会安装该路由。数据包到达 VPS 后,内核会直接丢弃它们,且不会记录任何日志。将这些值写入 /etc/sysctl.d/99-tailscale.conf,才能让设置在重启后恢复。

如果在转发仍处于关闭状态时发布路由,tailscale up 会立即发出警告,并显示一行类似 Warning: IPv4 forwarding is disabled. Subnet routes and exit nodes may not work correctly. 的内容。请阅读该命令的输出,不要直接跳过。

发布路由

sudo tailscale up --advertise-routes=10.0.0.0/24

在已登录到 tailnet 的 VPS 上,直接修改现有设置:

sudo tailscale set --advertise-routes=10.0.0.0/24

后续每次修改都使用 tailscale set。使用单个标志重新运行 tailscale up 时,未重复指定的标志会被重置;CLI 会报错并提示,以这种方式修改设置时必须同时指定所有非默认标志。tailscale set 只修改一个设置,其他设置保持不变。

多个网段应放在同一个逗号分隔列表中,逗号后不留空格:--advertise-routes=10.0.0.0/24,192.168.50.0/24。每个条目都必须是 CIDR 表示法中的网络地址(无类别域间路由,即 10.0.0.0/24 形式)。如果误填了本机地址 10.0.0.5/24,命令会被拒绝,因为前缀后的位不全为 0;错误信息会指出你可能想使用的前缀。若要停止发布路由,使用 sudo tailscale set --advertise-routes= 设置空列表。

在管理控制台中批准路由

发布路由是一项请求,不会立即生效。在管理员批准之前,不会有客户端收到该路由,该网段中的任何资源也都无法访问。这是有意设计的,因为如果某台机器可以将自己添加到所有人的路由表中,它就能截获任意网段的流量。

在管理控制台的 Machines 页面中批准路由。VPS 会显示一个子网标记。打开对应行,找到子网部分,编辑路由设置,勾选该路由,然后保存。

批准按前缀单独生效。今天发布 10.0.0.0/24,下个月再发布 192.168.50.0/24 时,新前缀会处于未批准状态,而旧前缀仍可正常工作。从 VPS 上看,已批准的路由和被忽略的路由没有区别,因此在排查其他问题前,先检查控制台中的状态。

您可以在 tailnet 策略文件中使用 autoApprovers 块跳过手动操作:

{
  "autoApprovers": {
    "routes": {
      "10.0.0.0/24": ["tag:subnet-router"]
    }
  }
}

然后使用该标签 sudo tailscale up --advertise-routes=10.0.0.0/24 --advertise-tags=tag:subnet-router 启动节点,路由在发布时就会立即获得批准。该标签必须先存在于同一个策略文件的 tagOwners 部分中。如果您通过脚本重建 VPS,建议配置此项,因为重建后的节点会被视为新节点,其路由会再次处于未批准状态。

为什么 Linux 客户端在未使用 --accept-routes 时会忽略路由

现在已发布并批准该路由。您的手机和 Mac 可以访问 10.0.0.20。Linux 笔记本电脑却无法访问,并且管理控制台中没有任何异常提示。

接受子网路由意味着将路由条目写入客户端的路由表。在 Android、iOS、macOS、tvOS 和 Windows 上,Tailscale 客户端会自动完成此操作。在 Linux 上则不会这样做,因为 Linux 机器通常是服务器或路由器,其路由表往往经过有意配置;如果系统静默插入从网络学习到的 /24,可能会破坏该机器当前处理的流量。因此,在 Linux 上必须在每个客户端中显式启用:

sudo tailscale set --accept-routes

然后检查路由写入的位置:

ip route show table 52
ip route get 10.0.0.20

Linux 上的 Tailscale 不会将已接受的路由放入主路由表,而是将其放入路由表 52,并安装策略规则。使用 ip rule show 可以看到优先级范围为 5210 到 5270 的这些规则;它们会将未匹配的数据包发送到该路由表。因此,单独运行 ip route show 永远不会列出 10.0.0.0/24,只检查这条命令的读者会认为 --accept-routes 没有生效。ip route show table 52 才是显示实际结果的命令,它应列出 tailscale0 上已发布的地址范围。

有一个例外需要了解。如果此 Linux 节点本身是其本地网络的第二个子网路由器,--accept-routes 会使它将发往自身直连子网的流量通过另一台路由器发送,而不是从自身接口发出。在高可用对中的备用路由器上,应关闭 --accept-routes,只发布路由。

故障模式:两个路由器通告重叠范围

两个子网路由器不得通告完全相同的范围。前缀长度不同的重叠范围是允许的,Tailscale 会选择匹配范围最具体的路由。路由器 A 通告 10.0.0.0/24,路由器 B 通告 10.0.0.0/16 时,前往 10.0.0.20 的流量会通过 A。

A 离线后,情况会让人意外。Tailscale 不会回退到匹配范围较宽的路由。前往 10.0.0.20 的流量会中断,而前往 10.1.0.20 的流量仍会通过 B 正常工作。表面上看,像是私有网络有一半不可用;实际原因是某个离线节点持有更具体的前缀。若要实现故障转移,请让通告较宽范围的路由器同时通告较窄的前缀,使两个路由器覆盖相同的地址。

另一种重叠更接近客户端。在 192.168.1.0/24 的酒店网络中使用子网路由器,而该路由器通告 192.168.1.0/24 时,两个路由会争用相同的目标地址,最终使用哪个路由取决于平台。在 Linux 上,请添加一条优先于 Tailscale 自有规则的规则,使本地地址使用 main 表:

sudo ip rule add to 192.168.1.0/24 priority 2500 lookup main

该规则不会持久保存,下次启动时会消失。真正的解决方法是选择一个在实际网络中不会遇到的私有地址范围。大多数家用路由器默认使用 192.168.0.0/24192.168.1.0/24,因此应在 10.0.0.0/8 中有意选择一个范围。相同的冲突也会破坏手动配置的普通 WireGuard VPN,原因相同:更具体的本地路由会优先匹配,因此流量不会进入隧道。

故障模式:DNS 解析到没有路由覆盖的地址

这种问题很难调试,因为没有任何组件报告错误。名称可以解析,但连接会超时。

假设 db.internal.example.com 通过您的私有名称服务器解析为 10.0.5.20,而您已公布 10.0.0.0/24。查询会成功,因为 DNS(域名系统)解析和 IP 路由是两个独立步骤,彼此都不会检查对方。随后,发往 10.0.5.20 的数据包在 tailnet 上找不到匹配路由,于是通过客户端的默认网关发出并丢失。

使用以下两个命令可以分别检查这两个环节:

nslookup db.internal.example.com
ip route get 10.0.5.20

如果查询返回地址,但 ip route get 无法通过 dev tailscale0 响应,则名称解析正常,缺少的是路由。请公布能够覆盖该地址的范围,可以使用 10.0.0.0/16 或另一个显式前缀,然后在控制台中批准新的前缀。

名称服务器本身也存在对应的陷阱。如果您在管理控制台中将全局名称服务器设置为类似 10.0.0.53 的私有地址,则该地址必须位于已批准的路由内,否则设备根本无法访问解析器。启用覆盖本地 DNS 服务器的选项,同时将其指向设备无法访问的解析器后,tailnet 中的所有设备都会立即失去名称解析,包括刚才还正常工作的设备。请先公布并批准通往解析器的路由,再修改 DNS 设置。如果您一直在排查隧道内的 DNS 问题,WireGuard 隧道中的 DNS 如何失效介绍了相同的机制,但不涉及上层的协调机制。

源 NAT 和站点到站点连接

默认情况下,子网路由器会将每个转发数据包的源地址改写为自身的私有地址。这就是 SNAT(源网络地址转换)。这样做是为了让回复能够正常返回,而无需修改私有网络:10.0.0.20 上的数据库会向 VPS 回复,因为它已经知道如何访问 VPS。代价是,数据库看到的所有 tailnet 连接都来自 VPS,因此基于源地址的防火墙规则和访问日志无法提供有效信息。

如果希望保留客户端真实的 tailnet 地址,可在 Linux 上关闭 SNAT:

sudo tailscale set --snat-subnet-routes=false

此时,私有网络中的主机需要添加返回 100.64.0.0/10 的路由。100.64.0.0/10 是 Tailscale 分配给设备的地址范围,该路由应指向子网路由器。如果没有这条返回路由,回复会发送到默认网关,无法到达客户端,因此连接会在第一个数据包之后挂起。请在私有网络的网关上添加静态路由,或者保持 SNAT 启用。

站点到站点连接是指两个子网路由器同时执行此操作:每个路由器发布自己的网络,并接受对方发布的网络:

sudo tailscale up --advertise-routes=10.0.0.0/24 --snat-subnet-routes=false --accept-routes

在另一台路由器上使用其自身地址范围运行对应命令。两个地址范围必须不同。如果大数据传输发生停顿,而 sshping 正常,原因通常是 MSS(最大分段大小)问题。MSS 是 TCP 数据包所能携带的最大数据块大小。隧道开销会使转发数据包超过中间某条链路支持的大小,设置 MSS 上限即可解决:

sudo iptables -t mangle -A FORWARD -o tailscale0 -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

使用 iptables-persistent 保存此规则,否则它会在下次启动时消失。

保持稳定运行的日常维护

截至 August 2026,节点密钥默认在 180 天后过期。子网路由器上的密钥过期后,该节点会退出登录,整个通告网段都会变得无法访问,而且任何位置都没有配置变更可以解释这一现象。在管理控制台的 Machines 页面中,为此设备禁用密钥过期,然后记录已完成此操作。

Tailscale 会优先在节点之间建立直接连接;无法建立时,则回退到其中继服务器。中继服务器可以正常工作,但会增加延迟。具有公网地址的 VPS 最容易配置:允许入站 UDP 41641 后,大多数节点都能直接连接。如果防火墙由 ufw 管理,请参阅 VPS 实际需要的 ufw 规则了解语法。

访问规则是另一部分。默认 tailnet 中,你的每台设备都可以访问其他设备,因此批准的路由会直接生效。编写 ACL 策略后,规则的目标端必须指定私有网段,因为 10.0.0.20 不是 tailnet 地址,也不受针对 tailnet IP 或标签编写的规则覆盖。

最后,决定是否接受一个并非由你运行的协调服务器。Tailscale 的控制平面是托管服务。密钥保留在你的设备上,但账户和策略文件存储在那里。在将通往私有网络的路由交给它之前,应先明确控制平面遭到入侵或身份登录凭据被窃取后,攻击者实际能够执行哪些操作;Tailscale 的信任模型说明了这一边界的位置。费用通常很少成为用户弃用它的原因,因为免费计划支持最多六名用户,并为每名用户提供不限数量的自有设备。不过,以标签启动的子网路由器与以你的身份登录的子网路由器计费方式不同。超过这一数量后,费用按用户而不是设备计算,因此在添加导致超出限制的账户之前,最好先了解家庭用户或五人团队在免费计划用完后实际需要支付的费用。运行Headscale,即自行托管的 Tailscale 控制服务器可以将控制平面保留在自己的 VPS 上,但需要自行维护。针对同一顾虑的另一种选择,是同时放弃 Tailscale 客户端;自行托管 NetBird VPN 服务器可将协调层及其网状网络客户端运行在一台由你控制的设备上。如果你仍在手写配置与此模型之间做选择,WireGuard 与 Tailscale 的对比会说明协调层提供了哪些功能,以及需要付出什么代价。

FAQ

子网路由器和出口节点有什么区别?

子网路由器会通告一段私有地址范围,因此 tailnet 设备可以访问未运行 Tailscale 的计算机。出口节点会通告自己是通往整个互联网的路由,因此设备会通过该节点的公网地址发送所有网络流量。一台 VPS 可以同时承担这两种角色。它们使用不同的标志:--advertise-routes--advertise-exit-node,并且分别需要在管理控制台中批准。

为什么我的 Linux 客户端忽略了通告的子网路由?

Linux 客户端不会自动接受子网路由,必须显式启用。请在客户端运行 sudo tailscale set --accept-routes。然后使用 ip route show table 52 检查,而不是使用 ip route show。Tailscale 会将已接受的路由安装到路由表 52,并通过策略规则访问这些路由,因此主路由表中不会列出它们,正常工作的路由看起来可能像是缺失的。

重启后我的子网停止工作了。哪里出了问题?

最可能是 IP 转发被关闭。使用 sysctl -w 设置的值不会在重启后保留,因此请将其写入 /etc/sysctl.d/99-tailscale.conf,并使用 sysctl net.ipv4.ip_forward 确认。如果转发已启用但该地址范围仍无法访问,请在管理控制台中查看该节点。节点密钥默认在 180 days 后过期,子网路由器的密钥过期后,表现更像网络故障,而不是账户问题。

两个子网路由器可以通告相同的地址范围吗?

不能通告完全相同的范围。前缀长度不同的重叠范围可以共存,并且最长匹配的路由优先。故障转移需要特别注意:当持有更具体前缀的路由器离线时,Tailscale 不会回退到范围更大的路由,因此该流量会停止。要构建真正的备用路由器对,请让两个路由器都通告相同的具体前缀。

主机名可以解析,但连接超时。为什么?

DNS 解析和路由是两个独立步骤。名称可能解析到一个没有任何已批准路由覆盖的地址,数据包随后会通过客户端的默认网关发出。请在客户端运行 ip route get <address>。如果结果不包含 dev tailscale0,请通告一个覆盖该地址的范围,并在管理控制台中批准新的前缀。