Let’s be real: setting up a traditional VPN like OpenVPN in 2024 feels like trying to tune a carburetor in a Tesla world. You spend three hours generating certificates, another two fighting with your ISP’s CGNAT (Carrier-Grade NAT), and eventually, you just give up and open Port 1194, praying the script kiddies don’t notice.
We’re done with that. If you want to access your Home Assistant dashboard or your “totally legal” Linux ISO collection from a coffee shop, you need a Mesh VPN. We’re pitting the WireGuard-powered Tailscale against the virtual-ethernet magic of ZeroTier and the aging king, OpenVPN.
Key Takeaways
-
Zero-Config: Both Tailscale and ZeroTier use NAT traversal to bypass manual port forwarding.
-
Layer 2 vs. Layer 3: ZeroTier treats your network like one big virtual switch; Tailscale treats it like a set of point-to-point tunnels.
-
Open Source Freedom: Use Headscale to de-cloud Tailscale, or self-host your own ZeroTier controller.
-
Exit Nodes: Route public traffic through your home fiber to dodge sketchy public Wi-Fi tracking.
The Comparison: Choose Your Fighter
FeatureOpenVPN (The Classic)Tailscale (The Darling)ZeroTier (The Swiss Army Knife)Setup Time45 mins (if lucky)2 minutes3 minutesFirewallRequires open portsWorks behind NATWorks behind NATProtocolTLS/SSL (Heavy)WireGuard (Fast)Custom (Layer 2 Ethernet)Best ForHardcore LegacyEase of Use / SSOLAN Games / MulticastScalabilityManual & PainfulAutomaticNetwork ID based
Method 1: The “I Just Want It to Work” (Tailscale Docker)
Tailscale is a “SaaS” wrapper around WireGuard. It’s slick, it handles SSO (Google/GitHub/Microsoft), and it just works. Here is how you spin up a node on your server using Docker Compose.
services: tailscale: image: tailscale/tailscale:latest container_name: tailscale hostname: homeserver-primary network_mode: "host" volumes: - ./state:/var/lib/tailscale # Persists keys so you don't re-auth every reboot - /dev/net/tun:/dev/net/tun # Required for tunnel creation cap_add: - NET_ADMIN - NET_RAW environment: - TS_STATEFUL_FILTERING=true restart: unless-stoppedMethod 2: The “Virtual Ethernet” Approach (ZeroTier)
While Tailscale is like a smart router, ZeroTier is like an invisible Ethernet cable. Because it operates at Layer 2, it supports things Tailscale struggles with—like mDNS, broadcast, and multicast. If you’re trying to play StarCraft over a VPN or discovery-based protocols, this is your winner.
Joining a Network via CLI
If you already have a ZeroTier Network ID, joining from a Linux server is a one-liner:
# Install and join in one go (standard Debian/Ubuntu)curl -s [https://install.zerotier.com](https://install.zerotier.com) | sudo bashsudo zerotier-cli join <your_network_id> # Replace with your 16-digit ID
# Check your statussudo zerotier-cli listnetworksDockerized ZeroTier Node
Want to keep your host OS clean? Run ZeroTier in a container:
services: zerotier: image: zerotier/zerotier:latest container_name: zerotier devices: - /dev/net/tun:/dev/net/tun network_mode: host cap_add: - NET_ADMIN - SYS_ADMIN volumes: - ./zt-data:/var/lib/zerotier-one restart: unless-stoppedMethod 3: The “De-Clouded” Path (Headscale)
If the proprietary “Control Plane” of Tailscale gives you the creeps, Headscale is your savior. It’s an open-source implementation of the coordination server. You host it on a $5 VPS, and suddenly, you own the entire map. No Big Tech required.
# Quick Headscale config initializationmkdir -p ./headscale/configcurl [https://raw.githubusercontent.com/juanfont/headscale/main/config-example.yaml](https://raw.githubusercontent.com/juanfont/headscale/main/config-example.yaml) -o ./headscale/config/config.yaml
# Point it to your actual domainsed -i 's|[http://127.0.0.1:8080](http://127.0.0.1:8080)|[https://vpn.sumguy.com](https://vpn.sumguy.com)|g' ./headscale/config/config.yamlWhy “Zero-Trust” is the Real Flex
In the old days of OpenVPN, once a user was “in,” they could see everything. It was a security nightmare. Modern mesh VPNs use Identity-Based Networking.
In Tailscale or ZeroTier, a device doesn’t just “connect”—it must be Authorized. You can write ACLs (Access Control Lists) that say “My phone can see the Plex server, but the Plex server can’t see my phone.” That is the essence of Zero-Trust: verify everything, trust nothing.
Final Thought
OpenVPN served us well for a decade, but we’ve moved past the era of static IPs and manual port forwarding. Tailscale is the king of UX, ZeroTier is the king of “it feels like a local wire,” and both are miles ahead of punching holes in your firewall. Choose your tool, stop opening ports, and start building.
The Gotcha Nobody Warns You About: DNS Leaks and Split Horizons
Here’s the thing — you get Tailscale or ZeroTier humming along, traffic tunnels beautifully, and then you try to reach your Proxmox node by hostname from your laptop at the coffee shop. Nothing. You ping the Tailscale IP directly and it works fine. What gives?
DNS. It’s always DNS.
Mesh VPNs tunnel your traffic, but they don’t automatically fix your resolver. Your laptop is still asking your ISP’s DNS (or 8.8.8.8) to resolve proxmox.home.lab, and obviously that’s not in their zone file. You need a split-horizon DNS setup where internal hostnames resolve to internal addresses, everywhere you are.
Tailscale makes this unusually painless with MagicDNS. Once enabled in the admin panel, your nodes register their Tailscale hostnames automatically. Your server named homeserver-primary becomes reachable at homeserver-primary.your-tailnet.ts.net without any manual DNS records. Enable it once, forget about it forever.
For ZeroTier, you have to do it yourself. The most common approach is running a lightweight DNS server — Pi-hole or a dedicated Unbound instance — on a node inside the ZeroTier network, then pushing that resolver via DHCP or manual config to all your devices.
If you’re running Pi-hole already, point your client’s DNS at the ZeroTier IP of your Pi-hole node:
# Check your ZeroTier node's assigned IPsudo zerotier-cli listnetworks
# Then set your client's DNS manually (Linux / systemd-resolved)sudo resolvectl dns ztXXXXXXXX 10.147.17.2sudo resolvectl domain ztXXXXXXXX ~home.labFor Tailscale users who also run a local resolver, you can override MagicDNS for specific domains in the admin panel under DNS → Nameservers → Restrict to search domain. This lets Tailscale handle .ts.net resolution while your Pi-hole handles .home.lab — the best of both worlds.
The quick sanity check when something feels off:
# On the client, check which resolver is actually being usedresolvectl status
# Then try resolving a known internal hostname explicitlydig @10.147.17.2 proxmox.home.labIf dig works but normal browsing doesn’t, your resolver routing is the problem, not the tunnel. Fix the DNS, and everything else snaps into place.