tsdproxy is a free, open source networking & connectivity project written in Go and released under MIT. It has 1,710 GitHub stars, 80 forks and 29 open issues, and was last pushed 36 hours ago. On this registry it ranks #44 of 57 tracked projects in Networking & Connectivity, with 5 head-to-head comparisons available.

What is tsdproxy?

TSDProxy is an automatic Tailscale reverse proxy for Docker containers that lets self-hosters expose services to a tailnet with one label and no per-service sidecars.

What it is

TSDProxy is a self-hosted reverse proxy written in Go that lives in the Docker ecosystem and sits between your containers and a Tailscale network. It watches the Docker daemon for containers carrying the tsdproxy.enable label, then spins up a Tailscale machine for each one using the Tailscale tsnet package, assigns a hostname from the tsdproxy.name label or the container name, and reverse-proxies incoming requests to that container. The result is a service reachable at a URL such as https://myapp..ts.net, with HTTPS handled automatically.

The concrete problem it removes is the routine of adding a Tailscale sidecar container to every service you want to publish, plus the manual certificate and routing work that normally goes with exposing something privately. Without it, each app in a compose stack needs its own Tailscale container, its own auth, and its own port plumbing. TSDProxy replaces that pattern with a single proxy that manages all tagged containers, cleans up the Tailscale machine and routes when a container stops, and works across container starts and stops without manual intervention.

Key capabilities

  • Label-based configuration: adding tsdproxy.enable: "true" to a container is enough to publish it, with tsdproxy.name choosing the hostname.
  • Automatic HTTPS, with Tailscale provisioning Let's Encrypt certificates for every machine.
  • TCP and UDP proxying alongside HTTP/HTTPS, covering SSH, databases, and other non-HTTP services.
  • Multi-port exposure with granular protocol control and port ranges in a single label, for example 2222-2230/tcp.
  • Funnel support through the tailscale_funnel option to expose a service to the public internet.
  • Health monitoring with automatic backend probes, recovery, and target re-resolution.
  • Webhook notifications pushed to ntfy, Discord, Slack, Gotify, or a generic webhook.
  • A REST API for programmatic control, plus a web dashboard with SSE streaming, access logs, and a status timeline.

Who uses it and how

  • Homelab operators who run multiple containers in docker-compose stacks and want each one reachable on their tailnet without editing proxy rules by hand.
  • Self-hosters who need non-HTTP services published too, such as SSH or database endpoints, using TCP/UDP proxying and port ranges.
  • Teams wanting public exposure selectively, using the tailscale_funnel option for individual services while keeping everything else private.
  • Headless or automated environments where setup runs without a browser, configured with an AuthKey or OAuth before services are added.
  • Administrators who expose non-Docker services through the list provider's simple YAML file, and manage access with admin and viewer roles plus an optional admin allowlist.

Getting started

Run it with Docker Compose using the almeidapaulopt/tsdproxy:2 image, mounting /var/run/docker.sock, a tsdproxy-data volume, and a ./config directory, then start the stack with docker compose up -d.

How it compares

TSDProxy stands alone in this registry; no comparable tools are named in the available facts.

When to use it — and when not to

Because it watches the Docker daemon directly, you must mount the Docker socket and operate TSDProxy itself as a persistent service alongside your containers, and it is a poor fit if your services are not running under Docker in the first place. It is also built around Tailscale, so it assumes you run a tailnet and want identities issued through Tailscale's machines rather than your own certificate authority. Note that the README excerpt is dense with feature tables but cuts off mid-documentation, and while the licence, language, and recent activity are stated, anyone adopting it should verify current release notes and the open issue list before depending on it in production.

project readme (upstream, from github) — read inline

TSDProxy - Tailscale Docker Proxy

The easiest way to expose Docker containers on your Tailscale network. One label. Zero sidecars.

GitHub Stars GitHub Issues Docker Pulls License Go Version Release

TSDProxy Demo

Quick Start

Get running in under a minute. One compose file, one label.

Step 1: Create docker-compose.yml

services:
  tsdproxy:
    image: almeidapaulopt/tsdproxy:2
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - tsdproxy-data:/data
      - ./config:/config
    ports:
      - "8080:8080"
    extra_hosts:
      - "host.docker.internal:host-gateway"
    restart: unless-stopped

  myapp:
    image: nginx:alpine
    labels:
      tsdproxy.enable: "true"
      tsdproxy.name: "myapp"

volumes:
  tsdproxy-data:

Step 2: Start it up

docker compose up -d

