在两台没有公网地址、互相看不见对方的机器之间传一个文件,标准答案通常是装一套组网工具:注册账号、登录、加入同一个网络,然后才能通信。Tailscale 在 2026 年 8 月的 TailscaleUp 会议上开源了一个新项目 tailcat,给出了另一条路:不用账号、不用登录、不建网络,两个终端各敲一条命令,一条端到端加密的隧道就建起来了。项目定位写得直白:像 netcat,但跑在 Tailscale 的数据平面上,绕开了它的控制平面。

仓库在开源后一天内从 3.0k star 涨到 3.5k,这个增速对网络工具来说并不多见。看懂它做了什么,需要先拆开 Tailscale 这套系统的两层结构。
控制平面才是门槛,数据平面一直是开源的
Tailscale 的架构分两层。控制平面负责账号、设备身份、ACL 策略和密钥分发,这部分以协调服务器(coordination server)为中心,官方托管版是闭源的,企业可以自建 Headscale 这类开源替代。数据平面负责真正的流量:用户态 WireGuard 加密、NAT 穿透、中继转发,这部分代码全部在开源仓库里。
日常组网场景里,控制平面是必需品。你要管理几十台设备、给不同的人分配不同的访问权限,就需要账号和策略。但很多连接场景用不到这些:临时把开发目录传给一台测试机、调试时抓一次远程端口、给一个几分钟寿命的沙箱环境开个通道。这类连接的生命周期以分钟计,为此注册账号、加入 tailnet、维护一套设备身份,成本全花在了不产生价值的地方。
tailcat 把数据平面单独拎出来用。两个机器各跑一个进程,不注册、不登录、不改路由表、不动 DNS、不需要 root,全程用户态。Tailscale 官方给它的话术定位也说明了意图:需要身份、策略和可审计性时用 Tailscale,只需要一次连接时用 tailcat。
一条命令建一条 WireGuard 隧道
使用方式和 netcat 同构。一端启动监听:
$ tailcat
# Selected bootstrap relay region 302, San Francisco
# 🐈 Server listening with new address: tcomFwWCCcjS5nKNq...服务端打印出一个 token,把 token 交给对端(聊天窗口、二维码、DNS TXT 记录都行),另一端:
$ echo hello | tailcat tcomFwWCCcjS5nKNq...hello 就出现在第一个终端里。传输层是标准的 WireGuard 加密,管道两端接的是 stdin/stdout,所以任何 Unix 管道组合都能直接套上去。官方演示的画面是两台机器之间传目录:发送端 tar --no-xattrs -cvz tsdr | tailcat <token>,接收端 tailcat | tar -xzv,文件列表在两端终端里同步滚动。

除了裸管道,tailcat 还内置了几种常用形态:
--serve=8080,8443把本机 TCP 端口暴露到隧道对端,对端tailcat <token> 8080就能像访问本机服务一样发 HTTP 请求--serve=no-auth-ssh起一个免认证 SSH 服务,认证由 WireGuard 握手完成,对端用tailcat ssh <token>直连;要接回系统级 SSH 就用--serve=22做端口转发--serve=exit-node把本机作为对端的出口节点tailcat ping --until-direct <token>测试连通性,pong 会标明当前走的是 DERP 中继还是直连路径,以及直连建立前后的延迟差
token 还可以直接当 SOCKS5 代理的目标主机名用:tailcat socks curl http://<token>:8081/。这些能力全部打包在一个静态编译的 Go 二进制里,go install github.com/tailscale/tailcat/cmd/tailcat@latest 一条命令安装。
token 里装了什么
tailcat 的连接元数据叫 connection token(内部名 ConnBlob):tc 前缀加 base64 编码的 CBOR 结构,装着两样东西:服务端的 WireGuard 公钥(Curve25519,32 字节),以及 DERP 中继信息(一个小整数引用默认中继列表,或者内嵌完整的中继节点地址)。
只带区域编号的短 token 约 50 字节。用 --full-address 或 tailcat resolve 可以展开成自包含形式,把中继的域名和 IP 直接写进去,客户端省掉一次拉取中继列表的往返。tailcat parse 能把任何 token 解码成 JSON 打印出来。
公钥即地址是这套设计里最巧的一环:服务端地址从它的 WireGuard 密钥推导出来,谁知道地址谁就能发起连接,地址本身就是访问凭证。密钥管理对应分了两档:
- 临时密钥(默认):每次运行生成新密钥,进程退出地址即作废。地址只对这一次运行有效,分享出去也只泄露这一次的入口
- 持久密钥:
tailcat genkey把密钥存到磁盘,地址跨重启稳定,适合发布成 DNS TXT 记录长期使用;代价是所有曾经拿到过地址的人都能连未来的服务,需要用--allow=nodekey:...显式限定客户端公钥
官方文档给的完整例子是一条从公网任意位置可达的 SSH 通道:服务端 genkey --fixed-region 生成绑定固定中继区域的密钥,--serve=22 --allow=<客户端公钥> 只接受指定客户端;客户端 genkey --client 生成身份密钥对;服务端地址发布成 DNS TXT 记录后,对端只需要 tailcat ssh my-server.example.com。服务器不开任何入站端口,WireGuard 握手先于 SSH 发生,未授权方的握手被静默丢弃,连服务存在的痕迹都探测不到。
数据平面逐层拆解

