Tailgate is a small, single-binary proxy that joins your Tailscale tailnet via tsnet and accepts SOCKS5 and HTTP CONNECT connections. Unlike a Tailscale exit node which routes all of a device's traffic through another node, Tailgate lets you selectively route only the traffic you choose -- per app, browser, or command.
- You want to route specific apps or browsers through your tailnet, not all traffic
- You can't (or don't want to) install the Tailscale daemon on the proxy host
- You need a proxy in a container, CI runner, or embedded device with no
/dev/net/tun - You want both SOCKS5 and HTTP CONNECT on one port with zero configuration
- Automatic protocol detection -- serves both SOCKS5 and HTTP CONNECT on a single port
- Joins your tailnet via tsnet -- no Tailscale daemon required on the proxy host
- Idle tunnel teardown -- tunnels with no traffic in either direction are cleaned up automatically
- Graceful shutdown -- drains active connections on SIGINT/SIGTERM
- Hardened request parsing -- caps CONNECT header size, returns proper 4xx errors
go install github.com/kljensen/tailgate@latestOr build from source (dependencies are vendored):
git clone https://github.com/kljensen/tailgate.git
cd tailgate
go build -mod vendor .tailgate [flags]
| Flag | Default | Description |
|---|---|---|
-hostname |
tailgate |
Tailscale hostname for this node |
-listen |
:1080 |
Address to listen on |
-state-dir |
(tsnet default) | Directory for tsnet state |
-verbose |
false |
Enable debug logging |
-version |
n/a | Print version and exit |
tailgate -hostname my-proxy -verboseOn first run, tsnet will print a login URL. Visit it to authorize the
node on your tailnet. State is saved to -state-dir (or a temp
directory by default), so subsequent runs reconnect automatically.
For headless or automated deployments, set TS_AUTHKEY:
TS_AUTHKEY=tskey-auth-... tailgate -hostname my-proxy -state-dir /var/lib/tailgateGenerate auth keys at https://login.tailscale.com/admin/settings/keys.
Use -state-dir for any persistent deployment so tsnet state survives
reboots.
# Via SOCKS5 (socks5h resolves DNS through the proxy)
curl --proxy socks5h://my-proxy:1080 https://example.com
# Via HTTP CONNECT
curl --proxy http://my-proxy:1080 https://example.comMany tools (curl, wget, git, python requests, etc.) respect the standard proxy environment variables:
export ALL_PROXY=socks5h://my-proxy:1080
# These then route through Tailgate
curl https://example.com
git clone https://github.com/user/repo.git
wget https://example.com/file.tar.gzFirefox
has built-in proxy settings -- set the SOCKS Host to my-proxy, port
1080, SOCKS v5, and check "Proxy DNS when using SOCKS v5" in Firefox.
Chrome and Safari use your operating system's proxy settings. See the
ArchWiki for a
comprehensive reference.
Tailgate listens on a single TCP port. When a connection arrives, it peeks
at the first byte: 0x05 means SOCKS5, anything else is parsed as an HTTP
CONNECT request (returning 400 if invalid). Both protocols establish a
bidirectional tunnel to the target host. Each side of the tunnel is wrapped
with an idle timeout so stale connections don't linger forever.
Tailgate listens via tsnet.Listen, so only devices on your Tailscale
network can connect. No proxy authentication is needed -- your tailnet
is the trust boundary. Use
Tailscale ACLs for finer-grained
access control.
- wireproxy -- the same idea for WireGuard
- Tailscale userspace networking -- Tailscale's built-in SOCKS5 proxy (requires the full daemon)
This is free and unencumbered software released into the public domain. See LICENSE for details.
