Understanding the `--fixed-region` Flag in `tailcat genkey`

The --fixed-region flag discovers the nearest DERP region once during key generation and embeds that region identifier directly into the generated token and key file, ensuring the server binds to the same region across restarts.

The tailcat tool from the tailscale/tailcat repository enables secure TCP tunnels over Tailscale. When running tailcat genkey, the --fixed-region flag determines how the server selects its Designated Encrypted Relay Protocol (DERP) region—either pinning it permanently at generation time or deferring the choice until startup.

How --fixed-region Works

When you invoke tailcat genkey --fixed-region, the tool performs a one-time DERP discovery probe to identify the geographically nearest relay region. According to the source code in cmd/tailcat/tailcat.go at line 1000, this boolean flag triggers an immediate region selection that gets persisted in two places:

  • The private key file stored at ~/.config/tailcat/keys/default.private.json
  • The connection token (beginning with tc…) printed to stdout

This baked-in region identifier ensures that subsequent server restarts use the exact same relay without re-probing the DERP map. The detailed rationale appears in README.md lines 94-100, which explains that this behavior keeps DNS-published tokens valid for future clients even after the server process restarts.

Default Behavior vs. Fixed Region Selection

Without the --fixed-region flag, tailcat genkey defaults to --region=auto. This stores a "pick at startup" directive in the key file rather than a specific region ID.

Default (--region=auto):

  • Region selection occurs every time the server starts
  • The server may bind to different DERP relays after restarts
  • Tokens remain valid but endpoint consistency is not guaranteed

Fixed (--fixed-region):

  • Region is selected once during key generation
  • The same DERP region is used for the lifetime of the key
  • Critical for stable DNS records and firewall rules

The flag parser in cmd/tailcat/tailcat.go enforces mutual exclusion—you cannot use --fixed-region simultaneously with an explicit --region=<name> argument.

Practical Usage Examples

Generating a Fixed-Region Key

Use the following command to create a server key locked to the nearest DERP region:


# Generate a server key with region pinned at creation time

$ tailcat genkey --fixed-region

# → writes ~/.config/tailcat/keys/default.private.json

# → prints a token (tc…); the token already contains the chosen region ID

The generated token encodes the region identifier, meaning any client connecting with this token will route through the same DERP relay regardless of when the server last restarted.

Programmatic Usage in Go

When using the Tailcat Go library directly, the Server struct handles region configuration through its initialization flow. While the library automatically picks the nearest region when starting with a zero-value configuration, keys generated with --fixed-region override this behavior by reading the embedded region from the token:

package main

import (
    "fmt"
    "log"
    "net"

    "github.com/tailscale/tailcat"
)

func main() {
    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()
            }
        },
    }
    if err := s.Start(); err != nil {
        log.Fatal(err)
    }
    fmt.Println(s.ConnBlob()) // token embeds the fixed DERP region
}

The tailcat.go file contains the core server implementation that consumes this baked-in region information from the connection token when Start() is called.

Source Code Implementation

The --fixed-region flag is implemented across several files in the tailscale/tailcat repository:

  • cmd/tailcat/tailcat.go (line 1000): Defines the boolean flag, its description, and enforces mutual exclusion with the --region argument
  • disco.go: Handles the actual DERP discovery logic used during the one-time probe when --fixed-region is requested
  • pickregion.go: Contains the fallback region selection logic used when the flag is not set (automatic selection mode)
  • README.md (lines 94-100): Documents the user-level behavior and explains that the nearest DERP region is discovered once and reused on subsequent restarts

When the flag is active, the region selection logic in disco.go runs during key generation rather than server startup, with the result persisted by the key storage handler in the main command file.

Summary

  • --fixed-region performs DERP discovery once at key-generation time and stores the region ID in both the key file and connection token
  • Default behavior (--region=auto) defers region selection until server startup, potentially choosing different regions after restarts
  • Use case: Essential for maintaining stable DNS records and ensuring tokens remain valid across server restarts
  • Implementation: Defined in cmd/tailcat/tailcat.go with discovery logic in disco.go and storage handled by the core server in tailcat.go
  • Mutual exclusion: Cannot be combined with explicit --region=<name> arguments

Frequently Asked Questions

What is a DERP region in Tailscale?

A DERP (Designated Encrypted Relay Protocol) region is a relay server that helps establish connections when direct peer-to-peer links are impossible due to NAT or firewall constraints. Each region consists of multiple servers in a specific geographic location, and Tailscale clients automatically select the nearest low-latency region for optimal performance.

Can I change the region after generating a key with --fixed-region?

No, the region is permanently embedded in the private key file and connection token. To use a different DERP region, you must generate a new key pair using tailcat genkey --fixed-region (which selects the new nearest region) or explicitly specify a region with --region=<name> without using the --fixed-region flag.

Does --fixed-region conflict with the --region flag?

Yes, these options are mutually exclusive. The command-line parser in cmd/tailcat/tailcat.go enforces that you cannot use --fixed-region alongside an explicit --region=<name> argument. You must choose between automatic discovery at generation time (--fixed-region), manual specification (--region=<name>), or automatic discovery at startup (default).

Where is the fixed region identifier stored?

The region identifier is stored in two locations: first, in the private key JSON file at ~/.config/tailcat/keys/default.private.json on the server; second, encoded within the connection token string (starting with tc…) that the command prints. The server reads this identifier from the key file on startup, while clients receive it through the token.

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 →