opensourceprojects.dev

A broadsheet for software that doesn't ask for your email

Expose Docker containers as Tailscale Services with labels, no port publishing
GitHub RepoViews6

Project Description

View on GitHub

Exposing Docker Containers to Your Tailnet Without Publishing a Single Port

You've got a handful of containers running on a home server or a small VPS, and you'd like to reach them from your laptop without opening ports to the internet. Tailscale solves half that problem, but wiring each container into your tailnet usually means publishing ports, spinning up sidecars, or burning a device slot per app. DockTail takes a different route: it watches your Docker containers, reads a few labels, and exposes them as native Tailscale Services.

What It Does

DockTail is a container that runs alongside your apps. It watches the Docker daemon, reads docktail.* labels on your containers, and exposes any matching container as a Tailscale Service. The key detail is that it uses native Tailscale Services rather than registering each app as its own Tailscale device.

Because it's proxying to containers directly on their Docker network IPs, your app containers don't need published ports by default. You label a service, run docker compose up -d, and the app becomes reachable at a tailnet hostname. It supports HTTP, HTTPS, TCP, and TLS-terminated TCP, with optional PROXY protocol on TCP services so backends can see the real client IP. Tailscale HTTPS certificates and Funnel for public access are both on the menu, and a single container can expose multiple services.

The runtime itself is stateless, and it reconciles automatically when containers restart or their IPs change. There's also an opt-in cleanup feature for unused service definitions, built to be safe when you're running multiple DockTail instances.

Why It's Cool

It sidesteps the device-slot problem. The usual pattern for exposing containers over Tailscale involves giving each app its own Tailscale identity, which eats into your device count. DockTail uses Services instead, so your apps don't consume separate device slots. If you're running a dozen small services, that difference adds up fast.

No port publishing means less configuration to get wrong. A lot of proxy setups depend on how you've wired your Docker networks and published ports. DockTail goes straight to the container IP, so the Compose file stays clean. Your nginx service is just an image and a label.

Labels are the whole interface. Discovery is automatic through Docker labels, and service creation happens automatically when you supply OAuth or API key credentials. There's no separate config file to keep in sync with your Compose stack. If you already think in Compose, this fits the mental model you have.

The comparison table is refreshingly honest. The README lines up DockTail against TSDProxy, ScaleTail, tsbridge, and plain Tailscale Services, complete with footnotes explaining where the alternatives have caveats (like depending on proxy and network setup, or requiring per-app Compose recipes). It's the kind of table that helps you decide whether the tool is right for you rather than just telling you it's the best.

Small touches that suggest real use. Optional PROXY protocol support for TCP backends, multiple services per container, and reconciliation on IP changes are the features you only add after running something in production. The stateless design also means you're not worried about DockTail's own state getting corrupted.

It's also worth noting that Tailscale itself featured the project on its YouTube channel ("I'm Running Docker Apps Differently Now"), and it's listed among Tailscale's community projects. That's not proof it's right for you, but it's a reasonable signal that the approach is sound.

How to Try It

You'll need Docker, a Tailscale tailnet, and OAuth client credentials (recommended, though API keys work too). The quick start is a single Compose file:

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:
      - TAILSCALE_OAUTH_CLIENT_ID=${TAILSCALE_OAUTH_CLIENT_ID}
      - TAILSCALE_OAUTH_CLIENT_SECRET=${TAILSCALE_OAUTH_CLIENT_SECRET}

  myapp:
    image: nginx:latest
    labels:
      - "docktail.service.enabl..."

The README truncates mid-label, so check the repository for the full label reference before you copy anything verbatim. The pattern, though, is clear: run DockTail with access to the Docker socket and the Tailscale socket, add labels to your app, and bring the stack up. From there you open the service's tailnet hostname and you're in.

The image lives at ghcr.io/marvinvr/docktail, releases are on GitHub, and the project is AGPL-3.0 licensed. There's also an optional DockTail Cloud reporting feature you can enable with a single environment variable if you want multi-host monitoring, but it's entirely opt-in.

Final Thoughts

DockTail is aimed at people who already run Docker Compose stacks and want them on their tailnet without the usual port-publishing and sidecar overhead. If you're managing a handful of self-hosted services and you've been putting off the Tailscale wiring, this removes most of the friction. The reliance on labels and the stateless design keep it simple to reason about, and the honest comparison table tells you upfront whether a different tool fits better. Worth a look before your next Compose file grows another published port.


Follow @githubprojects for more developer tools and open source projects.

Back to Projects
Project ID: docktailLast updated: November 13, 2026 at 02:47 AM