How to Use Tailcat with DNS TXT Records for Server Discovery

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 and the discovery logic in 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:


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


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


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


# 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, 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:


# Generate a client identity key

tailcat genkey --client

Then configure the server to accept only that identity:


# 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.
  • parseToken in 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 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.

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 →