docktail is a free, open source networking & connectivity project written in Go and released under AGPL-3.0. It has 1,282 GitHub stars, 48 forks and 5 open issues, and was last pushed 3 days ago. On this registry it ranks #57 of 71 tracked projects in Networking & Connectivity, with 5 head-to-head comparisons available.

What is docktail?

DockTail is an AGPL-3.0, Go-based tool that watches Docker containers, reads their docktail.* labels, and exposes matching containers as native Tailscale Services, for self-hosters and infrastructure teams that want tailnet-reachable services without a Tailscale device per application.

What it is

DockTail is a Go application in the Infrastructure & Operations / Networking & Connectivity category, licensed under AGPL-3.0 and documented at docktail.org. It runs as a stateless Docker container, watches the Docker daemon, reads docktail.* labels from containers, and creates matching Tailscale Services using OAuth credentials or an API key. Because it proxies directly to container Docker network IPs, application containers do not need published Docker ports by default. It supports HTTP, HTTPS, TCP and TLS-terminated TCP, Tailscale HTTPS with automatic certificates, and Tailscale Funnel for public internet access.

The problem it solves is the gap between Docker and Tailscale's service model. Exposing a container on a tailnet conventionally means either configuring Tailscale Services by hand on the host or attaching a Tailscale device to each application, which consumes device slots and adds per-app setup. DockTail replaces that manual work with label-based configuration and automatic Docker reconciliation, so exposed services follow containers when they restart or their IPs change. Cleanup of unused Tailscale service definitions is available as an opt-in step, which the project notes is safe to run with multiple DockTail instances.

Key capabilities

  • Automatic discovery of Docker containers through docktail.* labels, including docktail.service.enable, docktail.service.name and docktail.service.port.
  • Automatic Tailscale service creation from OAuth credentials (TAILSCALE_OAUTH_CLIENT_ID and TAILSCALE_OAUTH_CLIENT_SECRET) or an API key, with mounted-secret alternatives through FILE__ prefixed variables.
  • HTTP, HTTPS, TCP and TLS-terminated TCP services, including optional PROXY protocol (docktail.service.proxy-protocol=2) so TCP backends see the tailnet client IP.
  • Tailscale HTTPS with automatic certificates, plus Tailscale Funnel (docktail.funnel.enable) for public internet access.
  • Multiple Tailscale services from one container, automatic reconciliation when containers restart or IPs change, and optional opt-in cleanup of unused service definitions that is safe with multiple instances.
  • A stateless container runtime with optional DockTail Cloud reporting for multi-host monitoring, enabled by one environment variable.

Who uses it and how

  • Homelab operators on Docker hosts already joined to a tailnet, who expose an application such as nginx with a few labels and no published ports, then reach it at myapp.your-tailnet.ts.net.
  • Environments hosting many applications that want to avoid each one consuming a separate Tailscale device slot.
  • Reverse proxy operators, for example running Traefik on TCP port 443, who need the tailnet client IP preserved through PROXY protocol.
  • Teams exposing non-HTTP services such as PostgreSQL on port 5432 over TCP, and deployments on Podman, Synology, Unraid, TrueNAS, macOS, Windows, Docker Swarm or Kubernetes, including hardened setups using a read-only Docker socket proxy and dropped capabilities.

Getting started

The documented path is Docker Compose using the image ghcr.io/marvinvr/docktail:latest, with /var/run/docker.sock mounted read-only and /var/run/tailscale mounted, plus optional OAuth environment variables for automatic service creation. A ready-to-run docker-compose.yaml is provided, and the documented assumption is that the Docker host is connected to Tailscale and allowed to advertise services.

How it compares

DockTail sits alongside other Docker-to-tailnet tools such as TSDProxy, ScaleTail and tsbridge, and against configuring plain Tailscale Services by hand. DockTail and plain Services are the two that use native Tailscale Services and therefore avoid consuming a separate Tailscale device slot per application; DockTail, TSDProxy and tsbridge are configured through Docker labels, while ScaleTail is template-based and generally starts each application from its own Compose recipe.

When to use it — and when not to

A self-hoster must operate a Docker host connected to Tailscale and permitted to advertise services, give DockTail access to the Docker socket (optionally through a read-only socket proxy with dropped capabilities), and supply OAuth credentials or an API key. It is not a fit for anyone who does not run Tailscale, cannot grant Docker socket access in any form, or cannot adopt an AGPL-3.0 licence. The README excerpt also defers host setup, sidecar setup, rootless Docker, OAuth permissions, ACLs, labels and Funnel to separate documentation, so this is a documented install rather than a zero-configuration one.

project readme (upstream, from github) — read inline

🍸 DockTail

Unleash your containers as Tailscale Services.

DockTail watches Docker containers, reads docktail.* labels, and exposes matching containers as Tailscale Services. App containers do not need published Docker ports by default; DockTail proxies directly to their Docker network IPs.

Why DockTail?

DockTail uses native Tailscale Services, not per-container Tailscale devices.

DockTail TSDProxy ScaleTail tsbridge Plain Services
Native Tailscale Services ✅ ❌ ❌ ❌ ✅
Configured via Docker labels ✅ ✅ ❌ ✅ ❌
Apps do not consume separate Tailscale device slots ✅ ❌ ❌ ❌ ✅
No app port publishing ✅ ⚠️¹ ⚠️² ⚠️¹ ⚠️³
Automatic Docker reconciliation ✅ ✅ ❌ ✅ ❌
Low manual setup after install ✅ ✅ ⚠️⁴ ✅ ❌
  • ¹ Depends on proxy and Docker network setup.
  • ² Depends on the sidecar template and app network setup.
  • ³ You configure how the service host reaches the backend yourself.
  • ⁴ ScaleTail is template-based, so each app usually starts from its own Compose recipe.

