今天在 GitHub Trending 上发现了一个来自 Tailscale 团队的创新项目:Tailcat,它重新定义了如何在两台机器间建立安全连接——不需要账号、不需要 root、不需要网络配置,只需一行命令。
一、项目概述
1.1 核心定位
Tailcat 的口号是 “Tailscale without Tailscale, by Tailscale”。它巧妙地将 Tailscale 的数据平面(WireGuard 加密隧道 + NAT 穿透)与控制平面(账号系统、协调服务器)完全解耦,打造出一个类似 netcat 的点对点工具。
核心特性:
- ✅ 零账号要求:无需注册 Tailscale 账号,无需登录
- ✅ 零权限要求:纯用户态实现,无需 root/admin 权限
- ✅ 零配置网络:不修改路由表、DNS 或防火墙规则
- ✅ 端到端加密:基于 WireGuard 的军事级加密
- ✅ NAT 穿透:自动进行 UDP 打洞,失败时回退到 DERP 中继
- ✅ 开源自研:Apache 2.0 许可,可自建 DERP 中继服务器
1.2 适用场景
| 场景 | 传统方案 | Tailcat 方案 |
|---|---|---|
| 临时文件传输 | scp + 密钥配置 | 一行命令,临时 token |
| 内网 SSH 访问 | 端口转发/内网穿透 | 无需公网 IP,无需开放端口 |
| 快速调试端口 | nc/telnet | 加密隧道 + P2P 直连 |
| 无 root 环境 | 无法操作 | 用户态运行,完全可行 |
二、技术原理
2.1 架构设计
Tailcat 的核心创新在于复用 Tailscale 的网络栈但移除控制平面依赖:
┌─────────────────────────────────────────┐
│ Tailcat 架构 │
├─────────────────────────────────────────┤
│ 应用层:SSH / 端口转发 / stdin-stdout │
├─────────────────────────────────────────┤
│ 传输层:gVisor Netstack(用户态 TCP/IP)│
├─────────────────────────────────────────┤
│ 加密层:WireGuard(用户态实现) │
├─────────────────────────────────────────┤
│ 穿透层:magicsock + DERP 中继 │
└─────────────────────────────────────────┘
关键技术栈:
- WireGuard 用户态实现:无需内核模块,不创建 TUN/TAP 设备
- magicsock:Tailscale 的传输层,处理 STUN 探测和 UDP 打洞
- gVisor Netstack:用户态 TCP/IP 协议栈,避免操作系统网络配置
- DERP 协议:加密中继协议,用于初始握手和 NAT 穿透失败时的兜底
2.2 连接令牌机制
Tailcat 用 连接令牌(Connection Token) 替代传统的公钥基础设施:
令牌格式:
tc<base64编码的CBOR数据>
CBOR 数据包含:
- 服务器的 WireGuard 公钥(Curve25519,32 字节)
- DERP 区域 ID 或完整 DERP 服务器元数据
令牌示例:
# 短令牌(引用 DERP 区域 ID,约 50 字节)
tcomFwWCCcjS5nKNqAod034nWoJZW0LZqDhhC8U_dKdnDRYQ8uNGFpGQEu
# 长令牌(嵌入 DERP 服务器详情,自包含)
tcomFwWCCcjS5nKNqAod034nWoJZW0LZqDhhC8U_dKdnDRYQ8uNGFygaFhToGjYWhudGMzMDJhLmlwbi5kZXZhNG0yMDguMTExLjM5LjM4YTZzMjYwNzpmNzQwOjA6M2Y6OjcyMA
2.3 连接建立流程
从源码中可以看到完整的握手协议(disco.go):
Step 1: 服务器启动
server$ tailcat
# Selected bootstrap relay region 302, San Francisco
# 🐈 Server listening with new address: tcXXXXXXXXX
服务器生成临时 WireGuard 密钥对,连接到最近的 DERP 中继,打印令牌。
Step 2: 客户端解析令牌
client$ tailcat parse tcXXXXXXXXX
{
"ServerPublic": "nodekey:9c8d2e67...",
"RegionID": 302
}
客户端从令牌中提取服务器公钥和 DERP 区域,生成自己的临时密钥对。
Step 3: Meow 握手协议
源码中定义了自定义的握手消息(disco.go):
// meowMagic 是所有 meow DERP 数据包的 4 字节前缀
var meowMagic = [4]byte{'m', 'e', 'o', 'w'}
const (
meowTypePing = 0x01 // client → server
meowTypePong = 0x02 // server → client ("meowed")
)
// 客户端发送 Meow Ping,携带自己的公钥
func EncodeMeowPing(nodeKey key.NodePublic, discoKey key.DiscoPublic) []byte {
b := make([]byte, 0, 4+1+key.NodePublicRawLen+key.DiscoPublicRawLen)
b = append(b, meowMagic[:]...)
b = append(b, meowTypePing)
b = nodeKey.AppendTo(b)
b = discoKey.AppendTo(b)
return b
}
完整流程:
- 客户端通过 DERP 中继发送 Meow Ping(包含客户端公钥)
- 服务器收到后添加客户端到 WireGuard peer 列表,回复 Meowed
- 双方开始 WireGuard 握手(通过 DERP 路由)
- 握手完成后,magicsock 尝试 UDP 打洞升级到直连
- 打洞失败时保持 DERP 中继连接
2.4 密钥管理策略
源码支持两种密钥模式:
临时密钥(默认):
- 每次运行生成新密钥,进程退出后销毁
- 令牌生命周期 = 进程生命周期
- 最安全:即使令牌泄露,进程结束后也无法重用
持久密钥:
# 生成持久密钥
tailcat genkey --region=nyc
# 密钥保存到 ~/.config/tailcat/keys/default.private.json
# 后续运行自动使用持久密钥
tailcat --serve=8080
# 🐈 Server listening with saved key "default": tcXXXXXXXXX
安全提示: 持久密钥意味着令牌长期有效,建议配合 --allow 白名单:
# 只允许特定客户端公钥连接
tailcat --serve=22 --allow=nodekey:cfb6bfa77a0654d7450947fd6acef17d...
三、安装与快速开始
3.1 安装方式
方式一:Go install(推荐)
go install github.com/tailscale/tailcat/cmd/tailcat@latest
方式二:Nix flakes
# 直接运行
nix run github:tailscale/tailcat
# 安装到系统
nix profile install github:tailscale/tailcat
3.2 最简示例:管道传输
服务器端:
server$ tailcat
# Selected bootstrap relay region 302, San Francisco
# 🐈 Server listening with new address: tcomFwWCCcjS5nKNqAod034nWoJZW0LZqDhhC8U_dKdnDRYQ8uNGFpGQEu
(等待客户端连接...)
客户端:
client$ echo "hello from client" | tailcat tcomFwWCCcjS5nKNqAod034nWoJZW0LZqDhhC8U_dKdnDRYQ8uNGFpGQEu
服务器收到:
server$ tailcat
hello from client
$
3.3 浏览器版本
官方提供了 WebAssembly 编译版本,可在浏览器中与 CLI 互操作:
👉 https://tailscale.github.io/tailcat/
支持发送/接收文件或文本,适合无法安装 CLI 的场景(浏览器版本仅支持 DERP 中继,暂不支持 WebRTC 直连)。
四、使用方法与实战
4.1 端口转发
服务器暴露本地端口:
server$ tailcat --serve=8080,8443 # 可指定多个端口,或 --serve=all
# 🐈 Server listening with new address: tcXXXXXXXXX
客户端连接:
client$ tailcat tcXXXXXXXXX 8080
GET / HTTP/1.1
Host: foo
HTTP/1.1 200 OK
....
4.2 无认证 SSH 服务器
服务器启动 SSH(Linux/macOS):
server$ tailcat --serve=no-auth-ssh
# 🐈 Server listening with new address: tcXXXXXXXXX
客户端连接:
# 交互式 SSH
client$ tailcat ssh tcXXXXXXXXX
# 执行远程命令
client$ tailcat ssh tcXXXXXXXXX ls -la
安全建议: 如需认证,可用 --serve=22 转发到系统 SSH 服务器。
4.3 测试连通性
Ping 测试:
client$ tailcat ping --until-direct tcXXXXXXXXX
pong in 42.1ms via DERP(sfo)
pong in 1.2ms via 203.0.113.7:41641 # 成功升级到直连
--until-direct 会持续 ping 直到建立直连路径(最多 10 秒),如果始终走 DERP 中继,说明 NAT 穿透失败。
4.4 SOCKS5 代理
# 通过隧道访问服务器网络
client$ tailcat socks tcXXXXXXXXX curl http://server.tailcat:8081/
# 令牌可直接作为 URL 主机名(大多数 CLI 工具支持)
client$ tailcat socks curl http://tcXXXXXXXXX:8081/
4.5 出口节点
让客户端通过服务器访问外部网络:
server$ tailcat --serve=exit-node
# 🐈 Server listening with new address: tcXXXXXXXXX
4.6 Go 库集成
源码提供了简洁的 Go API:
服务器端:
package main
import (
"fmt"
"log"
"net"
"github.com/tailscale/tailcat"
)
func main() {
s := &tailcat.Server{
OnTCP: func(port uint16) func(net.Conn) {
return func(c net.Conn) {
fmt.Fprintf(c, "hello from port %v\n", port)
c.Close()
}
},
}
if err := s.Start(); err != nil {
log.Fatal(err)
}
fmt.Println(s.ConnBlob()) // 打印令牌
select {} // 阻塞等待
}
客户端:
package main
import (
"context"
"io"
"log"
"os"
"github.com/tailscale/tailcat"
)
func main() {
cl := tailcat.NewClient(tailcat.ConnBlob(os.Args[1]))
defer cl.Close()
c, err := cl.DialTCPPort(context.Background(), 80)
if err != nil {
log.Fatal(err)
}
io.Copy(os.Stdout, c)
}
五、常见问题与解决方案
5.1 连接建立慢
现象: 首次连接需要 5-10 秒。
原因:
- DERP 区域选择需要网络探测
- NAT 穿透需要多次尝试
解决方案:
# 生成持久密钥时固定区域
tailcat genkey --fixed-region
# 或明确指定区域
tailcat genkey --region=nyc
5.2 始终走 DERP 中继,无法直连
现象: tailcat ping 显示始终 via DERP(sfo),延迟较高。
原因:
- 双方都在对称型 NAT 后(企业网络、移动网络)
- 防火墙屏蔽 UDP
解决方案:
- 使用自建 DERP 服务器(延迟更低)
- 一方切换到非对称型 NAT 网络(家庭宽带通常可行)
5.3 公共 DERP 速率限制
现象: 传输速度受限,官方 DERP 有速率限制。
解决方案:自建 DERP 中继
# 1. 部署 DERP 服务器(需要域名 + TLS 证书)
# 参考:https://github.com/tailscale/tailscale/tree/main/cmd/derper
# 2. 生成使用自建 DERP 的令牌
server$ tailcat genkey --region=derp.example.com
tcomFwWCCAIsKOqPUux6ClG2RM4A_vOq4VBzGgHGGjq9OsJuFKSWFygaFhToGhYWhwZGVycC5leGFtcGxlLmNvbQ
# 3. 验证令牌包含自建 DERP 信息
client$ tailcat parse tcomFwWCCAIsKOqPUux6ClG2RM4A...
{
"ServerPublic": "nodekey:8022c28e...",
"Region": [
{
"Nodes": [
{
"HostName": "derp.example.com"
}
]
}
]
}
5.4 令牌安全存储
问题: 持久密钥保存在本地文件,如何保护?
解决方案:
# 查看已保存的密钥
tailcat genkey --list
# 删除默认密钥(下次运行会生成临时密钥)
tailcat genkey --delete --key=default
# 为特定用途创建命名密钥
tailcat genkey --key=production --region=nyc
5.5 浏览器版本限制
限制:
- 仅支持 DERP 中继,无法 WebRTC 直连(Issue #4)
- 文件传输功能有限
适用场景: 快速临时访问、演示、无 CLI 权限的环境
六、进阶场景
6.1 通过 DNS 发布令牌
将令牌发布为 DNS TXT 记录,即可通过域名访问:
# DNS 配置
my-server.example.com. 300 IN TXT "tailcat=tcXXXXXXXXX"
# 客户端直接用域名
client$ tailcat ssh my-server.example.com
client$ tailcat my-server.example.com 8080
优势: 无需记忆或传递长令牌,域名即地址。
6.2 客户端身份验证
为 SSH 等敏感服务添加客户端身份验证:
客户端生成身份密钥:
client$ tailcat genkey --client
# wrote file to ~/.config/tailcat/keys/client-default.private.json
nodekey:cfb6bfa77a0654d7450947fd6acef17d2cd848da1d30b2540b13dac272ddfd16
服务器限制只允许该客户端:
server$ tailcat --serve=22 --allow=nodekey:cfb6bf...ddfd16
# 🐈 Server listening with saved key "default": tcXXXXXXXXX
效果: 只有拥有对应私钥的客户端能建立握手,其他人甚至无法探测到服务存在。
6.3 性能优化建议
从源码和架构分析:
选择最近的 DERP 区域:
# 查看可用区域 curl https://tailcat.dev/derpmap.json | jq '.regions[].regionName' # 固定区域避免每次探测 tailcat genkey --region=region-name长令牌减少 DERP map 请求:
# 生成自包含令牌 tailcat genkey --full-address批量文件传输: 使用
--serve=all一次暴露多个端口,减少连接建立次数。
七、总结
Tailcat 代表了网络工具设计的一种新范式:将复杂的基础设施能力封装到极简的命令行界面中。它不需要你理解 WireGuard 的握手流程、不需要配置 iptables 规则、不需要申请公网 IP,只需要:
# 一行启动服务器
tailcat
# 一行连接客户端
tailcat <token>
这种"开箱即用"的体验,得益于 Tailscale 团队在用户态网络栈、NAT 穿透、协议设计上的深厚积累。从源码中可以看到,它复用了 Tailscale 的核心组件(magicsock、netstack、derp),但通过 Meow 握手协议 和 连接令牌 机制,完全解耦了对控制平面的依赖。
适用人群:
- 开发者:快速调试远程服务、临时端口转发
- 运维:无需 SSH 配置的临时访问通道
- 安全研究员:研究 WireGuard、NAT 穿透、去中心化网络
- 普通用户:在严格网络环境下传输文件
限制:
- 公共 DERP 有速率限制,生产环境建议自建
- 对称型 NAT 下可能无法建立直连
- 尚无 API 稳定性承诺(处于早期开发阶段)
对于 Tailscale 用户,Tailcat 是一个有趣的"侧信道"——当你不想或无法使用完整的 Tailscale 网络时,它提供了同样安全的点对点能力。对于非 Tailscale 用户,它是体验 WireGuard + NAT 穿透威力的最佳入门工具。
项目地址: https://github.com/tailscale/tailcat
在线体验: https://tailscale.github.io/tailcat/
开源协议: BSD-3-Clause