Today we’re releasing tailcat, a remix of pieces of Tailscale that gives you a way to use the open-source Tailscale data plane (WireGuard® + NAT traversal + DERP) without the Tailscale control plane, written by the people who made Tailscale. It’s Tailscale without Tailscale, by Tailscale.
Specifically, tailcat is both an open-source Go package and a CLI tool using that package. It lets you run a server-side listener and a client to connect to that server, moving bidirectional bytes back and forth.
That is, it’s like netcat but flowing over Tailscale’s magicsock (WireGuard encryption + NAT traversal + DERP rendezvous/fallback relay).
Notably, tailcat has:
- no IP addresses
- no accounts (no logins, no passwords, no SSO)
- no control plane
- no users
- no admins
- no administrative controls
- no root or admin OS access requirement
- no relationship with or dependence on Tailscale as a company (if you run your own
cmd/derperDERP server, at least)
When you watch people describe Tailscale to each other online, you see very different interpretations of what “Tailscale” means to them.
One group of people, often seen saying things like “I’ll just run WireGuard myself,” focuses on the WireGuard part and doesn't consider (or care about) parts like NAT traversal, DERP fallbacks, centrally managed firewall (ACL) rules, SSO login, tagging, MDM policies, audit logging, etc. Maybe they only want or need the WireGuard part on a public IP. That’s fine.
Another group of people talks more about the company, corporate structure, long-term viability, founders, funding stage, pricing, certifications, reliability, responsible handling of security disclosures, etc.
Another group of people talk about whether Tailscale is open source or not. As a reminder: our core is open source (with a real OSI-approved license!), our DERP server is open source, and our clients are open source on platforms that are themselves open source: Linux and Android. Our server-side control plane is not. A lot of people in this audience appreciate that Headscale (which we love and partially fund development of) exists, either to use today, or use in the future, as a fallback plan.
All of those interpretations are fine. Whether you’re using our official GUI client wrappers around our official control plane, with a corporate SSO identity provider, or you’re at the other extreme, using only tsnet on Linux nodes against your self-hosted Headscale server, there are many ways to wire up and use Tailscale and its many pieces:
- Its WireGuard + NAT traversal + DERP fallback data plane
- Its control plane
- Its company (paying us to run and support things for you)
- Its open source code
tailcat gives you another way to use a subset of Tailscale.
Let’s say you want to run a tailcat server. Here’s what it does:
- generates a keypair (either ephemeral or named & reused)
- picks a DERP server (either one you specify, or an auto-selected bandwidth-limited Tailscale-run one)
- generates a
tailcataddress, which is a string of the form: tc + base64(CBOR( public key + DERP bootstrap info )) - you then share that address string with somebody out of band, either directly, or by putting it in a DNS TXT record, and sharing that DNS hostname out of band
The client side is about the same:
- pick a key (ephemeral or locally named & reused)
- connect to the rendezvous DERP server specified in the
tailcataddress - send a
MEOWmessage to the server’s public key over DERP to add yourself to the netmap
At that point, if the server is cool with that client’s public key (it can be optionally locked down), then it replies with a happy MEOW reply.
The client then proceeds to make a TCP connection to the other side using an embedded userspace TCP stack atop WireGuard. There are actual IP addresses on the wire (IPv6 ones derived from your public key), but they’re never visible to users. Your operating system is never involved at the TCP layer and never sees the synthetic tailcat IPs. All your operating system does is send the DERP TCP messages and/or NAT-punched UDP WireGuard messages.
Because it goes over Tailscale’s magicsock data plane, NAT traversal automatically kicks in and tries to get a direct connection, so data transfer (WireGuard UDP packets) ends up going directly between the client and server, without a DERP relay involved. But if both sides are behind a hard NAT without any port mapping services available, the data packets are relayed over DERP as a fallback. If you use Tailscale-hosted DERP servers, those are rate-limited (bandwidth costs us money). But if you run your own DERP server, you can control any rate limiting.
In the default mode where you don’t specify a port number on the tailcat server, the default is to just pipe the received data to the server’s stdout, like netcat. But it can also run in a client mode, where it runs a SOCKS server on an ephemeral local port and then runs a provided child process (e.g. curl or whatever) with an environment variable set to use said SOCKS server, letting tailcat-oblivious programs use tailcat transparently. (tailcat is currently always userspace-only, never reconfiguring your system’s networking stack … no TUN devices, no routing table changes, etc.)
I wrote tailcat in September 2023 on a long ten-hour flight while catching up on bad movies. At the time, tailcat was mostly a fun novelty. I presented it internally, and I’d use it occasionally myself, but I mostly forgot about it. But then a number of customers approached us with use cases where it was a perfect fit, so we gave them copies of it, with arrangements where we’d host the DERP fallback relays for them in cases where tailcat’s use of Tailscale’s magicsock fails to get a direct connection.
Fast-forward to a few months ago, when all this AI agentic coding stuff was in full swing. It’s been really powerful to just give my sandboxed AI agents access to make their own also-untrusted nested VMs and give them tailcat. With access to exotic hardware in faraway places, I let the AI go wild wiring things up to each other and running experiments. Off the top of my head, I can recall:
- giving an agent access to a fleet of every Raspberry Pi generation
- giving an agent access to a sandboxed EC2 instance that had ambient access to control a nearby EC2 instance and
kexecreboot it repeatedly, while porting Tailscale to run in EC2’s UEFI environment, including porting the Amazon Nitro ENA network driver to pure Go (under Tamago) - giving an agent access to a Windows host to repeatedly create and destroy Hyper-V VMs to debug and fix a stack corruption bug in the Go runtime and standard library
In most of these cases, I probably technically could’ve just used Tailscale proper, but it would’ve been more tedious to the point that I probably wouldn’t have even done it, and would’ve just set up a few port forwards instead, or opened up some ports on a firewall somewhere. I find that tailcat is often the perfect tool when I already have two shells open on two machines in two very different worlds and I just want to connect the two together, for a quick file copy, or port forward, or letting one SSH to the other. Especially when one side is untrusted or ephemeral or I’m afraid to touch its system configuration.
When we launched Taildrop in 2021, one of the first requests was for netcat-like sharing between nodes. tailcat now provides that, and more. We’d still like to do something tailcat-like in the main Tailscale client too, but we’ll have to figure out how that fits into the rest of the Tailscale product.
Another reason to open source tailcat is that it’s kinda obvious and inevitable. We’d selfishly rather people be using, improving, and filing bugs against our data plane, which then makes the rest of the Tailscale product better.
I would be remiss if I didn’t mention that you should contact us if you have fun use cases where tailcat might help you, and where we can help you integrate tailcat or run a global fleet of DERP relays for you. (e.g. IoT, P2P games, distributed GPUs, etc.)
The DERP server fleet we’re running for tailcat is throttled and only available in a handful of regions around the world. The idea is that, most of the time, our magicsock NAT traversal will do its thing and DERP isn’t relevant, with tailcat getting a direct UDP WireGuard connection between the two peers. But in cases where that fails, we’d be happy to exchange money for goods and services.
Or, hey, run your own DERP fleet or single server. It’s open source too.
Enjoy!
We look forward to seeing what you build and how you use this. Give tailcat a spin here.
