Skip to content

Instantly share code, notes, and snippets.

@bnhf
Last active June 23, 2026 12:45
Show Gist options
  • Select an option

  • Save bnhf/fed4cc3035f32a0f086b1da074a3d50b to your computer and use it in GitHub Desktop.

Select an option

Save bnhf/fed4cc3035f32a0f086b1da074a3d50b to your computer and use it in GitHub Desktop.
Tailscale - Deploying with Docker and Portainer

Just thought I'd put together some detail on deploying Tailscale using Docker and Portainer. These bits-and-pieces are available elsewhere, but not together, so hopefully this will save someone a bit of time if you'd like to add Tailscale to an existing Docker install:

Here's my annotated recommended docker-compose, to use with Portainer-Stacks. Note that I'm not using a pre-made Auth Key. I started that way, but realized it was very easy to simply check the Portainer log for the tailscaled container once the stack is running. In that log you'll see the standard Auth link that you can use to authorize the container. This way you don't need to create a key in advance, or create a reusable key that introduces a security risk:

version: '3.9'
services:
  tailscale:
    image: tailscale/tailscale
    container_name: tailscaled
    cap_add:
      - NET_ADMIN
      - NET_RAW
    environment:
#      - TS_HOSTNAME=${TS_HOSTNAME} # Usually not necessary for your hostname to be the same name on the tailscale network
#      - TS_AUTHKEY=${TS_AUTHKEY} # Generate auth keys here: https://login.tailscale.com/admin/settings/keys
#      - TS_ROUTES=${TS_ROUTES} # Creates a subnet router for Tailscale. Use your subnet's CIDR in the form: 192.168.1.0/24
#      - TS_ACCEPT_DNS=${TS_ACCEPT_DNS} # Set to false for Pi-hole Docker setups
      - TS_SOCKET=${TS_SOCKET} # Specifying the /var/lib/tailscale/tailscaled.sock location allows use of standard Tailscale commands 
      - TS_EXTRA_ARGS=${TS_EXTRA_ARGS} # Add any other supported arguments in the docker commandline style: e.g. --advertise-exit-node
      - TS_STATE_DIR=${TS_STATE_DIR} # Required to create a persistent container state that will survive reboots
    volumes:
      - /data:/var/lib # Creates a tailscale directory under /data for persistence
      - /dev/net/tun:/dev/net/tun
    network_mode: host
    restart: unless-stopped

These are the minimum environment variables you'll want to define in the Portainer-Environment section:

TS_SOCKET=/var/run/tailscale/tailscaled.sock
TS_EXTRA_ARGS=--accept-routes
TS_STATE_DIR=/var/lib/tailscale

With these variables, you'll be able to exec into the container to run commands like "tailscale version" and "tailscale status". Your container will accept routes advertised by a designated node, and your setup (including authorization) will persist across reboots.

@boris1000

Copy link
Copy Markdown

OK, problem was that the host wasn't connected to the tailnet - don't really know why but do not fully understand the logic.
Now I am connected, but can it be that the host is disconnecting automatically or does it stay online - what it should.

Still struggling to access my local IPs - what do I enter now the routed IP ot the tailscale IP for the host ...

@flussaudio

Copy link
Copy Markdown

n00b alert! Trying to get this deployed on a UGREEN 4800 via Dockhand compose. I'm not an 'ix guy so forgive the question.

When we see something like - TS_AUTHKEY=${TS_AUTHKEY} should the key be within the brackets, or are they to be deleted in favor of the key characters only, i.e. 'TS AUTHKEY=xxxxxxxxxxxxxxxxx' ?

@bnhf

bnhf commented Jun 23, 2026

Copy link
Copy Markdown
Author

When we see something like - TS_AUTHKEY=${TS_AUTHKEY} should the key be within the brackets, or are they to be deleted in favor of the key characters only, i.e. 'TS AUTHKEY=xxxxxxxxxxxxxxxxx' ?

In the Portainer-Stacks Editor, there's a special section specifically for environment variables. The idea is to leave the Docker Compose as-is, and put any of your specific env vars in that section. Using this approach, you know at a glance what values are specific to you.

BTW, when it comes to TS_AUTHKEY, I'd suggest you not supply this value. Then, when you spin-up the container, check the Portainer-Log, and you'll see a URL you can copy-and-paste into your browser to do the authorization.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment