Skip to content
Go back

Tailscale Deep Dive: Mesh Networking That Actually Works

By SumGuy 8 min read
Tailscale Deep Dive: Mesh Networking That Actually Works

You’ve probably heard the pitch: “Tailscale is just WireGuard, but easy.” And yeah, that’s technically true. But that’s like saying a car is “just an engine, but with wheels.” The magic—and the real power—lives in what wraps around that WireGuard core.

Let me be honest: I spent two years managing WireGuard manually. Key distribution? Manual. IP allocation? Manual. Routing? Manual. It worked, sure. But at 2 AM when someone’s key got leaked and I had to rotate every single device, I swore there had to be a better way. Turns out, there was. I just didn’t want to pay for it.

Then Headscale happened. But we’ll get there.

WireGuard Alone Isn’t Enough

WireGuard is phenomenal—it’s fast, it’s lean, it’s auditable. But it’s also a VPN protocol, not a complete solution. You still have to:

This is why people end up with elaborate Ansible playbooks or custom scripts. It works, but it’s not something you want to debug at 11 PM on a Friday.

Tailscale takes all of that and hides it behind a CLI command. tailscale up, and you’re in the mesh. No key files to juggle. No static configs. Just works.

Getting Started: Five Minutes to a Working Mesh

Installation is stupidly simple:

Terminal window
# macOS
brew install tailscale
# Linux (Ubuntu/Debian)
curl -fsSL https://tailscale.com/install.sh | sh
# Windows
# Download from tailscale.com/download/windows
# Then just run:
tailscale up

Your browser opens, you authenticate with Google/Microsoft/GitHub (or your organization’s SSO if you’re on a team account), and boom—you’re on the tailnet. Your device gets a 100.x.x.x IP automatically. Other devices see it immediately.

Try pinging another device:

Terminal window
tailscale status # See all devices on your tailnet
ping 100.x.x.123 # Ping another node directly

It just works. No configuration files. No routing tables. No crying.

ACLs: The Policy Engine That Keeps Everyone Honest

The real power emerges when you need to control who talks to what. That’s ACLs.

By default, Tailscale allows all devices on your tailnet to reach all other devices. That’s fine if you trust everyone. But once you’re connecting home servers, work laptops, VPS instances, and IoT garbage into the same mesh, you want granular control.

Open the Tailscale admin console at https://login.tailscale.com/admin/acls/file and you’ll see the ACL policy file in JSON:

{
"acls": [
// Admins can access everything
{
"action": "accept",
"src": ["group:admins"],
"dst": ["*:*"]
},
// Work laptops can reach work servers, but not home lab
{
"action": "accept",
"src": ["tag:work"],
"dst": ["tag:work-servers:*"]
},
// Home lab devices (tagged with `tag:homelab`) can only reach each other
{
"action": "accept",
"src": ["tag:homelab"],
"dst": ["tag:homelab:*"]
},
// Home servers can reach the database, but nothing else
{
"action": "accept",
"src": ["tag:home-servers"],
"dst": ["tag:database:443,5432"]
},
// Everything else is denied
{
"action": "deny",
"src": ["*"],
"dst": ["*:*"]
}
],
"tagOwners": {
// Only the admin can assign tags; you could delegate to specific users too
"homelab": ["autogroup:admin"],
"work": ["autogroup:admin"],
"home-servers": ["autogroup:admin"],
"database": ["autogroup:admin"]
}
}

Tags are assigned to devices during the auth flow or by editing them in the admin console. Once tagged, they inherit ACL rules. Change the policy, and it’s live immediately—no SSH-ing into each device to update configs.

Subnet Routers: Bridge Your Home Lab Into the Mesh

Not every device on your home network needs Tailscale installed. You’ve got printers, NAS boxes, smart light switches—devices where installing Tailscale isn’t an option.

Enter: subnet routers.

Set up one Linux box on your home network as a subnet router, and it becomes the gateway. Every device on your home network suddenly accessible from the tailnet, without installing Tailscale on them.

On your router machine (or a spare VM):

Terminal window
# Enable IP forwarding
echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
# Advertise the home network (assume your LAN is 192.168.1.0/24)
sudo tailscale up --advertise-routes=192.168.1.0/24
# Enable route acceptance in the admin console (one-time)
# Login to https://login.tailscale.com/admin/machines
# Click your router device → "Approve subnets"

Now any device on the tailnet can reach 192.168.1.0/24. Ping the printer, RDP into the NAS, SSH into the Proxmox host—all through encrypted WireGuard tunnels, no VPN app installed on those devices.

Exit Nodes: Route Everything Through a VPS (Or Your Home)

Ever want to tunnel all your traffic through a remote server? Tailscale’s exit node does exactly that.

