# How to Use Tailcat as a SOCKS5 Proxy: Complete Setup and Architecture Guide

> Learn how to use Tailcat as a SOCKS5 proxy. This guide covers complete setup and architecture, converting WireGuard to a local SOCKS5 proxy effortlessly.

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

---

**Tailcat converts encrypted Tunnel+WireGuard connections into a local SOCKS5 proxy by running `tailcat socks <token>` on the client, which starts a local TCP listener and forwards traffic through the Tailcat server while automatically injecting the `all_proxy` environment variable.**

Tailcat is an experimental tunneling tool from the Tailscale organization (`tailscale/tailcat`) that bridges lightweight WireGuard connections with application-layer proxies. When you use Tailcat as a SOCKS5 proxy, you create a local TCP endpoint that tunnels arbitrary traffic through an encrypted client-to-server circuit, allowing any SOCKS5-aware application to communicate securely without native integration.

## Architecture of Tailcat SOCKS5 Mode

The SOCKS5 implementation spans both client and server components, with the proxy logic running entirely within the client process.

### Server Component

The **Tailcat server** listens for inbound WireGuard connections and advertises a **ConnBlob token** that clients use to establish sessions. The core server implementation resides in [`cmd/tailcat/tailcat.go`](https://github.com/tailscale/tailcat/blob/main/cmd/tailcat/tailcat.go), specifically within the `newServer` function and the generic `Server` struct. The server itself does not implement SOCKS5 logic; it merely accepts encrypted tunnels and forwards traffic to the specified destination ports.

### Client SOCKS5 Implementation

The client-side SOCKS5 proxy is implemented in the `clientSOCKSMode` function (lines 93-104 of [`cmd/tailcat/tailcat.go`](https://github.com/tailscale/tailcat/blob/main/cmd/tailcat/tailcat.go)). This function:

1. Creates a local TCP listener defaulting to `socks5h://127.0.0.1:0` (random available port)
2. Instantiates a `socks5.Server` from the `tailscale.com/net/socks5` package
3. Passes a custom `Dialer` (defined in lines 55-72) that routes connections through the established Tailcat tunnel

### Address Classification and Routing

Tailcat uses the `classifySOCKSAddr` function (lines 618-653 of [`cmd/tailcat/tailcat.go`](https://github.com/tailscale/tailcat/blob/main/cmd/tailcat/tailcat.go)) to determine how to route each SOCKS5 request. The classification logic distinguishes between:

- **Tailcat tokens**: Destination hosts matching the token format (e.g., `tc1yRz…`) trigger a direct dial to the Tailcat server
- **Magic hostname**: The special name `server.tailcat` resolves to the Tailcat server itself
- **Standard destinations**: Regular hostnames or IPs are resolved via `lookupNetIP` and tunneled through the client-to-server circuit

Unit tests in [`cmd/tailcat/socks_test.go`](https://github.com/tailscale/tailcat/blob/main/cmd/tailcat/socks_test.go) (lines 31-88) validate these classification rules and edge cases.

## Step-by-Step SOCKS5 Configuration

### 1. Start the Tailcat Server

First, initialize a Tailcat server to generate an address token. The server exposes specific ports for tunneling:

```bash

# Start server on ports 8080 (HTTP) and 8443 (HTTPS)

$ tailcat --serve=8080,8443

# Output: 🐈 Server listening with new address: tc1yRz…

```

Copy the token (e.g., `tc1yRz…`) for the client connection.

### 2. Launch the SOCKS5 Proxy Client

Run the `tailcat socks` subcommand with the server token to start the local proxy:

```bash
$ tailcat socks tc1yRz…

```

By default, this binds to a random local port. The proxy remains active until interrupted, forwarding all SOCKS5 connections through the encrypted tunnel to the server.

### 3. Configure Application Environment

For applications that read standard environment variables, export `all_proxy` pointing to the Tailcat listener:

```bash
$ export all_proxy=socks5h://127.0.0.1:<port>
$ curl http://example.com/

```

## Command Execution with Automatic Proxy Injection

Tailcat can execute commands with the `all_proxy` environment variable pre-configured. When you append a command to `tailcat socks`, the client:

1. Starts the SOCKS5 listener
2. Sets `all_proxy=socks5h://<listen_address>` (implemented in `clientSOCKSMode`, lines 78-84 of [`cmd/tailcat/tailcat.go`](https://github.com/tailscale/tailcat/blob/main/cmd/tailcat/tailcat.go))
3. Executes the command via `exec`, replacing the tailcat process

```bash

# Automatically proxies wget through the Tailcat tunnel

$ tailcat socks tc1yRz… wget https://example.org/file.txt

```

## Advanced SOCKS5 Options

### Custom Listen Addresses

Bind the SOCKS5 proxy to a specific interface and port using the `--listen` flag:

```bash

# Bind to all interfaces on port 1080

$ tailcat socks --listen=:1080 tc1yRz… &
$ export all_proxy=socks5h://127.0.0.1:1080

```

### DNS-based Token Resolution

Tailcat supports resolving server tokens via DNS TXT records, eliminating the need to pass tokens explicitly on the command line:

```bash

# Assumes example.com has TXT record "tailcat=tc1yRz…"

$ tailcat socks example.com curl http://server.tailcat:8081/

```

The client queries DNS for the TXT record, extracts the token, and establishes the tunnel before processing the SOCKS5 request.

## Summary

- **Tailcat implements SOCKS5 entirely on the client side** through the `clientSOCKSMode` function in [`cmd/tailcat/tailcat.go`](https://github.com/tailscale/tailcat/blob/main/cmd/tailcat/tailcat.go), using the `tailscale.com/net/socks5` library
- **Traffic classification** via `classifySOCKSAddr` routes Tailcat tokens to the server and standard hostnames through the tunnel
- **Automatic environment injection** sets `all_proxy=socks5h://<addr>` when running commands via `tailcat socks`
- **Flexible addressing** supports explicit tokens, the `server.tailcat` magic hostname, or DNS TXT record resolution
- **Local binding** defaults to random ports on 127.0.0.1 but supports custom `--listen` configurations for network-wide proxy access

## Frequently Asked Questions

### What is the default SOCKS5 listen address in Tailcat?

By default, Tailcat binds to `socks5h://127.0.0.1:0` (a random available port on localhost) when running in SOCKS5 mode. The actual port is selected by the operating system and displayed when the proxy starts, or you can specify a fixed address using the `--listen` flag.

### How does Tailcat route different types of SOCKS5 destinations?

According to `classifySOCKSAddr` in [`cmd/tailcat/tailcat.go`](https://github.com/tailscale/tailcat/blob/main/cmd/tailcat/tailcat.go) (lines 618-653), Tailcat inspects the destination hostname. If it matches a Tailcat token format (starting with `tc`), the proxy dials the Tailcat server directly. If it matches `server.tailcat`, it routes to the server itself. All other hostnames or IPs undergo standard DNS resolution via `lookupNetIP` before being tunneled through the WireGuard connection.

### Can applications use Tailcat's SOCKS5 proxy without code modifications?

Yes. Any application that respects the `all_proxy` or `http_proxy` environment variables can use Tailcat's SOCKS5 proxy without modification. Additionally, you can configure specific applications (like `curl`, `wget`, or OpenSSH via `ProxyCommand` as shown in [`cmd/tailcat/ssh.go`](https://github.com/tailscale/tailcat/blob/main/cmd/tailcat/ssh.go)) to use `socks5h://127.0.0.1:<port>` explicitly.

### Is it possible to run Tailcat SOCKS5 without passing the token on the command line?

Yes. Tailcat supports DNS TXT record-based token resolution. If you provide a hostname (instead of a token) to `tailcat socks`, the client queries DNS for a TXT record containing `tailcat=<token>`, extracts the token, and uses it to establish the connection. This allows teams to distribute server addresses through DNS infrastructure rather than command-line arguments.