# How to Use Tailcat with DNS TXT Records for Server Discovery

> Learn how to use Tailcat with DNS TXT records to discover remote servers. Connect via hostname using ConnBlob tokens for easier server access.

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

---

**Tailcat discovers remote servers by retrieving a connection token (ConnBlob) from DNS TXT records formatted as `tailcat=<token>`, allowing clients to connect via hostname instead of raw tokens.**

Tailcat is the experimental WireGuard-based remote access tool from the `tailscale/tailcat` repository that enables secure server discovery through standard DNS infrastructure. By publishing connection tokens as DNS TXT records, you can expose Tailcat services under human-readable domain names without embedding sensitive strings in automation scripts or documentation. This approach leverages the `parseToken` routine in [`main/tailcat.go`](https://github.com/tailscale/tailcat/blob/main/main/tailcat.go) and the discovery logic in [`main/disco.go`](https://github.com/tailscale/tailcat/blob/main/main/disco.go) to resolve hostnames into WireGuard connection parameters.

## How DNS TXT Record Discovery Works

When you supply a hostname where Tailcat expects a connection token, the client invokes the **`parseToken`** function to determine whether the argument is a URL-compatible hostname. If the validation succeeds, Tailcat performs a DNS TXT query searching for a record prefixed with **`tailcat=`**.

The retrieved token—referred to internally as the **ConnBlob**—is a CBOR-encoded structure containing the server's WireGuard public key and DERP relay endpoint information. Once extracted from DNS, the token undergoes the same decoding pipeline as a manually provided string, yielding the cryptographic material required for the WireGuard handshake over magicsock/DERP transport.

This mechanism decouples service addressing from key distribution: DNS provides location, while WireGuard provides authentication.

## Generating a Persistent Server Key

To ensure your DNS records remain valid across server restarts, you must generate a stable key that embeds a fixed DERP region. Without this step, the server generates ephemeral tokens that change on every launch, invalidating your DNS configuration.

Generate a persistent key using the `--fixed-region` flag:

```bash

# Create a saved key that embeds the nearest DERP region

tailcat genkey --fixed-region

# Example output (token printed)

tc1ABCdefGHIjklMNOpqrSTUvWxyZ...

```

The command outputs a connection token starting with `tc1` that encodes both the server's identity and its preferred relay region. Save this token securely; it represents the stable identity you will publish in DNS.

## Publishing the Token as a DNS TXT Record

With your persistent token in hand, create a DNS TXT record at your authoritative nameserver. The record name must match the hostname clients will use, and the content must exactly match the `tailcat=<token>` format.

Add the following record to your DNS zone:

```text

# In your DNS provider UI (or via nsupdate)

my-server.example.com. 300 IN TXT "tailcat=tc1ABCdefGHIjklMNOpqrSTUvWxyZ..."

```

Set an appropriate TTL (300 seconds in the example above) to balance propagation speed against cache duration. The prefix `tailcat=` is mandatory; the parser in [`main/disco.go`](https://github.com/tailscale/tailcat/blob/main/main/disco.go) specifically searches for this substring to distinguish Tailcat tokens from unrelated TXT data.

## Starting the Server with Persistent Keys

Start the Tailcat server using the saved key stored on disk. The server automatically loads the default identity unless you specify an alternative path.

```bash

# The server automatically loads the saved key (default)

tailcat --serve=22

# Output shows the server is listening with the saved token

# 🐈 Server listening with saved key "default": tc1ABCdefGHIjklMNOpqrSTUvWxyZ...

```

The `--serve=22` flag exposes SSH on port 22. Because the server initializes with the pre-generated key, the WireGuard public key and DERP coordinates remain constant, ensuring that existing DNS TXT records continue resolving to valid connection parameters.

## Connecting Clients via Hostname

Clients can now connect using the domain name instead of the raw token. When you execute a subcommand with a hostname argument, Tailcat transparently performs the DNS TXT lookup, extracts the token, and initiates the WireGuard handshake.

```bash

# The client performs a DNS-TXT lookup for the token

tailcat ssh my-server.example.com

# Or any other subcommand, e.g.:

tailcat ping my-server.example.com
tailcat socks my-server.example.com curl http://server.tailcat:8081/

```

According to the source code in [`main/tailcat.go`](https://github.com/tailscale/tailcat/blob/main/main/tailcat.go), this hostname resolution occurs early in the argument parsing phase, meaning all Tailcat subcommands that accept connection tokens inherently support DNS-based discovery.

## Restricting Access with Client Keys

For environments requiring additional authorization layers, you can generate client-specific keys and restrict server access to specific node keys.

Generate a client identity:

```bash

# Generate a client identity key

tailcat genkey --client

```

Then configure the server to accept only that identity:

```bash

# Allow only this client on the server

tailcat --serve=22 --allow=nodekey:cfb6bf...ddfd16

```

Even when using DNS discovery, the WireGuard handshake remains subject to these authorization checks, ensuring that possession of the DNS TXT record alone does not grant network access.

## Summary

- **ConnBlob tokens** encode WireGuard keys and DERP endpoints in a CBOR structure.
- **DNS TXT records** must use the exact format `tailcat=<token>` to be recognized by the discovery logic in [`main/disco.go`](https://github.com/tailscale/tailcat/blob/main/main/disco.go).
- **`parseToken`** in [`main/tailcat.go`](https://github.com/tailscale/tailcat/blob/main/main/tailcat.go) automatically detects hostnames and triggers DNS lookups when URLs are supplied instead of raw tokens.
- **Stable keys** generated with `--fixed-region` prevent token rotation and DNS staleness.
- WireGuard authentication occurs independently of DNS, maintaining cryptographic security even when tokens are publicly readable in DNS.

## Frequently Asked Questions

### What is the exact format required for Tailcat DNS TXT records?

DNS TXT records must contain exactly one string starting with `tailcat=` followed immediately by the connection token. For example: `"tailcat=tc1ABCdefGHIjklMNOpqrSTUvWxyZ..."`. The parser in [`main/disco.go`](https://github.com/tailscale/tailcat/blob/main/main/disco.go) splits TXT record strings and searches for this prefix to extract the token for CBOR decoding.

### Does publishing the token in DNS compromise security?

No. The DNS TXT record contains the **ConnBlob**, which includes the server's public WireGuard key and DERP coordinates. While this information is sensitive to enumeration, the actual connection requires the client to possess a private key authorized by the server (or vice versa depending on configuration). The WireGuard handshake provides cryptographic authentication independent of how the connection token was discovered.

### Can I use any DNS provider for Tailcat server discovery?

Yes, provided the provider supports standard DNS TXT records. Tailcat uses the system's default resolver mechanisms as implemented in the Go standard library, queried during the `parseToken` execution flow. No proprietary APIs or special record types are required.

### How do I rotate a Tailcat token published in DNS?

Generate a new persistent key using `tailcat genkey --fixed-region`, update the DNS TXT record to contain the new `tailcat=<newtoken>` value, and wait for TTL propagation. Clients will resolve the new token on subsequent connections while existing WireGuard sessions remain valid until naturally rotated or explicitly disconnected.