Set a VPS as an exit node:

Terminal window
# On your VPS
sudo tailscale up --advertise-exit-node

Then on any client:

Terminal window
# Use this VPS as the exit node for all traffic
tailscale set --exit-node-allow-lan-access=false
tailscale set --exit-node=<vps-ip>
# Check it's working
curl https://ifconfig.me # Should show your VPS's public IP
# Disable it when done
tailscale set --exit-node=

Why use this? Appear to be in another country (geo-locked services). Hide your home IP when accessing stuff from the road. Route all traffic through your own server instead of trusting a random VPN provider.

One warning: exit nodes can get expensive bandwidth-wise. Be realistic about how much you’ll actually use it before flipping the switch.

MagicDNS and Split DNS

Manually remembering 100.x.x.45 sucks. MagicDNS gives you DNS names automatically.

In the admin console, enable MagicDNS. Now your devices are accessible by name:

Terminal window
ping mydesktop.tail12345.ts.net
ssh user@homeserver.tail12345.ts.net
curl https://nextcloud.tail12345.ts.net

Split DNS lets you override DNS for specific domains:

{
"dnsConfig": {
"nameservers": ["1.1.1.1"],
"overrides": {
"internal.example.com": ["100.x.x.10"],
"*.lab": ["100.x.x.11"]
}
}
}

Now queries for *.internal.example.com go to your internal DNS server (on the tailnet), but everything else goes to Cloudflare. No more keeping a split-brain DNS setup.

Taildrive and Taildrop: File Sharing Built In

Need to send files across the tailnet? Taildrop is instant peer-to-peer file sharing:

Terminal window
tailscale file cp ~/document.pdf alice@ # Sends to Alice's device
tailscale file list # See incoming files

Files get pushed directly to the recipient’s device over the mesh—no central server needed.

Taildrive (newer) lets you mount directories from other devices as network shares:

Terminal window
# On the machine with files to share:
tailscale drive share Documents
# On another device:
tailscale drive list # See shared directories
# Access via file browser or mount in /mnt/tailscale/...

Perfect for backing up configs or accessing shared storage without NFS/SMB complexity.

Headscale: The Self-Hosted Escape Hatch

Here’s the uncomfortable truth: Tailscale works because you’re trusting Tailscale’s servers with your authentication and control plane. For most people, that’s fine. They’re a reputable company, they’ve never had a major breach, and closed-source control planes are actually pretty normal.

But what if you want full control? Or you don’t want to rely on another SaaS company? Enter Headscale—an open-source control plane that speaks the Tailscale protocol.

Headscale isn’t a Tailscale replacement; it’s a WireGuard controller that’s compatible with Tailscale clients. You run Headscale on your own hardware, point your devices at it, and you own the whole thing.

Basic Headscale setup (on a Linux box):

Terminal window
# Install Headscale
curl -L -o headscale.deb https://github.com/juanfont/headscale/releases/download/v0.24.0/headscale_0.24.0_linux_amd64.deb
sudo dpkg -i headscale.deb
# Configure it
sudo nano /etc/headscale/config.yaml
# Set server_url to your domain, listen_addr to localhost, etc.
# Start the service
sudo systemctl enable headscale
sudo systemctl start headscale
# Create a namespace (like a team)
headscale namespaces create personal
# Invite a device
headscale preauthkeys create -n personal

On your client:

Terminal window
tailscale up --login-server=https://headscale.yourdomain.com
# Approve the auth request on the Headscale server
headscale nodes list
headscale nodes register --user=personal --key=<auth-key>

Now you’ve got a complete, self-hosted mesh. No reliance on Tailscale’s infrastructure. No closed-source control plane. Just WireGuard doing what WireGuard does best.

The tradeoff? You’re responsible for backups, certificate renewal, and uptime. It’s absolutely worth learning, but know what you’re signing up for.

Tailscale vs Self-Managed WireGuard: The Honest Tradeoff

Go with Tailscale if:

Go with self-managed WireGuard or Headscale if:

Honestly? For my setup—a handful of personal devices plus a home lab—I use Tailscale. The control plane stays with Headscale, but I’ll probably migrate a home instance before long. The time saved not managing keys and IPs is worth way more than the cognitive load of running another service.

Pick what fits. The whole point of mesh networking is flexibility.


Share this post on:

Send a Webmention

Written about this post on your own site? Send a webmention and it'll show up above once verified.


Previous Post
Sysctl Tuning: The Linux Kernel Knobs That Actually Matter
Next Post
n8n + LLM: Building Automations That Actually Think

Discussion

Powered by Garrul . Sign in with GitHub or Google, or post anonymously.

Related Posts