How to Generate a Persistent WireGuard Key for Tailcat

To generate a persistent WireGuard key for Tailcat, either let the binary create it automatically at $HOME/.config/tailcat/wireguard.key on first launch, or manually generate one using wg genkey and place it in that location; Tailcat reuses this key across restarts to maintain a stable network identity.

Tailcat is a networking utility from the tailscale/tailcat repository that establishes secure connections using WireGuard. According to the source code, the application manages cryptographic identity persistence by automatically generating and storing private keys in the user's configuration directory, eliminating the need for manual key management in typical deployments.

Automatic Key Generation on First Run

When Tailcat initializes, the logic in config.go checks for an existing private key file. If the file does not exist, the program invokes the generation routine in wire.go, which calls tailscale.com/wgkey.NewPrivateKey() to create a cryptographically secure private key. The application then writes this key to the configuration directory with restrictive permissions, ensuring it persists for subsequent executions.

To trigger automatic generation, simply execute the Tailcat binary:

./tailcat

On first run, Tailcat creates the directory $HOME/.config/tailcat/ (respecting $XDG_CONFIG_HOME on Linux) and writes the wireguard.key file containing the base64-encoded private key.

Manual Key Generation Methods

For infrastructure-as-code deployments or when you require key control before the first execution, you can generate the key manually using two approaches supported by the Tailcat architecture.

Using the WireGuard Command-Line Tools

The standard WireGuard utilities provide the simplest method for key generation. Create the configuration directory and generate the key in one pipeline:


# Create the config directory and generate the key

mkdir -p "$HOME/.config/tailcat"
wg genkey | tee "$HOME/.config/tailcat/wireguard.key"

# Set restrictive permissions (owner read/write only)

chmod 600 "$HOME/.config/tailcat/wireguard.key"

This approach uses the wg genkey utility to produce a Curve25519 private key and immediately persists it to the location Tailcat expects.

Programmatic Generation with Go

For applications integrating Tailcat's logic directly, replicate the exact method used in wire.go by importing the Tailscale wireless key library:

package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"tailscale.com/wgkey"
)

func main() {
	// Generate a new private WireGuard key using Tailcat's implementation
	priv, err := wgkey.NewPrivateKey()
	if err != nil {
		panic(err)
	}

	// Encode in the format Tailcat expects (base64 string plus newline)
	data := []byte(priv.String() + "\n")

	// Determine configuration directory
	cfgDir, _ := os.UserConfigDir()
	keyPath := filepath.Join(cfgDir, "tailcat", "wireguard.key")
	
	// Ensure directory exists with appropriate permissions
	if err := os.MkdirAll(filepath.Dir(keyPath), 0o700); err != nil {
		panic(err)
	}
	
	// Write key with restricted permissions (0o600 = owner read/write only)
	if err := ioutil.WriteFile(keyPath, data, 0o600); err != nil {
		panic(err)
	}

	fmt.Printf("Persistent WireGuard key written to %s\n", keyPath)
}

This Go implementation mirrors the behavior in wire.go, utilizing wgkey.NewPrivateKey() to ensure cryptographic compatibility with Tailcat's WireGuard stack.

Configuration File Locations

Tailcat follows platform-specific conventions for configuration storage:

  • Linux: $HOME/.config/tailcat/wireguard.key (or $XDG_CONFIG_HOME/tailcat/wireguard.key if set)
  • macOS: $HOME/Library/Application Support/tailcat/wireguard.key
  • Windows: %AppData%\tailcat\wireguard.key

The key file must contain a single line with the base64-encoded private key. When config.go loads on startup, it reads this file and derives the corresponding public key automatically for WireGuard handshake negotiations.

Security Best Practices

The private key generated for Tailcat operations requires strict confidentiality:

  • File permissions: Always set 0o600 (read/write for owner only) on the key file. Both automatic generation and manual scripts must respect this permission mask.
  • Backup considerations: If you back up the key, encrypt the backup. Anyone with access to this private key can impersonate your node on the WireGuard network.
  • Rotation: To rotate keys, delete the wireguard.key file and restart Tailcat. The application will generate a new key in wire.go and establish a fresh network identity.

Summary

  • Automatic approach: Run Tailcat once to trigger the generation logic in wire.go, which creates the key at the platform-appropriate config path.
  • Manual approach: Use wg genkey or the Go wgkey.NewPrivateKey() API to create the key file before launching the application.
  • Key location: Store the file at $HOME/.config/tailcat/wireguard.key (Linux) or the equivalent platform-specific path handled by config.go.
  • Permissions: Always restrict the key file to 0o600 to prevent unauthorized access.
  • Persistence: Once created, Tailcat reuses this key across all subsequent executions, maintaining a stable WireGuard public key for network authentication.

Frequently Asked Questions

Where does Tailcat store the WireGuard private key?

Tailcat stores the private key in your user configuration directory under a subdirectory named tailcat. On Linux systems, this defaults to $HOME/.config/tailcat/wireguard.key. The exact path determination logic resides in config.go, which respects platform standards such as $XDG_CONFIG_HOME on Linux and Library/Application Support on macOS.

Can I use an existing WireGuard key with Tailcat?

Yes. If you have an existing private key generated by wg genkey or another WireGuard-compatible tool, you can place it at the expected configuration path. Ensure the file contains only the base64-encoded private key followed by a newline, and set permissions to 0o600. Tailcat's config.go loader will accept any valid Curve25519 private key that conforms to the WireGuard specification.

What happens if I delete the wireguard.key file?

If you delete the key file and restart Tailcat, the automatic generation routine in wire.go triggers immediately upon startup. The application generates a new private key using wgkey.NewPrivateKey(), writes it to the configuration directory, and uses the new key for all subsequent connections. This effectively rotates your node's WireGuard identity, though you will need to re-authenticate with any coordination servers or peers that whitelist specific public keys.

Is the private key generated by Tailcat compatible with standard WireGuard tools?

Yes. Tailcat uses the standard WireGuard key format implemented in the tailscale.com/wgkey package. The private keys are standard Curve25519 keys encoded in base64, fully compatible with wg, wg-quick, and other WireGuard implementations. You can extract the key from Tailcat's config directory and use it with other tools, or import keys generated by wg genkey into Tailcat.

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 →