tailcat 复用了四个 Tailscale 开源组件,每个都解决链路里的一层问题:
- WireGuard(用户态实现):全部流量的加密层。不创建内核 TUN/TAP 设备,不写路由表,这是免 root 的前提
- magicsock:Tailscale 的传输层,在直连 UDP 和 DERP 中继之间自动 multiplex。负责 STUN 端点发现和 UDP 打洞
- DERP 中继:加密中继协议,承担双重角色:打洞成功前的引导信道(bootstrap),和打洞失败后的兜底数据路径
- Netstack(gVisor):用户态 TCP/IP 协议栈,在进程内终结 TCP 连接。tailcat 能在不配置任何系统网络的前提下接受入站连接、发起出站连接,靠的就是它
连接建立过程分六步:服务端生成密钥对并连上 DERP 中继,打印 token;客户端解析 token 拿到公钥和中继区域,生成自己的临时密钥,连到同一个中继;客户端通过中继发一条 "Meow" 消息(对,这个握手消息就叫这个),带上自己的节点公钥;服务端把它加进 WireGuard 对端列表,回一条 "Meowed";双方以对方为对端完成标准 WireGuard 握手,隧道打通;同时两侧通过中继交换 disco call-me-maybe 消息,各自 advertise 自己的 UDP 端点(STUN 探测到的公网地址加本地接口地址),尝试 UDP 打洞。打洞成功,流量从 DERP 中继升级到点对点直连;失败,DERP 继续兜底,连接依然可用,走公共中继时吞吐受限。
tailcat ping 的输出把这条路径升级过程直接呈现出来:
$ tailcat ping --until-direct <token>
pong in 42.1ms via DERP(sfo)
pong in 1.2ms via 203.0.113.7:41641第一跳走旧金山中继 42 毫秒,打洞完成后同一条隧道降到直连 1.2 毫秒。
自建中继与 Go 库
默认中继是 Tailscale 托管的免费公共服务,限速、无 SLA,官方明说可能随时收回。不想依赖公共设施的话,两条路都是开源的:
一是跑自己的 DERP 中继(derper,Tailscale 主仓库里自带),给它一个能签 TLS 证书的域名,Let's Encrypt 自动签;然后 tailcat genkey --region=derp.example.com 生成绑定自建中继的密钥,token 里会内嵌中继主机名,客户端全程不接触 Tailscale 的中继列表,速率限制只剩自己的带宽。二是自建一份 DERP map JSON,两侧用 --derpmap-url 指过去,适合有多台中继的部署。
tailcat 同时是一个可导入的 Go 库(github.com/tailscale/tailcat),CLI 只是薄封装。最小服务端十几行:声明一个 tailcat.Server,按端口注册 TCP 处理函数,Start() 之后把 ConnBlob() 打出来;客户端侧 tailcat.NewClient(token) 加一个 DialTCPPort 就能拨号。给自动化脚本、CI 任务或者 AI 代理的沙箱环境嵌入一次临时加密连接,不需要碰任何组网概念。Tailscale 官方的使用建议里也把「给 agent 一台测试机的临时访问权」列为 tailcat 的典型场景。
定位与边界

tailcat 不是要替代 Tailscale,两者在官方叙事里是并排的两档:要身份、策略、审计,用 Tailscale;只要一次连接,用 tailcat。也不必拿它和 filecoin 这类文件传输服务对比——tailcat 不经手数据,中继只看到加密流量,端到端密钥在两个 WireGuard 对端手里。
边界同样要认清。项目明确声明不承诺任何 API 稳定性:Go API、CLI 参数、线上格式都可能变。临时密钥的地址无法预告(生成之前不存在),双方必须有个带外信道传 token,这一步没有魔法。打洞失败时公共中继的限速吞吐只够应急。另外它是 2026 年 8 月刚开源的新项目,接口还在快速迭代期,生产依赖要掂量这个成本。
对个人开发者,它最实际的用法是替代那类「为了传一次文件临时开端口/挂 scp/找个网盘」的折衷方案:两端各一条命令,无配置、无暴露面、密钥级认证。对在自建服务栈里已经有 derper 或者 Tailscale 经验的人,tailcat 是把已有基础设施复用到一次性连接场景的低成本扩展。
仓库地址:github.com/tailscale/tailcat,BSD-3-Clause 协议,Go 语言,官方产品页在 tailscale.com/tailcat。
来源:Tailscale 官方产品页、tailscale/tailcat README(GitHub)、Hacker News 讨论(news.ycombinator.com/item?id=49452990)