How to Connect to a Tailcat Server: 4 Methods Explained

You can connect to a Tailcat server using the CLI for command forwarding, the browser-based Web UI via JavaScript bindings, standard SSH clients for SFTP, or any SOCKS5-compatible application.

Tailcat is a peer-to-peer TCP relay built on Tailscale's DERP network that enables secure connections without requiring public IP addresses. This guide explains how to connect to a Tailcat server using the different front-ends implemented in the tailscale/tailcat repository, referencing the actual source code structures that manage the connection lifecycle.

Understanding Tailcat's Connection Architecture

Before initiating a connection, it helps to understand how Tailcat establishes its peer-to-peer tunnels.

Ed25519 Key-Derived Addresses

Every Tailcat server generates an Ed25519 private key, hashing the public key to produce a human-readable address ending in .tc (e.g., example.tc:23). This address is stored in the server's Key field within the tailcat.Server struct defined in tailcat.go. Clients use this address to locate and authenticate the server.

DERP Relay and Handshake

Both client and server open a WireGuard-over-DERP tunnel using the tailcat.Client struct. The core connection flow involves:

  1. Fetching the DERP map from https://tailcat.dev/derpmap.json (or a custom DERPMapURL)
  2. Sending a "Meow" packet handshake request (implemented in tailcat/connblob_deprecated.go)
  3. Receiving a connection string containing the DERP region and unique session identifier
  4. Multiplexing logical TCP streams over the single DERP tunnel

How to Connect Using the CLI

The tailcat binary in cmd/tailcat/tailcat.go provides direct command forwarding through an encrypted tunnel.

Start a server on the remote machine:

tailcat -listen

The server prints its listen address to stderr (see lines 1523-1524 in cmd/tailcat/tailcat.go). For scripting, use the --json flag (line 1536) to emit the address in machine-readable format.

Connect from the client and run a command:

tailcat example.tc:23 curl https://ifconfig.me

The CLI creates a tunnel to the server, runs the command locally, and forwards I/O over the Tailcat connection.

How to Connect via the Web UI

The browser interface uses WebAssembly bindings defined in web/main_js.go to expose the connection logic to JavaScript.

Access the hosted demo at https://tailcat.dev/ or run the local server:

tailcat-web

The page provides "Listen" and "Dial" buttons that call the JavaScript globals tailcatListen and tailcatDial. From the browser console or embedded scripts (as seen in web/app.js at line 142):

const ln = await tailcatListen({ 
  derpMapURL, 
  privateKey, 
  verbose, 
  onConnection 
});

This spins up a server or client directly inside the browser for interactive file transfers or remote shell sessions.

How to Connect Using SSH

Tailcat implements a minimal SSH subsystem in tailcat_ssh.go that supports SFTP and a basic MOTD.

Start the SSH server:

tailcat -ssh -listen

Connect from the client using the built-in SSH client:

tailcat ssh example.tc:23

You will see the server's MOTD: "🐈 Connected via tailcat SSH" (defined at line 30 of tailcat_ssh.go). Note that the server only offers SFTP for file transfers, not a full shell environment. Standard sftp tools can interact with this subsystem.

How to Connect via SOCKS5 Proxy

The SOCKS5 proxy mode allows any application to route traffic through the Tailcat tunnel.

Create a local proxy server:

tailcat socks --listen=0.0.0.0:1080

Use any SOCKS5-compatible client. For example, with curl:

curl -x socks5h://localhost:1080 http://ifconfig.me

The proxy implementation resides in cmd/tailcat/socks.go, with the listener setup occurring in cmd/tailcat/tailcat.go at lines 1045-1061. Each TCP stream is forwarded through the Tailcat DERP tunnel to the destination.

Summary

  • Tailcat servers advertise Ed25519-derived addresses ending in .tc, stored in the Server.Key field
  • Four connection methods are available: CLI (tailcat <addr>), Web UI (tailcatListen/tailcatDial), SSH (tailcat ssh), and SOCKS5 (tailcat socks)
  • Core connection logic resides in tailcat.go, tailcat_client.go, and tailcat_server.go
  • Handshake mechanism uses "Meow" packets defined in tailcat/connblob_deprecated.go to establish the DERP tunnel

Frequently Asked Questions

What address format does Tailcat use for server identification?

Tailcat uses human-readable addresses derived from Ed25519 public key hashes, formatted as <base32-encoded-key>.tc with an optional port (e.g., example.tc:23). This address is generated by the server and stored in the Key field of the tailcat.Server struct according to the source code in tailcat.go.

How does the initial handshake work between client and server?

The client sends a "listen" or "dial" request encapsulated in a Meow packet to initiate the connection. The server responds with a connection string containing the DERP region and unique session identifier. This handshake logic is implemented in tailcat/connblob_deprecated.go within the core library, creating the encrypted tunnel over Tailscale's DERP network.

Can I use standard OpenSSH clients with Tailcat servers?

Yes, but with limitations. The Tailcat SSH subsystem (tailcat_ssh.go) only supports SFTP for file transfers and displays a minimal MOTD. You must use the tailcat ssh <addr> command rather than the standard ssh binary, as the Tailcat client implements the specific protocol handshake required to establish the DERP tunnel before SSH negotiation begins.

Is the Web UI connection method secure for production use?

The Web UI utilizes the same WireGuard-over-DERP encryption as the CLI, with JavaScript bindings (tailcatListen and tailcatDial in web/main_js.go) handling cryptographic operations in the browser. However, for production environments requiring automated authentication or integration with existing security tooling, the CLI or SOCKS5 proxy methods are recommended over the browser-based interface.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →