上午十一点,我像往常一样打开数据库客户端,准备连一下远端测试库 100.64.10.42:3306。等了几秒,直接弹出超时报错 Communications link failure: Connect timed out。 第一反应是 Tailscale 没开?低头看右下角系统托盘,Tailscale 菜单清清楚楚写着 Connected。

案发现场:数据库客户端超时,但 Tailscale 托盘明确显示 Connected
再切到 Tailscale 网页控制台,目标数据库所在的云主机也亮着绿灯 Connected——直到我把目光挪到第一行:我当前这台 Windows 电脑右侧的 LAST SEEN 列,挂着一个灰色圆点,时间停在 0:18 GMT+8。

Tailscale 控制台:远端服务器在线,本机却早在 0:18 离线
本机以为自己在线,服务端知道它早在半夜就已经失联了。
在拆解为什么断连之前,有必要先交代一下 Tailscale 的设计意图——因为今天踩的这个坑,根源恰恰写在它最引以为傲的架构拆分里。
以前我们要连一台云上的 MySQL,最省事但最危险的做法,是在防火墙上直接敞开公网 203.0.113.55:3306;讲究一点会自己搭传统 VPN,让各地设备先连进一台中心 VPN 服务器,再由中心机转发流量。但传统 VPN 的痛点很明显:所有数据都要绕中心节点走一圈,带宽受限、延迟翻倍,还得手动维护公网入口和密钥。
Tailscale 的思路是:把分散在各地的电脑、云主机拉进同一个「虚拟局域网(100.64.x.x)」里,零配置组网,同时不暴露任何业务端口。
为此,它把「牵线搭桥」和「真正传数据」拆成了两个平面:
controlplane.tailscale.com)保管身份认证、公钥和节点坐标(Network Map),不经手任何业务数据。

FIG. 00 · Tailscale 设计意图:传统中心转发 vs 控制面牵线与点对点直连
FIG. 00 · Tailscale 的设计意图:控制面只交换公钥与坐标(虚线),业务数据走点对点加密隧道直连(实线)。
这套架构平时极其顺滑——直到有一天,你的本机突然连不上那个「只负责牵线的控制面」。
打开终端敲一行 tailscale status,真相立刻摊在屏幕上:

本机 tailscale status 诊断:offline 且提示 You are logged out
再试着 tailscale ping 100.64.10.42,直接返回 no matching peer——本机连对方的路由表都没有。
托盘菜单里的 Connected 只代表本地客户端开关处于「开启」状态,并不代表它真的连上了控制服务器。就像电灯开关拨到了 ON,但大楼总闸已经跳了,灯自然亮不起来。

FIG. 01 · Tailscale 控制面与数据面分离架构示意图
FIG. 01 · 控制面与数据面的断层:tailscaled 无法同步 Network Map,导致数据面找不到任何节点。
是不是 Tailscale 官方改了策略?做个对照实验就能证伪——在本地分别用直连和走本地代理(127.0.0.1:10808)请求同一接口:
# 直连:连接被重置
curl.exe -I -m 5 --noproxy "*" https://controlplane.tailscale.com/key?v=142
# -> curl: (35) Recv failure: Connection was reset
# 走本地代理:秒通
curl.exe -I -m 5 -x http://127.0.0.1:10808 https://controlplane.tailscale.com/key?v=142
# -> HTTP/1.1 200 OK这就实锤了:不是 Tailscale 封禁或改策略,而是本机直连 controlplane.tailscale.com 在 TLS 握手阶段触发了中间链路的连接重置(TCP RST)。
至于为什么昨天还能用、凌晨 0:18 突然断掉,通常是因为夜间宽带重拨或 DNS 轮询 IP 切换后刚好撞上了拦截规则;只要当时发生一次网络抖动,客户端尝试重新连接控制面拉取密钥时被 RST,就会彻底卡在 logged out / offline。
很多人会问:我把代理软件(常见代理客户端)的 TUN 模式打开让 Tailscale 连上,再把 TUN 关掉,行不行?
短期内大概率能用,但不是一劳永逸的。
原理就在前面的双平面设计里:
controlplane.tailscale.com,所以靠本地缓存还能正常用好几个小时;
前不久我写过一篇《同样写代码的 AI 工具,为什么只有 Antigravity 要开 TUN 模式?》。当时排查发现,Antigravity 把 UI(Chromium)和大脑(language_server.exe,Go 语言编写)拆成两个进程:浏览器读 Windows 系统代理,而 Go 语言的 net/http 默认无视系统代理,只认环境变量。
看一眼我当时的 代理客户端状态就全明白了——开了「自动配置系统代理」,但没开 Tun(甚至因为非管理员运行也开不了 Tun):

代理客户端只开启了自动配置系统代理,未启用 Tun 模式
Tailscale 和 Antigravity 简直是同一个故事的上下集,只是进程边界又往下沉了一层:
对比维度 Antigravity (AI IDE) Tailscale (Windows 客户端)
核心网络进程 language_server.exe(Go 语言) tailscaled.exe(Go 语言)
网络库行为 Go net/http 无视系统代理,只认环境变量 Go net/http 无视系统代理,只认环境变量
运行边界 用户态子进程(随 GUI 启动) Windows 系统服务(LocalSystem 身份)
不开 TUN 的解法 .bat / .vbs 给进程树注入 HTTPS_PROXY 注册表给 Tailscale 服务注入 HTTPS_PROXY

FIG. 02 · Antigravity 与 Tailscale 的边界对照
FIG. 02 · 同源的 Go net/http 陷阱,不同的进程边界:前者困在用户态子进程,后者沉在 LocalSystem 系统服务。
Antigravity 的 Go 后端是你双击应用拉起的子进程,用 .bat / .vbs 就能喂环境变量;而 Tailscale 的 tailscaled.exe 是开机自启的 Windows 系统服务,既不读系统代理,也不继承用户环境变量。
不需要一直开着 TUN 跟虚拟网卡抢路由,也不用写全局系统环境变量去污染浏览器或企业 VPN。我们只需要单独给 Tailscale 这一个服务配置代理环境变量。
以管理员身份打开 PowerShell 执行:
reg add "HKLM\SYSTEM\CurrentControlSet\Services\Tailscale" /v Environment /t REG_MULTI_SZ /d "HTTPS_PROXY=http://127.0.0.1:10808" /f
Restart-Service Tailscaletailscaled 服务只会在自己的进程空间里读取 HTTPS_PROXY=http://127.0.0.1:10808,让控制面稳稳走代理保持在线,电脑上其他软件和数据面加密隧道完全不受影响。
从 Antigravity 的黑屏,到今天 Tailscale 亮着绿灯却连不上 3306,两次排障指向了同一条工程常识:决定工具在复杂网络里能不能活下来的,往往是你有没有看清它的「边界」画在哪里。
界面开关与后台服务的边界、控制面与数据面的边界、用户态进程与 LocalSystem 服务的边界——看清边界,一把小手术刀就够了,不必动辄开启全盘接管的 TUN。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。