# How to Run a Minimal Tailcat Server in Go

> Easily run a minimal Tailcat server in Go. Set up a WireGuard tunnel and DERP connection quickly. Share tokens for secure, encrypted client connections.

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

---

**Create a `tailcat.Server` value with optional TCP handling, call `Start()` to initialize the WireGuard tunnel and DERP connection, then share the base64 token from `ConnBlob()` with clients to establish encrypted connections.**

Tailcat is a lightweight, userspace WireGuard tunnel implementation that routes traffic through Tailscale's DERP relays. The `tailscale/tailcat` repository provides a Go library that allows you to run a minimal server with just a few lines of code, requiring no kernel modules or root privileges. This guide explains how to leverage the zero-value `Server` struct to spin up an encrypted tunnel server based on the actual source implementation.

## Understanding the Tailcat Server Architecture

Tailcat operates entirely in userspace, bypassing the need for kernel WireGuard modules while maintaining encrypted connectivity through Tailscale's global DERP infrastructure. The core implementation resides in [`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go), where the `Server` struct (defined at lines 77-85) orchestrates ephemeral key generation, nearest DERP region discovery, and WireGuard setup.

Unlike traditional VPN servers requiring extensive configuration, Tailcat's `Server` type uses sensible defaults when instantiated as a zero value. This design automatically provisions an ephemeral WireGuard key pair, selects the geographically closest DERP relay, and configures a basic logger without explicit initialization.

## Creating a Minimal Tailcat Server

To run a minimal Tailcat server, instantiate the `Server` struct, optionally configure connection handling, invoke the startup sequence, and retrieve the connection token for clients.

### Step 1: Instantiate the Server

Create a `tailcat.Server` value. The zero-value provides production-ready defaults:

```go
s := &tailcat.Server{}

```

### Step 2: Configure TCP Handling (Optional)

Set the `OnTCP` field to define how the server responds to incoming TCP connections. This field accepts a function that receives a port number and returns a `net.Conn` handler:

```go
s := &tailcat.Server{
    OnTCP: func(port uint16) func(net.Conn) {
        return func(c net.Conn) {
            fmt.Fprintf(c, "hello from port %v\n", port)
            c.Close()
        }
    },
}

```

### Step 3: Start the Server

Call the `Start()` method (implemented at lines 52-60 in [`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go)) to initialize the WireGuard interface, connect to the DERP relay, and begin listening for incoming connections:

```go
if err := s.Start(); err != nil {
    log.Fatal(err)
}

```

### Step 4: Retrieve the Connection Token

The `ConnBlob()` method returns a short base64-encoded string containing the server's WireGuard public key and DGRP routing information. Clients require this token to establish the tunnel:

```go
fmt.Println(s.ConnBlob())

```

### Complete Minimal Server Example

```go
package main

import (
	"fmt"
	"log"
	"net"

	"github.com/tailscale/tailcat"
)

func main() {
	// Create a server with a simple TCP handler.
	s := &tailcat.Server{
		OnTCP: func(port uint16) func(net.Conn) {
			return func(c net.Conn) {
				fmt.Fprintf(c, "hello from port %v\n", port)
				c.Close()
			}
		},
	}
	// Start the server – this connects to a DERP relay,
	// generates an ephemeral WireGuard key and begins listening.
	if err := s.Start(); err != nil {
		log.Fatal(err)
	}
	// Print the connection token that the client will use.
	fmt.Println(s.ConnBlob())
	// Block forever (or add your own shutdown logic).
	select {}
}

```

Run the server with:

```bash
go run ./minimal_server.go

```

The terminal will output a token similar to `tcWcL4Q5d7f...` that clients use to connect.

## Connecting Clients to Your Server

Clients can connect using the CLI wrapper located in [`cmd/tailcat/tailcat.go`](https://github.com/tailscale/tailcat/blob/main/cmd/tailcat/tailcat.go) or programmatically using the library. Pass the token printed by `ConnBlob()` as the connection argument:

```bash
tailcat <token>

```

Alternatively, implement a client in Go using the `tailcat` package to dial the server using the same token string.

## Understanding the DERP Integration

The server automatically connects to the nearest Tailscale DERP (Designated Encrypted Relay for Packets) region during startup. This relay handles the initial key exchange and maintains the encrypted tunnel when direct peer-to-peer connectivity is unavailable due to NAT or firewall restrictions. The DERP selection logic and WireGuard configuration occur within the `Start()` method, requiring no manual intervention.

## Summary

- The `tailcat.Server` zero-value in [`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go) provides sensible defaults including ephemeral WireGuard keys and automatic DERP region selection
- The `Server` struct is defined at lines 77-85 in [`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go), with the `Start()` method implementing initialization logic at lines 52-60
- `ConnBlob()` generates a base64-encoded connection token containing the WireGuard public key and DERP routing information required for client authentication
- Incoming TCP connections are handled via the configurable `OnTCP` callback, which receives the port number and returns a `net.Conn` handler function
- The CLI implementation in [`cmd/tailcat/tailcat.go`](https://github.com/tailscale/tailcat/blob/main/cmd/tailcat/tailcat.go) demonstrates production usage of the library for command-line server and client operations

## Frequently Asked Questions

### What is the difference between Tailcat and standard WireGuard?

Tailcat operates entirely in userspace without requiring kernel modules or root privileges, whereas standard WireGuard typically requires kernel support and administrative access. Tailcat routes traffic through Tailscale's DERP relays when direct UDP connectivity is unavailable, making it functional behind restrictive NATs and corporate firewalls where traditional WireGuard might fail.

### How do clients connect to a Tailcat server?

Clients use the base64 token returned by the server's `ConnBlob()` method. This token encodes the server's WireGuard public key and DERP region information. Pass this token to the `tailcat` CLI or use it with the `Client` type in the Go library to establish the encrypted tunnel and begin routing traffic.

### Can I run a Tailcat server without handling TCP connections?

Yes. The `OnTCP` field is optional; if left nil, the server will establish the WireGuard tunnel and DERP connection but reject incoming TCP connections. This configuration is useful when you only need the tunnel infrastructure without exposing services, or when implementing custom protocol handlers outside the `OnTCP` callback pattern.

### Where is the main server logic implemented in the source code?

The core server implementation resides in [`tailcat.go`](https://github.com/tailscale/tailcat/blob/main/tailcat.go) at the repository root. The `Server` struct definition appears at lines 77-85, while the initialization logic including DERP discovery and WireGuard setup is contained within the `Start()` method at lines 52-60. The command-line interface wrapping this library is implemented in [`cmd/tailcat/tailcat.go`](https://github.com/tailscale/tailcat/blob/main/cmd/tailcat/tailcat.go).