How to Start a Tailcat Server That Prints Its Connection Token

Run the tailcat CLI to automatically emit a connection token (ConnBlob) to stdout, or instantiate tailcat.Server in Go, call Start(), then print s.ConnBlob() to programmatically expose the token.

Tailcat is a secure tunneling tool from the Tailscale ecosystem that generates a unique cryptographic token upon startup. When you start a Tailcat server, it outputs a ConnBlob—a base64-encoded identifier that clients use to establish authenticated tunnels. This guide explains both command-line and programmatic methods to start the server and capture its token, based on the tailscale/tailcat source code.

Command-Line Usage

Running the tailcat executable without arguments starts a server on an automatically chosen port (port 0) and immediately prints the connection token.

$ tailcat
tc1LzR0KxY...   # ← connection token (ConnBlob) emitted on stdout

The server listens indefinitely after printing the token. You can capture the token to a shell variable for scripting:

TOKEN=$(tailcat)
echo "Server token: $TOKEN"

Configuring Exposed Ports and Services

Use the --serve flag to specify which ports or services the server exposes. The token is still printed to stdout after the server initializes:


# Serve ports 80 and 443, plus an auth-free SSH server

$ tailcat --serve=80,443,no-auth-ssh
tc1LzR0KxY...

This parsing logic is implemented in cmd/tailcat/tailcat.go, which wraps the core server type and handles flag processing before printing s.ConnBlob().

Go API Implementation

To embed Tailcat in your own application, import github.com/tailscale/tailcat and interact with the Server type directly.

Creating a Server Instance

Instantiate tailcat.Server and optionally define an OnTCP callback to handle incoming connections. This configuration lives in tailcat.go:

package main

import (
	"fmt"
	"log"
	"net"

	"github.com/tailscale/tailcat"
)

func main() {
	s := &tailcat.Server{
		// Optional: per-port handler; here we simply write a greeting.
		OnTCP: func(port uint16) func(net.Conn) {
			return func(c net.Conn) {
				fmt.Fprintf(c, "hello from port %v\n", port)
				c.Close()
			}
		},
	}

Starting the Server and Retrieving the Token

Call Start() to initialize the listener, then invoke ConnBlob() to retrieve the token string. The Start() method blocks until the server is ready, at which point the token is available:

	if err := s.Start(); err != nil {
		log.Fatal(err)
	}
	// The connection token is available after successful startup.
	fmt.Println(s.ConnBlob())
	select {} // Keep the server running indefinitely.
}

The ConnBlob() method, defined in tailcat.go, generates the token using the server's cryptographic identity material.

Source Code Architecture

The Tailcat repository separates concerns into two primary files:

  • cmd/tailcat/tailcat.go: The CLI entry point that parses --serve flags, constructs the Server object, calls Start(), and prints the token to stdout via fmt.Println(s.ConnBlob()).
  • tailcat.go: Defines the Server struct, the Start() initialization method, and the ConnBlob() accessor that generates the base64-encoded connection token.

Summary

  • Run tailcat without arguments to start a server on a random port and print the ConnBlob token to stdout automatically.
  • Use the --serve flag to configure specific ports and services like no-auth-ssh before the token is emitted.
  • In Go programs, instantiate tailcat.Server, call s.Start(), then access s.ConnBlob() to retrieve the token programmatically.
  • The token generation logic resides in tailcat.go, while the CLI wrapper and flag parsing are implemented in cmd/tailcat/tailcat.go.

Frequently Asked Questions

What format is the Tailcat connection token?

The token is a base64-encoded ConnBlob string that uniquely identifies the server instance. It typically starts with the prefix tc followed by alphanumeric characters and encodes the server's cryptographic public key and connection parameters.

How do I capture the token when starting Tailcat from a script?

Use shell command substitution to store the output in a variable: TOKEN=$(tailcat). For the Go API, assign the return value of s.ConnBlob() to a string variable immediately after checking that s.Start() returns a nil error.

Can I specify which ports the Tailcat server exposes?

Yes. Pass the --serve flag with comma-separated values such as 80,443,no-auth-ssh when running the CLI. This configures the built-in TCP forwarders and SSH server before the token is printed, as handled in cmd/tailcat/tailcat.go.

Is the connection token available before the server starts listening?

No. The ConnBlob is generated during the Start() method's initialization phase in tailcat.go. You must successfully call Start() and wait for it to return before calling ConnBlob(), or the token will be empty or invalid.

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 →