ts-unplug-proxy runs local SOCKS5 and/or HTTP proxies that dial requested destinations through a tsnet.Server.
ts-unplug-proxy allows you to:
- Use one local proxy process for many tailnet services
- Let proxy-aware tools choose the remote hostname and port
- Resolve tailnet hostnames through Tailscale status/DNS instead of local DNS
- Avoid running one fixed local port mapping per remote service
This differs from ts-unplug, which maps one local TCP port to one fixed remote target.
Build from source:
make ts-unplug-proxyInstall to $GOPATH/bin:
make installts-unplug-proxy -dir <state-dir> (-socks5 <listen:port> | -http <listen:port>) [options]Start a SOCKS5 proxy:
ts-unplug-proxy -dir ./state -socks5 localhost:1080
curl --socks5-hostname localhost:1080 http://myserver.tailnet.ts.netFor SOCKS5, use socks5h:// or --socks5-hostname so the client sends the hostname to the proxy. Tailnet names are resolved from Tailscale status/DNS; public names fall back to normal tsnet egress.
Start an HTTP proxy:
ts-unplug-proxy -dir ./state -http localhost:8080
curl -x http://localhost:8080 http://myserver.tailnet.ts.netStart both on different ports:
ts-unplug-proxy -dir ./state -socks5 localhost:1080 -http localhost:8080Start both on the same port:
ts-unplug-proxy -dir ./state -socks5 localhost:1080 -http localhost:1080-
-dir- Directory for tsnet server state- Stores Tailscale authentication and connection state
- Example:
-dir ./state,-dir /var/lib/tsunplug-proxy
-
At least one listener flag:
-socks5 <listen:port>- Enable a SOCKS5 proxy listener-http <listen:port>- Enable an HTTP proxy listener
-
-v- Log proxy connections and proxy dialsts-unplug-proxy -dir ./state -v -socks5 localhost:1080
-
-vv- Log proxy connections, proxy dials, andtsnet.Serverdebug infots-unplug-proxy -dir ./state -vv -socks5 localhost:1080
Use SOCKS5 hostname mode so the tailnet DNS name is sent to the proxy:
ts-unplug-proxy -dir ./state -socks5 localhost:1080
curl --socks5-hostname localhost:1080 http://api-staging.tailnet.ts.netFor proxy URLs, use socks5h:// rather than socks5:// when the client supports it:
ALL_PROXY=socks5h://localhost:1080 curl http://api-staging.tailnet.ts.netts-unplug-proxy -dir ./state -http localhost:8080
curl -x http://localhost:8080 http://api-staging.tailnet.ts.netHTTPS through the HTTP proxy uses CONNECT:
curl -x http://localhost:8080 https://api-staging.tailnet.ts.netStart one or both proxy listeners:
ts-unplug-proxy -dir ./state -socks5 localhost:1080 -http localhost:8080Configure your browser to use either SOCKS host localhost:1080 or HTTP proxy localhost:8080.
┌─────────────────────────────────────────────────────────┐
│ Your Local Machine │
│ │
│ ┌──────────────┐ SOCKS5/HTTP ┌────────────────┐ │
│ │ Your App │ ───────────────> │ ts-unplug- │ │
│ │ │ │ proxy │ │
│ └──────────────┘ └───────┬────────┘ │
│ │ │
└────────────────────────────────────────────┼────────────┘
│ Tailscale
│
┌────────────────────────────────────────────┼────────────┐
│ Tailnet │ │
│ ┌───────▼────────┐ │
│ │ Remote Service │ │
│ └────────────────┘ │
└─────────────────────────────────────────────────────────┘
ts-unplug-proxy:
- Connects a
tsnet.Serverto your tailnet - Listens locally for SOCKS5 and/or HTTP proxy connections
- Receives each requested destination from the proxy client
- Resolves MagicDNS peer names from Tailscale status, including short names like
sippy - Falls back to Tailscale DNS via
LocalClient.QueryDNSfor other DNS records - Falls back to normal
tsnet.Server.Dialfor non-tailnet public names such aswww.google.ca - Dials resolved IPs with
tsnet.Server.Dial - Relays traffic between the client and the destination
The proxy does not use the local OS resolver for tailnet hostnames received from SOCKS5 or HTTP proxy clients. Public names may use the normal resolver path inside tsnet.Server.Dial, which is necessary for general internet egress.
Use a loopback listen address such as localhost:1080 or 127.0.0.1:1080 unless you intentionally want other machines to use the proxy.
This command does not implement proxy authentication. Do not bind it to a shared interface unless the network path is already trusted and access-controlled.
The -dir contains sensitive Tailscale credentials. Protect it appropriately:
chmod 700 ./stateAt least one proxy listener is required:
ts-unplug-proxy -dir ./state -socks5 localhost:1080
ts-unplug-proxy -dir ./state -http localhost:8080Use SOCKS5 hostname mode:
curl --socks5-hostname localhost:1080 http://myserver.tailnet.ts.netFor proxy URLs, use socks5h:// rather than socks5:// when the client supports it:
ALL_PROXY=socks5h://127.0.0.1:1080 curl http://myserver.tailnet.ts.netlsof -i :1080
ts-unplug-proxy -dir ./state -socks5 localhost:1081- Verify the remote hostname and port are correct
- Check the remote service is running
- Ensure your Tailscale identity has access to the destination
- Try
tailscale ping myserver.tailnet.ts.net
- ts-unplug Guide - Fixed local port mapping to a tailnet service
- ts-plug Guide - Expose local services to your tailnet
- Main README - Quick start guide