Features

  • Automatic Docker container discovery through labels.
  • Automatic Tailscale service creation with OAuth or API key credentials.
  • HTTP, HTTPS, TCP, and TLS-terminated TCP support.
  • Optional PROXY protocol on TCP services so backends see the tailnet client IP.
  • Tailscale HTTPS with automatic certificates.
  • Tailscale Funnel for public internet access.
  • Multiple Tailscale services from one container.
  • Automatic reconciliation when containers restart or IPs change.
  • Optional cleanup of unused Tailscale service definitions (opt-in, safe with multiple instances).
  • Stateless Docker container runtime.
  • Optional DockTail Cloud reporting — multi-host monitoring, opt-in via one env var.

Quick Start

services:
  docktail:
    image: ghcr.io/marvinvr/docktail:latest
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /var/run/tailscale:/var/run/tailscale
    environment:
      # Optional but recommended. Enables automatic service creation.
      - TAILSCALE_OAUTH_CLIENT_ID=${TAILSCALE_OAUTH_CLIENT_ID}
      - TAILSCALE_OAUTH_CLIENT_SECRET=${TAILSCALE_OAUTH_CLIENT_SECRET}

  myapp:
    image: nginx:latest
    # No ports needed. DockTail proxies directly to the container IP.
    labels:
      - "docktail.service.enable=true"
      - "docktail.service.name=myapp"
      - "docktail.service.port=80"
docker compose up -d
curl http://myapp.your-tailnet.ts.net

This assumes the Docker host is connected to Tailscale and allowed to advertise services. See the full docs for host setup, sidecar setup, rootless Docker, OAuth permissions, ACLs, labels, Funnel, and examples. docker-compose.yaml is a ready-to-run version of this setup; for Podman, Synology, Unraid, TrueNAS, macOS, Windows, Swarm and Kubernetes see the platform guides, and for a read-only Docker socket proxy and dropped capabilities see Hardening.

For Docker secrets or other mounted secret files, set FILE__TAILSCALE_OAUTH_CLIENT_ID / FILE__TAILSCALE_OAUTH_CLIENT_SECRET or TAILSCALE_OAUTH_CLIENT_ID_FILE / TAILSCALE_OAUTH_CLIENT_SECRET_FILE to the mounted file paths instead of putting the values directly in the environment.

Common Examples

Expose an app with Tailscale HTTPS:

labels:
  - "docktail.service.enable=true"
  - "docktail.service.name=api"
  - "docktail.service.port=3000"
  - "docktail.service.service-port=443"

Expose a database over TCP:

labels:
  - "docktail.service.enable=true"
  - "docktail.service.name=db"
  - "docktail.service.port=5432"
  - "docktail.service.protocol=tcp"
  - "docktail.service.service-port=5432"

Preserve the tailnet client IP on a TCP reverse proxy:

labels:
  - "docktail.service.enable=true"
  - "docktail.service.name=traefik"
  - "docktail.service.port=443"
  - "docktail.service.protocol=tcp"
  - "docktail.service.service-port=443"
  - "docktail.service.proxy-protocol=2"

Expose a service publicly with Tailscale Funnel:

labels:
  - "docktail.funnel.enable=true"
  - "docktail.funnel.port=3000"
  - "docktail.funnel.funnel-port=8443"

Mount an HTTP(S) Funnel at a path:

labels:
  - "docktail.funnel.enable=true"
  - "docktail.funnel.port=3000"
  - "docktail.funnel.path=/webhook"

DockTail Cloud (optional)

Once you run DockTail on more than one machine, "is it still up?" gets tedious. DockTail Cloud is a hosted dashboard for that — and because it already has the Docker and Tailscale context, it tells you which kind of broken you're looking at:

● down · OOM-killed                   →  the container was killed for running out of memory
● local up · awaiting approval        →  the app is fine, the exposure isn't
● host offline · heartbeat missing    →  the box stopped reporting

It rides along with the agent you already run — no second binary. Set one environment variable and the same container starts reporting:

environment:
  - DOCKTAIL_CLOUD_KEY=${DOCKTAIL_CLOUD_KEY}   # from cloud.docktail.org

Without the key the module is completely inert: no connection is opened and DockTail behaves exactly as before. The link is outbound-only and metadata-only — the protocol has no exec, deploy, or shell message types, which you can verify in cloud/.

DockTail Cloud is a paid service (plans and pricing); a new workspace can connect one host as an unmonitored preview before you choose a plan. docker-compose.cloud.yaml is a complete example.

Explore DockTail Cloud · open the dashboard · agent setup

Documentation

The canonical documentation source lives in docs/. The site at docktail.org is built from a separate repository, which pins this one as a submodule and renders those Markdown files with tools/docsgen at build time.

Build From Source

go build -o docktail .
docker build -t docktail:latest .

The image is published for linux/amd64, linux/arm64 and linux/arm/v7, and releases newer than 1.8.3 carry static Linux binaries for the same platforms; see Platforms And Release Binaries.

Links

Star History

Star History Chart

License

AGPL v3


By @marvinvr

Frequently asked questions

Is docktail free to use?

docktail is open source under the AGPL-3.0 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 docktail do?

Expose Docker containers as Tailscale Services using label-based configuration.

What is docktail written in?

docktail is primarily written in Go. Its source is publicly available at https://github.com/marvinvr/docktail, and it has 1,282 GitHub stars.