If you've ever fought with port forwarding, dynamic DNS, and a router UI that looks like it was designed in 2009, you already know why WireGuard alone isn't th…
If you've ever fought with port forwarding, dynamic DNS, and a router UI that looks like it was designed in 2009, you already know why WireGuard alone isn't the whole story. WireGuard gives you the tunnel, but you still have to handle key distribution, NAT traversal, and IP allocation yourself. Tailscale wraps WireGuard in a mesh network that does all of that for you — devices find each other, negotiate direct connections through NAT, and fall back to relays when they can't. You get a private network across your laptop, phone, home server, and a cheap VPS, with almost none of the usual friction.
This is the setup I actually run: a home lab behind CG-NAT (thanks, ISP) reachable from anywhere, no forwarded ports, no static IP.
What you'll need
- A Linux box to act as your home lab server (Ubuntu 22.04+/Debian 12 used here, but Tailscale runs on basically everything)
- Root or sudo access on that box
- A free Tailscale account (GitHub, Google, or Microsoft login — no credit card)
- One more device to test from (your laptop or phone works fine)
- Optional: a spare cheap VPS if you want an always-on exit node or subnet router with a public IP
Step 1: Install Tailscale on your server
Tailscale's install script handles the repo setup and package install for you:
curl -fsSL https://tailscale.com/install.sh | sh
Then bring the interface up and authenticate:
sudo tailscale up
This prints a URL. Open it in a browser, log in, and approve the device. Your server now has a 100.x.y.z address on the Tailscale network (called a "tailnet") and a name like homeserver.your-tailnet.ts.net.
Check it worked:
tailscale status
You should see your machine listed with its Tailscale IP.
Step 2: Install it on your other devices
Same install script on any other Linux box, the official app on iOS/Android, or the installer on Windows/macOS. Log into the same account, approve each device, and they all land on the same private network automatically. No manual peer config, no exchanging public keys — that's the whole point.
Once two devices are both up, you can SSH straight to the Tailscale IP or MagicDNS name from anywhere with internet:
ssh you@homeserver.your-tailnet.ts.net
No open ports on your router. No dynamic DNS cron job. It just works, including from a phone on mobile data.
Step 3: Turn on MagicDNS (skip memorizing 100.x IPs)
In the Tailscale admin console, enable MagicDNS. Every device gets a stable hostname on your tailnet, so homeserver resolves without you touching /etc/hosts anywhere. If you're running internal services (Grafana, a NAS UI, whatever), this alone is worth the setup.
Step 4: Expose your whole home LAN with a subnet router
Say you've got a NAS, a Pi-hole, and a couple of IoT devices on your home LAN that aren't running Tailscale themselves. Rather than installing it on every single device, advertise your home subnet from one node:
sudo tailscale up --advertise-routes=192.168.1.0/24
Then approve the route in the admin console under Machines → your device → Edit route settings. Now any device on your tailnet can reach 192.168.1.50 directly, as if it were on the LAN.
Enable IP forwarding first, or the routes won't actually pass traffic:
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
Step 5: Set up an exit node for full-tunnel traffic
If you want all your traffic routed through home (useful on public wifi, or to get a Kenyan-looking IP while traveling), turn your server into an exit node:
sudo tailscale up --advertise-exit-node
Approve it in the admin console, then on the client device:
tailscale up --exit-node=homeserver
Now that device routes all internet traffic through your home connection.
Step 6: Lock it down with ACLs
By default every device on your tailnet can talk to every other device. That's fine for a one-person setup, but if you're sharing access with a friend or a teammate, tighten it. In the admin console under Access Controls, you define rules in JSON:
{
"acls": [
{
"action": "accept",
"src": ["group:admin"],
"dst": ["*:*"]
},
{
"action": "accept",
"src": ["group:guest"],
"dst": ["homeserver:22", "homeserver:3000"]
}
],
"groups": {
"group:admin": ["you@example.com"],
"group:guest": ["friend@example.com"]
}
}
This restricts guests to SSH and one web service on your home server, nothing else on the tailnet.
What actually goes wrong
Tailscale connects but the subnet route doesn't work. Almost always IP forwarding not enabled, or the route not approved in the admin console — Tailscale silently ignores unapproved routes rather than erroring loudly. Check tailscale status on the router node; unapproved routes show up there if you know to look.
SSH works but nothing else does behind the subnet router. Firewall on the router node itself is blocking forwarded traffic, not Tailscale. ufw in particular likes to eat forwarded packets even with ip_forward on. You may need a ufw route allow rule or to drop to iptables directly for the forwarding chain.
Exit node traffic feels slow. You're not always getting a direct peer-to-peer connection — check with tailscale ping <device>. If it says "via DERP," you're bouncing through Tailscale's relay servers because NAT traversal failed (common on CG-NAT or restrictive corporate networks). It still works, just adds latency.
Devices on the same LAN can't see each other via Tailscale, but they can over the LAN directly. This is usually fine — Tailscale prefers direct LAN connections when it detects them, so don't panic if tailscale ping shows a local IP instead of a 100.x address. That's it working correctly, not failing.
Mobile client drops the connection in the background. Android and iOS both like to kill background VPN processes to save battery. Whitelist the Tailscale app from battery optimization on Android; on iOS it's mostly out of your hands beyond keeping the app foregrounded when it matters.
A note on trust boundaries
Tailscale's control plane knows your tailnet's topology even though it doesn't see your traffic (WireGuard is end-to-end encrypted). If that's a dealbreaker for your threat model, look at Headscale, a self-hosted, open-source reimplementation of the control server that's compatible with the official Tailscale clients — same mesh convenience, no third party in the loop.
Next step
Once remote access is solid, point Tailscale Serve or Funnel at an internal service to share it over HTTPS without a reverse proxy at all — genuinely useful for quick demos without spinning up Caddy or Nginx for something you'll tear down in an hour.
Further reading
Hashtags
#tailscale #wireguard #homelab #selfhosting #meshvpn #headscale