{"id":23630657,"url":"https://github.com/almeidapaulopt/tsdproxy","last_synced_at":"2026-06-03T00:01:18.319Z","repository":{"id":258722552,"uuid":"868828087","full_name":"almeidapaulopt/tsdproxy","owner":"almeidapaulopt","description":"Automatic Tailscale reverse proxy for Docker containers. Zero sidecars. Label-based config. Automatic HTTPS.","archived":false,"fork":false,"pushed_at":"2026-06-01T17:16:19.000Z","size":1747,"stargazers_count":1599,"open_issues_count":14,"forks_count":75,"subscribers_count":7,"default_branch":"main","last_synced_at":"2026-06-01T18:21:10.820Z","etag":null,"topics":["automatic","containers","docker","docker-compose","go","homelab","https","networking","proxy","reverse-proxy","self-hosted","sidecar","ssl","tailscale","traefik-alternative","tsnet","vpn","wireguard"],"latest_commit_sha":null,"homepage":"https://almeidapaulopt.github.io/tsdproxy/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/almeidapaulopt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null},"funding":{"github":"almeidapaulopt","patreon":"almeidapaulopt","open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":"almeidapaulopt","thanks_dev":null,"custom":null}},"created_at":"2024-10-07T08:57:00.000Z","updated_at":"2026-06-01T17:17:04.000Z","dependencies_parsed_at":"2024-11-01T15:17:38.404Z","dependency_job_id":"9ff5ad46-905d-44a1-a9b9-76b1e1a9d845","html_url":"https://github.com/almeidapaulopt/tsdproxy","commit_stats":null,"previous_names":["almeidapaulopt/tsdproxy"],"tags_count":49,"template":false,"template_full_name":null,"purl":"pkg:github/almeidapaulopt/tsdproxy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/almeidapaulopt%2Ftsdproxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/almeidapaulopt%2Ftsdproxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/almeidapaulopt%2Ftsdproxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/almeidapaulopt%2Ftsdproxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/almeidapaulopt","download_url":"https://codeload.github.com/almeidapaulopt/tsdproxy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/almeidapaulopt%2Ftsdproxy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33841996,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-02T02:00:07.132Z","response_time":109,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automatic","containers","docker","docker-compose","go","homelab","https","networking","proxy","reverse-proxy","self-hosted","sidecar","ssl","tailscale","traefik-alternative","tsnet","vpn","wireguard"],"created_at":"2024-12-28T02:03:12.907Z","updated_at":"2026-06-03T00:01:18.310Z","avatar_url":"https://github.com/almeidapaulopt.png","language":"Go","funding_links":["https://github.com/sponsors/almeidapaulopt","https://patreon.com/almeidapaulopt","https://buymeacoffee.com/almeidapaulopt"],"categories":["Go","docker"],"sub_categories":[],"readme":"# TSDProxy - Tailscale Docker Proxy\n\n**The easiest way to expose Docker containers on your Tailscale network. One label. Zero sidecars.**\n\n[![GitHub Stars](https://img.shields.io/github/stars/almeidapaulopt/tsdproxy?style=flat\u0026label=stars)](https://github.com/almeidapaulopt/tsdproxy/stargazers)\n[![GitHub Issues](https://img.shields.io/github/issues/almeidapaulopt/tsdproxy?style=flat)](https://github.com/almeidapaulopt/tsdproxy/issues)\n[![Docker Pulls](https://img.shields.io/docker/pulls/almeidapaulopt/tsdproxy?style=flat)](https://hub.docker.com/r/almeidapaulopt/tsdproxy)\n[![License](https://img.shields.io/github/license/almeidapaulopt/tsdproxy?style=flat)](LICENSE)\n[![Go Version](https://img.shields.io/github/go-mod/go-version/almeidapaulopt/tsdproxy?style=flat\u0026label=Go)](https://go.dev/)\n[![Release](https://img.shields.io/github/v/release/almeidapaulopt/tsdproxy?style=flat\u0026label=latest)](https://github.com/almeidapaulopt/tsdproxy/releases)\n\n\u003cdiv align=\"center\"\u003e\n  \u003c!-- Replace with demo GIF: docker compose up → containers appear in Tailscale admin → HTTPS URL loads --\u003e\n  \u003cimg src=\"https://github.com/almeidapaulopt/tsdproxy/raw/main/docs/assets/demo.gif\" alt=\"TSDProxy Demo\" width=\"800\" onerror=\"this.style.display='none'\"/\u003e\n\u003c/div\u003e\n\n## Quick Start\n\nGet running in under a minute. One compose file, one label.\n\n**Step 1: Create `docker-compose.yml`**\n\n```yaml\nservices:\n  tsdproxy:\n    image: almeidapaulopt/tsdproxy:2\n    volumes:\n      - /var/run/docker.sock:/var/run/docker.sock\n      - tsdproxy-data:/data\n      - ./config:/config\n    ports:\n      - \"8080:8080\"\n    extra_hosts:\n      - \"host.docker.internal:host-gateway\"\n    restart: unless-stopped\n\n  myapp:\n    image: nginx:alpine\n    labels:\n      tsdproxy.enable: \"true\"\n      tsdproxy.name: \"myapp\"\n\nvolumes:\n  tsdproxy-data:\n```\n\n**Step 2: Start it up**\n\n```bash\ndocker compose up -d\n```\n\nTSDProxy 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.\n\nYour container is now available at `https://myapp.\u003ctailnet-name\u003e.ts.net` with automatic HTTPS.\n\nFor automated (headless) setup, configure an [AuthKey or OAuth](https://almeidapaulopt.github.io/tsdproxy/docs/advanced/tailscale/) before adding services.\n\n## Key Features\n\n| Feature | Description |\n|---------|-------------|\n| Zero sidecars | No Tailscale container needed per service. One proxy handles everything. |\n| Label-based config | Add `tsdproxy.enable=true` to any container. Done. |\n| Automatic HTTPS | Tailscale provisions Let's Encrypt certs for every machine. |\n| Multi-port support | Expose multiple ports per container with granular protocol control. |\n| TCP \u0026 UDP proxying | Proxy TCP (SSH, databases) and UDP traffic alongside HTTP/HTTPS services. |\n| Port ranges | Define ranges of ports in a single label — e.g. `2222-2230/tcp`. |\n| Funnel support | Expose services to the public internet with `tailscale_funnel` option. |\n| Health monitoring | Automatic backend health probes with recovery and target re-resolution. |\n| Webhook notifications | Push proxy events to ntfy, Discord, Slack, Gotify, or generic webhooks. |\n| REST API | Programmatic control over proxies — pause, resume, and manage via API. |\n| Role-based access | Admin and viewer roles with optional admin allowlist. |\n| Dynamic lifecycle | Containers start and stop. Tailscale machines appear and disappear. |\n| Live config reload | Change settings without restarting TSDProxy. |\n| Dashboard | Real-time web UI with SSE streaming, access logs, and status timeline. |\n| List provider | Expose non-Docker services via a simple YAML file. |\n\n## How It Works\n\n```mermaid\ngraph LR\n    A[Docker Containers] --\u003e|tsdproxy.enable label| B[TSDProxy]\n    B --\u003e|creates tsnet.Server| C[Tailscale Network]\n    C --\u003e|automatic HTTPS| D[Secure URLs]\n    D --\u003e|reverse proxy| A\n```\n\nUnder the hood:\n\n1. **Container Scanning** - TSDProxy watches your Docker daemon for containers tagged with `tsdproxy.enable=true`.\n2. **Machine Creation** - When a tagged container appears, TSDProxy spins up a Tailscale machine via `tsnet`.\n3. **Hostname Assignment** - The machine gets a hostname from the `tsdproxy.name` label or the container name.\n4. **Port Mapping** - TSDProxy maps the container's internal port to the Tailscale machine.\n5. **Traffic Routing** - Incoming requests to `https://myapp.\u003ctailnet\u003e.ts.net` are reverse-proxied to the container.\n6. **Dynamic Cleanup** - When a container stops, its Tailscale machine and routes are removed automatically.\n\n## Port Configuration\n\nExpose multiple ports with per-port protocol and options:\n\n```yaml\nlabels:\n  tsdproxy.enable: \"true\"\n  tsdproxy.name: \"myservice\"\n\n  # HTTPS on 443 -\u003e container port 80\n  tsdproxy.port.1: \"443/https:80/http\"\n\n  # HTTP on 80 -\u003e container port 8080\n  tsdproxy.port.2: \"80/http:8080/http\"\n\n  # HTTP redirect to HTTPS\n  tsdproxy.port.3: \"81/http-\u003ehttps://myservice.tailnet.ts.net\"\n\n  # TCP proxy for SSH\n  tsdproxy.port.4: \"22/tcp:22/tcp\"\n\n  # UDP proxy (e.g. game server, VoIP)\n  tsdproxy.port.5: \"5060/udp:5060/udp\"\n\n  # Port range (TCP ports 2222 through 2230)\n  tsdproxy.port.6: \"2222-2230/tcp:2222-2230/tcp\"\n```\n\n## Docker Images\n\n| Tag | Description |\n|-----|-------------|\n| `almeidapaulopt/tsdproxy:2` | Latest v2 release |\n| `almeidapaulopt/tsdproxy:latest` | Latest stable release |\n| `almeidapaulopt/tsdproxy:dev` | Latest development build |\n| `almeidapaulopt/tsdproxy:vx.x.x` | Specific version |\n\n## Documentation\n\nFull setup guides, configuration reference, and advanced usage:\n\n**[almeidapaulopt.github.io/tsdproxy](https://almeidapaulopt.github.io/tsdproxy/)**\n\nKey docs: [Getting Started](https://almeidapaulopt.github.io/tsdproxy/docs/getting-started/) | [Docker Labels](https://almeidapaulopt.github.io/tsdproxy/docs/providers/docker/) | [Port Configuration](https://almeidapaulopt.github.io/tsdproxy/docs/providers/docker/#port-configuration) | [List Provider](https://almeidapaulopt.github.io/tsdproxy/docs/providers/lists/) | [TCP Proxy](https://almeidapaulopt.github.io/tsdproxy/docs/advanced/tcp-proxy/) | [Funnel](https://almeidapaulopt.github.io/tsdproxy/docs/security/funnel/) | [REST API](https://almeidapaulopt.github.io/tsdproxy/docs/operations/api/) | [Health Checks](https://almeidapaulopt.github.io/tsdproxy/docs/operations/health-check/) | [Webhooks](https://almeidapaulopt.github.io/tsdproxy/docs/notifications/) | [Admin Allowlist](https://almeidapaulopt.github.io/tsdproxy/docs/security/admin-allowlist/) | [Upgrading from v1](https://almeidapaulopt.github.io/tsdproxy/docs/upgrading/from-v1/)\n\n## Contributing\n\nBug reports, feature requests, documentation improvements, and pull requests are all welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n\nIf you'd rather support the project financially, [sponsorships](https://github.com/sponsors/almeidapaulopt) help keep development going.\n\n## License\n\nThis project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.\n\n---\n\n[![Star History Chart](https://api.star-history.com/svg?repos=almeidapaulopt/tsdproxy\u0026type=Date)](https://star-history.com/#almeidapaulopt/tsdproxy\u0026Date)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falmeidapaulopt%2Ftsdproxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falmeidapaulopt%2Ftsdproxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falmeidapaulopt%2Ftsdproxy/lists"}