How to Build a Zero‑Config Mesh VPN with Tailscale: Linux, Windows, and Docker (MagicDNS, ACLs, Exit Nodes)
Overview
Tailscale is a modern mesh VPN built on WireGuard that makes secure connectivity across laptops, servers, and containers almost effortless. Instead of managing keys and gateways by hand, you sign in with your identity provider and every device gets a stable, encrypted connection. In this tutorial, you will set up Tailscale on Linux, Windows, and Docker, enable MagicDNS for human‑friendly names, create fine‑grained ACL rules, and configure subnet routers and exit nodes. By the end, you will have a production‑ready, zero‑config VPN that can replace brittle port forwards and site‑to‑site tunnels.
Prerequisites
You need a Tailscale account (Google, Microsoft, GitHub, or SSO), admin rights on the devices, and outbound internet access. Optional but recommended: the ability to change local firewall rules. Tailscale supports Windows 10/11, Windows Server, macOS, Linux (Debian/Ubuntu, RHEL, Fedora, Alpine), and containers (Docker, Kubernetes).
Step 1 — Create the network and enable MagicDNS
Sign up at the Tailscale Admin Console and create a tailnet (your private network). In Settings → DNS, enable MagicDNS to get easy hostnames like web01.tailnet-name.ts.net. Also enable device approval if you want an admin to approve new devices before they can join.
Step 2 — Install on Windows
Download and install the Tailscale client for Windows. Launch it, click Log in, and complete the browser prompt. After the device appears in the Admin Console, give it a readable name (for example, win-laptop). To allow others to route their traffic through this machine later, you can designate it as an exit node in Settings, then in the client select Use exit node when needed.
Step 3 — Install on Linux
On Debian/Ubuntu, install and bring the service up. Example:
curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/jammy.noarmor.gpg | sudo tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null; \
curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/jammy.tailscale-keyring.list | sudo tee /etc/apt/sources.list.d/tailscale.list; \
sudo apt-get update && sudo apt-get install -y tailscale; \
sudo systemctl enable --now tailscaled; \
sudo tailscale up
Follow the login URL, approve the device, and verify you can ping another device’s Tailscale IP or its MagicDNS name. On RHEL/Fedora, use dnf install tailscale with the corresponding repo instructions from Tailscale’s docs, then run systemctl enable --now tailscaled and tailscale up.
Step 4 — Join Docker containers
For containers, the simplest pattern is a Tailscale sidecar or running Tailscale inside the container with --net=host. Create an auth key in the Admin Console (Keys → Generate auth key). For ephemeral containers, mark it reusable and ephemeral. Then:
docker run --rm --net=host --cap-add NET_ADMIN --cap-add SYS_MODULE \
-e TS_AUTHKEY=tskey-XXXXX -e TS_HOSTNAME=app01 --name ts \
ghcr.io/tailscale/tailscale:stable
Alternatively, keep Tailscale in a sidecar and expose your app container over the Tailscale interface. Using ephemeral keys avoids long‑lived credentials inside images.
Step 5 — Use MagicDNS and stable names
With MagicDNS, you can connect to devices by name instead of IP, for example ssh ubuntu@web01. If a device is multihomed, Tailscale handles routing without your input. If you cannot resolve names, ensure MagicDNS is enabled and your OS DNS cache is clean (flush with ipconfig /flushdns on Windows or systemd-resolve --flush-caches on Linux).
Step 6 — Create Access Control Lists (ACLs)
ACLs define who can reach what. In the Admin Console, open Access controls and edit the JSON. Example to allow the Helpdesk group SSH to Linux servers and RDP to Windows only:
{ "groups": { "group:helpdesk": ["[email protected]","[email protected]"] }, "tagOwners": { "tag:linux": ["group:helpdesk"], "tag:windows": ["group:helpdesk"] }, "acls": [ { "action":"accept", "src":["group:helpdesk"], "dst":["tag:linux:22","tag:windows:3389"] } ] }
Tag devices by starting Tailscale with tags, for example sudo tailscale up --advertise-tags=tag:linux. Use the principle of least privilege and review the policy on every new service.
Step 7 — Advertise a subnet router
To reach an entire LAN behind a Linux box (like a lab or on‑prem server), advertise routes from that machine:
sudo tailscale up --advertise-routes=192.168.10.0/24
Approve the route in the Admin Console. If you prefer the LAN device IPs to be the source (no SNAT), add --snat-subnet-routes=false and ensure your LAN gateway routes replies back via the router.
Step 8 — Offer an exit node for internet egress
An exit node lets clients send all internet traffic through a trusted device; useful on public Wi‑Fi. On the chosen device run:
sudo tailscale up --advertise-exit-node
Enable it in the Admin Console, then on clients open the Tailscale client and select Use exit node. Confirm DNS and split‑tunnel settings match your security policy.
Step 9 — Firewall and auto‑start tips
Tailscale uses outbound UDP on random high ports (WireGuard) and falls back to TCP/443 via DERP relays when direct NAT traversal fails. Allow outbound UDP and HTTPS. On Linux, Tailscale manages its own interface (tailscale0), but you should avoid conflicting rules that drop established/related traffic. Ensure auto‑start with systemctl enable --now tailscaled (Linux) and verify the Windows service is running after reboots.
Troubleshooting
If a device shows offline, verify system time (NTP), restart the service with sudo systemctl restart tailscaled, and check that your identity provider token has not expired. If pings work but names do not, re‑enable MagicDNS and flush DNS caches. If a container cannot join, confirm it has --net=host or appropriate capabilities and that you used a valid auth key. For route issues, ensure routes are approved and that upstream routers have return routes when SNAT is disabled. As a last resort, try tailscale bugreport and review logs at /var/log or the Windows Event Viewer.
Security best practices
Use short‑lived, ephemeral auth keys in CI and containers. Turn on device approval and SSO/MFA. Rely on tags, not users, to grant access in ACLs. Keep systems patched and enable client auto‑updates. Prefer exit nodes you control and monitor. Regularly audit your ACL JSON and remove unused devices from the tailnet.
What you built
You now have a resilient, zero‑config mesh VPN that spans Windows, Linux, and Docker. With MagicDNS, ACLs, subnet routing, and exit nodes, you can securely reach any service without exposing ports to the internet, and you can grow the network in minutes instead of days.
Comments
Post a Comment