TSDProxy creates a default config at /config/tsdproxy.yaml on first run. Open the dashboard at http://localhost:8080, click the proxy card, and authenticate with Tailscale.

Your container is now available at https://myapp..ts.net with automatic HTTPS.

For automated (headless) setup, configure an AuthKey or OAuth before adding services.

Key Features

Feature Description
Zero sidecars No Tailscale container needed per service. One proxy handles everything.
Label-based config Add tsdproxy.enable=true to any container. Done.
Automatic HTTPS Tailscale provisions Let's Encrypt certs for every machine.
Multi-port support Expose multiple ports per container with granular protocol control.
TCP & UDP proxying Proxy TCP (SSH, databases) and UDP traffic alongside HTTP/HTTPS services.
Port ranges Define ranges of ports in a single label — e.g. 2222-2230/tcp.
Funnel support Expose services to the public internet with tailscale_funnel option.
Health monitoring Automatic backend health probes with recovery and target re-resolution.
Webhook notifications Push proxy events to ntfy, Discord, Slack, Gotify, or generic webhooks.
REST API Programmatic control over proxies — pause, resume, and manage via API.
Role-based access Admin and viewer roles with optional admin allowlist.
Dynamic lifecycle Containers start and stop. Tailscale machines appear and disappear.
Live config reload Change settings without restarting TSDProxy.
Dashboard Real-time web UI with SSE streaming, access logs, and status timeline.
List provider Expose non-Docker services via a simple YAML file.

How It Works

graph LR
    A[Docker Containers] -->|tsdproxy.enable label| B[TSDProxy]
    B -->|creates tsnet.Server| C[Tailscale Network]
    C -->|automatic HTTPS| D[Secure URLs]
    D -->|reverse proxy| A

Under the hood:

  1. Container Scanning - TSDProxy watches your Docker daemon for containers tagged with tsdproxy.enable=true.
  2. Machine Creation - When a tagged container appears, TSDProxy spins up a Tailscale machine via tsnet.
  3. Hostname Assignment - The machine gets a hostname from the tsdproxy.name label or the container name.
  4. Port Mapping - TSDProxy maps the container's internal port to the Tailscale machine.
  5. Traffic Routing - Incoming requests to https://myapp..ts.net are reverse-proxied to the container.
  6. Dynamic Cleanup - When a container stops, its Tailscale machine and routes are removed automatically.

Port Configuration

Expose multiple ports with per-port protocol and options:

labels:
  tsdproxy.enable: "true"
  tsdproxy.name: "myservice"

  # HTTPS on 443 -> container port 80
  tsdproxy.port.1: "443/https:80/http"

  # HTTP on 80 -> container port 8080
  tsdproxy.port.2: "80/http:8080/http"

  # HTTP redirect to HTTPS
  tsdproxy.port.3: "81/http->https://myservice.tailnet.ts.net"

  # TCP proxy for SSH
  tsdproxy.port.4: "22/tcp:22/tcp"

  # UDP proxy (e.g. game server, VoIP)
  tsdproxy.port.5: "5060/udp:5060/udp"

  # Port range (TCP ports 2222 through 2230)
  tsdproxy.port.6: "2222-2230/tcp:2222-2230/tcp"

Docker Images

Tag Description
almeidapaulopt/tsdproxy:2 Latest v2 release
almeidapaulopt/tsdproxy:latest Latest stable release
almeidapaulopt/tsdproxy:dev Latest development build
almeidapaulopt/tsdproxy:vx.x.x Specific version

Documentation

Full setup guides, configuration reference, and advanced usage:

almeidapaulopt.github.io/tsdproxy

Key docs: Getting Started | Docker Labels | Port Configuration | List Provider | TCP Proxy | Funnel | REST API | Health Checks | Webhooks | Admin Allowlist | Upgrading from v1

Contributing

Bug reports, feature requests, documentation improvements, and pull requests are all welcome. See CONTRIBUTING.md for guidelines.

If you'd rather support the project financially, sponsorships help keep development going.

License

This project is licensed under the MIT License. See the LICENSE file for details.


Star History Chart

Frequently asked questions

Is tsdproxy free to use?

tsdproxy is open source under the MIT licence. There is no licence fee and no seat count — you can self-host it or, where the project offers one, pay a vendor for a managed version instead.

What does tsdproxy do?

Automatic Tailscale reverse proxy for Docker containers. Zero sidecars. Label-based config. Automatic HTTPS.

What is tsdproxy written in?

tsdproxy is primarily written in Go. Its source is publicly available at https://github.com/almeidapaulopt/tsdproxy, and it has 1,710 GitHub stars.