tailcat: A netcat-like CLI and Go library that connects machines over Tailscale's data plane without its control plane.
What problem it solves
Tailcat provides netcat-style connections over an encrypted WireGuard tunnel while exchanging connection metadata out of band instead of relying on Tailscale's control plane. It lets users run without a Tailscale account, root or administrator access, or changes to machine routing and DNS.
Key features
Encrypted peer-to-peer tunnels — Tailcat creates point-to-point WireGuard-encrypted tunnels and exchanges connection metadata outside the Tailscale control plane. Connections initially bootstrap through DERP and use NAT traversal to upgrade to a direct peer-to-peer UDP path when possible.
Source: README
Netcat-style command-line usage — One side runs a listener and receives a short tailcat address, while the other passes that address to the client. The CLI can pipe standard input and output between machines and expose or forward local TCP ports.
Source: README, cmd
SSH and file services — Tailcat can serve SSH with public-key authentication or explicitly without SSH authentication, with the encrypted tunnel supplying client identity in the latter mode. It also provides SFTP-compatible file services through `tailcat ls`, `tailcat cp`, and conventional SFTP and SCP clients.
Source: README, tailcat_sftp.go
Flexible key and relay management — Servers can use ephemeral keys by default or saved keys that persist across restarts. Tailcat supports the default DERP map, user-operated relays, custom DERP maps, and client restrictions through allowed node keys.
Source: README, keyset.go
CLI and Go library interfaces — The project offers a command-line interface in `cmd/tailcat` and an importable Go library. The library exposes client and server primitives for TCP and UDP connections and standard listener-style serving.
Source: README, tailcat.go
Quick start
Copied verbatim from the project's README.
$ tailcat
# Selected bootstrap relay region 302, San Francisco
# 🐈 Server listening with new address: tcomFwWCCcjS5nKNqAod034nWoJZW0LZqDhhC8U_dKdnDRYQ8uNGFpGQEu
(hangs, waiting...)$ echo hello | tailcat tcomFwWCCcjS5nKNqAod034nWoJZW0LZqDhhC8U_dKdnDRYQ8uNGFpGQEu
$ $ tailcat
# Selected bootstrap relay region 302, San Francisco
# 🐈 Server listening with new address: tcomFwWCCcjS5nKNqAod034nWoJZW0LZqDhhC8U_dKdnDRYQ8uNGFpGQEu
hello
$Who it may suit
This may suit users who want netcat-like access, SSH, file transfer, or port forwarding without a Tailscale account or control plane. It may also suit Go developers who need to embed these tunnel primitives in an application.
Topics to discuss
Which out-of-band method for exchanging tailcat addresses is most useful in practice?
How should teams safely manage saved keys, client allowlists, and shared DERP relays?
Which additional network or service workflows should the CLI and Go library support next?
Written by ReadmeX AI from the project's README, source and public GitHub data; it may contain mistakes.
Read the original README https://github.com/tailscale/tailcat#readme
ReadmeX opened this community for a trending project; it is not run by the project. Maintainers can claim it from the community page.
Comments
…