MCPcopy Index your code
hub / github.com/almeidapaulopt/tsdproxy

github.com/almeidapaulopt/tsdproxy @v2.3.4

Chat with this repo
repository ↗ · DeepWiki ↗ · release v2.3.4 ↗ · + Follow
727 symbols 3,203 edges 92 files 215 documented · 30%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

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.<tailnet-name>.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.<tailnet>.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

Extension points exported contracts — how you extend this code

TargetProvider (Interface)
TargetProvider interface to be implemented by all target providers [2 implementers]
internal/targetproviders/targetproviders.go
Provider (Interface)
Proxy interface for each proxy provider [1 implementers]
internal/proxyproviders/proxyproviders.go
Middleware (FuncType)
Middleware type as before.
internal/core/http.go
ContainerOption (FuncType)
container struct stores the data from the docker container.
internal/targetproviders/docker/container.go
ProxyInterface (Interface)
ProxyInterface interface for each proxy [1 implementers]
internal/proxyproviders/proxyproviders.go
LoggerMiddlewareOption (FuncType)
LoggerMiddlewareOption configures LoggerMiddleware behavior.
internal/core/log.go

Core symbols most depended-on inside this repo

Close
called by 109
internal/proxyproviders/proxyproviders.go
Error
called by 102
internal/config/validator.go
String
called by 57
internal/model/port.go
NewTSNetClient
called by 53
e2e/helpers.go
WaitForProxyReachable
called by 50
e2e/helpers.go
StartContainer
called by 49
e2e/helpers.go
ProxyHTTPURL
called by 47
e2e/helpers.go
VerifyHTTPResponse
called by 41
e2e/helpers.go

Shape

Function 317
Method 307
Struct 85
TypeAlias 11
Interface 4
FuncType 3

Languages

Go98%
TypeScript2%

Modules by API surface

e2e/helpers.go44 symbols
internal/model/port_test.go36 symbols
internal/proxymanager/proxymanager.go34 symbols
internal/proxymanager/proxy.go29 symbols
internal/targetproviders/docker/container_test.go27 symbols
internal/model/port.go27 symbols
internal/targetproviders/docker/container.go26 symbols
internal/targetproviders/list/list.go24 symbols
internal/dashboard/dash.go22 symbols
internal/proxymanager/port.go21 symbols
internal/api/api.go21 symbols
internal/core/webhook/webhook.go19 symbols

For agents

$ claude mcp add tsdproxy \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page