# How to Start a Tailcat Server That Prints Its Connection Token

> Learn how to start a Tailcat server and print its connection token. Get your Tailcat server token easily with our step-by-step guide.

- Repository: [Tailscale/tailcat](https://github.com/tailscale/tailcat)
- Tags: how-to-guide
- Published: 2026-08-30

---

**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.

```sh
$ 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:

```sh
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:

```sh

# 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`](https://github.com/tailscale/tailcat/blob/main/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`](https://github.com/tailscale/tailcat/blob/main/tailcat.go):

```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:

```go
	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`](https://github.com/tailscale/tailcat/blob/main/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`](https://github.com/tailscale/tailcat/blob/main/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`](https://github.com/tailscale/tailcat/blob/main/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`](https://github.com/tailscale/tailcat/blob/main/tailcat.go), while the CLI wrapper and flag parsing are implemented in [`cmd/tailcat/tailcat.go`](https://github.com/tailscale/tailcat/blob/main/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`](https://github.com/tailscale/tailcat/blob/main/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`](https://github.com/tailscale/tailcat/blob/main/tailcat.go). You must successfully call `Start()` and wait for it to return before calling `ConnBlob()`, or the token will be empty or invalid.