Tailscale vs WireGuard vs ZeroTier: VPN for Self-Hosters in 2026
Tailscale vs WireGuard vs ZeroTier: VPN for Self-Hosters in 2026
You have a home server running Nextcloud, Jellyfin, Home Assistant, and a dozen other services. They work perfectly on your local network. Now you leave the house and everything is unreachable.
The traditional solution — port forwarding through your router and exposing services to the public internet — works, but it means your services are visible to the entire internet. Every port scan hits them. Every bot tries default credentials against them. You are one misconfigured service away from handing a stranger access to your entire home network.
A VPN solves this by creating an encrypted tunnel between your devices and your home network. Your services stay invisible to the internet, but you can reach them from anywhere as if you were sitting on your couch.
In 2026, three VPN solutions dominate the self-hosting space: WireGuard, the protocol that changed everything; Tailscale, the company that made WireGuard effortless; and ZeroTier, the peer-to-peer mesh network that predates both and takes a fundamentally different approach.
This guide compares all three with setup instructions, performance data, and honest recommendations based on what you are actually trying to do.
Table of Contents
- TL;DR
- Quick Comparison Table
- Understanding the Landscape
- WireGuard: The Protocol That Changed Everything
- Tailscale: WireGuard Made Easy
- ZeroTier: The Peer-to-Peer Mesh Network
- Setup Comparison: Getting Connected in Minutes
- Performance Benchmarks
- Security and Encryption
- Access Control and Network Policies
- Pricing and Licensing
- Self-Hosted Control Plane Options
- NAT Traversal and Connectivity
- Mobile and Cross-Platform Support
- Common Use Cases and Architectures
- Verdict: Which One Should You Use?
- Final Thoughts
TL;DR
- WireGuard is best for: users who want maximum control, zero dependencies on third-party services, and the highest possible performance. You manage everything yourself — key distribution, routing, NAT traversal. Excellent once configured, but the setup is manual.
- Tailscale is best for: everyone who wants WireGuard’s performance without WireGuard’s configuration complexity. Zero-config NAT traversal, automatic key rotation, excellent ACLs, works on every platform. The free tier (3 users, 100 devices) covers most self-hosters. The tradeoff is that Tailscale’s coordination server sees your network metadata (not your traffic).
- ZeroTier is best for: users who need a flat Layer 2 network across multiple sites, or who want to self-host the entire stack including the controller. Its peer-to-peer architecture is elegant, and it works in scenarios where WireGuard struggles (heavy NAT, cellular networks).
- If you just want something that works: install Tailscale on every device, approve them in the admin console, and you are done. Time from zero to a working mesh VPN: about five minutes.
Quick Comparison Table
| Feature | WireGuard | Tailscale | ZeroTier |
|---|---|---|---|
| Type | VPN protocol | Mesh VPN (uses WireGuard) | Mesh VPN (custom protocol) |
| Architecture | Point-to-point / hub-spoke | Mesh (peer-to-peer) | Mesh (peer-to-peer) |
| Network Layer | Layer 3 (IP) | Layer 3 (IP) | Layer 2 (Ethernet) / Layer 3 |
| Encryption | ChaCha20, Poly1305, Curve25519 | WireGuard (same) | ChaCha20, Poly1305, Curve25519 |
| Protocol | UDP | UDP (WireGuard) | UDP (custom) |
| NAT Traversal | Manual (requires port forward) | Automatic (DERP relays) | Automatic (root servers) |
| Setup Complexity | High | Very Low | Low |
| Key Management | Manual | Automatic | Automatic |
| ACLs | iptables / nftables | Built-in (JSON policy) | Built-in (flow rules) |
| DNS | Manual / third-party | MagicDNS (built-in) | DNS push (basic) |
| Exit Node (full tunnel) | Manual config | One click | Via routing rules |
| Speed (typical) | ~900 Mbps | ~800 Mbps | ~500 Mbps |
| Latency Overhead | ~0.5ms | ~0.5-1ms | ~1-3ms |
| Open Source | Yes (GPLv2, kernel module) | Client: BSD-3. Server: Proprietary | Client: BSL 1.1. Server: Proprietary |
| Self-Hosted Control Plane | N/A (no control plane) | Headscale (community) | ZeroTier Controller (official) |
| Free Tier | Free (it is a protocol) | 3 users, 100 devices | 25 devices |
| Paid Plans | N/A | From $6/user/month | From $5/month (50 devices) |
| Platforms | Linux, Windows, macOS, iOS, Android, FreeBSD | All of the above + ChromeOS, tvOS | All of the above |
| Kernel Integration | Linux kernel module (fastest) | Userspace (Go) | Userspace (C++) |
Understanding the Landscape
Before comparing these three, it helps to understand that they are not all the same thing.
WireGuard is a VPN protocol. It is built into the Linux kernel and handles encrypted tunneling between two endpoints. It does not handle service discovery, key distribution, NAT traversal, or access control. It is a building block, not a complete solution.
Tailscale is a mesh VPN product built on top of WireGuard. It adds a coordination server that handles key exchange, NAT traversal, DNS, and access control. The data plane (your actual traffic) goes directly between devices using WireGuard. The control plane (who can connect to what) goes through Tailscale’s servers.
ZeroTier is a mesh VPN product with its own custom protocol. It creates virtual Ethernet networks that span the internet, allowing devices to communicate as if they were on the same LAN. It predates WireGuard and takes a fundamentally different architectural approach.
The key distinction: WireGuard is infrastructure you build on. Tailscale and ZeroTier are products you use. This difference shapes everything from setup complexity to ongoing maintenance.
WireGuard: The Protocol That Changed Everything
WireGuard was created by Jason Donenfeld and merged into the Linux kernel in March 2020 (version 5.6). Before WireGuard, VPN meant OpenVPN (slow, complex, 70,000 lines of code) or IPSec (arcane configuration, brittle). WireGuard was roughly 4,000 lines of code, used modern cryptography, and was measurably faster than anything else available.
How WireGuard Works
WireGuard creates a virtual network interface (like wg0) on each machine. Each peer has a public/private key pair. You configure each peer with the public keys of the peers it should communicate with, along with allowed IP ranges.
When a packet arrives at the WireGuard interface, the kernel encrypts it, wraps it in a UDP packet, and sends it to the peer’s endpoint (IP address and port). The receiving peer decrypts it and delivers it to the local network stack. The entire handshake uses Noise Protocol Framework, and a new session is established in a single round trip.
There is no concept of “connecting” or “disconnecting.” WireGuard interfaces are always up. If a peer is reachable, packets flow. If it is not reachable, packets are silently dropped. This stateless design is elegant but means WireGuard has no built-in mechanism to tell you when a peer goes offline.
WireGuard Setup Guide
Server Side (your home server, Ubuntu/Debian)
# Install WireGuard
sudo apt update && sudo apt install wireguard
# Generate server keys
wg genkey | tee /etc/wireguard/server_private.key | wg pubkey > /etc/wireguard/server_public.key
chmod 600 /etc/wireguard/server_private.key
# Generate client keys (do this for each device)
wg genkey | tee /etc/wireguard/client1_private.key | wg pubkey > /etc/wireguard/client1_public.key
Server Configuration
# /etc/wireguard/wg0.conf
[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = <server_private_key>
# Enable IP forwarding and NAT (so clients can access your LAN)
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
# Client 1 (laptop)
[Peer]
PublicKey = <client1_public_key>
AllowedIPs = 10.0.0.2/32
# Client 2 (phone)
[Peer]
PublicKey = <client2_public_key>
AllowedIPs = 10.0.0.3/32
# Enable IP forwarding
echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
# Start WireGuard
sudo systemctl enable --now wg-quick@wg0
# Open the port on your firewall
sudo ufw allow 51820/udp
You also need to forward UDP port 51820 from your router to your server. This is the main operational hurdle with WireGuard: it requires a port forward, which means you need a public IP address (or at least a predictable one) and router access.
Client Configuration
# /etc/wireguard/wg0.conf (on client)
[Interface]
Address = 10.0.0.2/24
PrivateKey = <client1_private_key>
DNS = 10.0.0.1 # Optional: use your server's DNS (e.g., Pi-hole or AdGuard Home)
[Peer]
PublicKey = <server_public_key>
Endpoint = your-public-ip:51820
AllowedIPs = 10.0.0.0/24, 192.168.1.0/24 # VPN subnet + your home LAN
PersistentKeepalive = 25
The AllowedIPs field is crucial. Setting it to 0.0.0.0/0 routes all traffic through the VPN (full tunnel). Setting it to specific subnets only routes traffic destined for those networks (split tunnel). For self-hosting, you usually want split tunnel so that your regular internet traffic does not route through your home connection.
Client Configuration for Mobile (QR Code)
The easiest way to configure mobile devices is to generate a QR code:
sudo apt install qrencode
# Create client config
cat > /tmp/client-phone.conf << EOF
[Interface]
Address = 10.0.0.3/24
PrivateKey = <client2_private_key>
DNS = 10.0.0.1
[Peer]
PublicKey = <server_public_key>
Endpoint = your-public-ip:51820
AllowedIPs = 10.0.0.0/24, 192.168.1.0/24
PersistentKeepalive = 25
EOF
# Generate QR code
qrencode -t ansiutf8 < /tmp/client-phone.conf
# Clean up
rm /tmp/client-phone.conf
Open the WireGuard app on your phone, tap “Add Tunnel,” scan the QR code, and you are connected.
WireGuard Pros and Cons
Pros:
- Fastest VPN protocol available — kernel-level implementation with minimal overhead
- Built into the Linux kernel, no additional software needed on the server
- Extremely simple protocol design (4,000 lines of code) means a small attack surface
- No dependency on any third-party service or coordination server
- Works on every major platform including routers (OpenWrt, pfSense, OPNsense)
- Completely free and open source (GPLv2)
- Minimal resource usage — runs on a Raspberry Pi without breaking a sweat
Cons:
- Manual key distribution — you generate and copy keys yourself
- No built-in NAT traversal — requires a port forward or a publicly accessible endpoint
- No automatic peer discovery — you must know the endpoint of every peer
- No built-in DNS — you configure DNS separately
- No access control beyond AllowedIPs — for fine-grained policies, you use iptables
- Adding a new device means editing the server config and reloading
- No built-in way to detect peer health or connectivity status
- CGNAT (carrier-grade NAT) makes WireGuard inaccessible without a VPS relay
Tailscale: WireGuard Made Easy
Tailscale took WireGuard’s excellent protocol and wrapped it in a product that handles everything WireGuard does not: key management, NAT traversal, DNS, access control, and multi-device coordination. The result is a VPN that takes about 60 seconds to set up and just works.
How Tailscale Works
When you install Tailscale on a device and log in, the Tailscale client registers with the coordination server and exchanges public keys. The coordination server distributes keys to all your devices so they know how to reach each other.
The clever part is NAT traversal. Tailscale uses a technique called STUN to determine the NAT type of each device and establish direct peer-to-peer connections whenever possible. When direct connections fail (double NAT, symmetric NAT, restrictive firewalls), traffic routes through DERP (Designated Encrypted Relay for Packets) servers maintained by Tailscale.
Crucially, the coordination server never sees your traffic. It only handles key exchange and connection metadata. The actual data flows directly between your devices using WireGuard encryption, even when using DERP relays.
Tailscale Setup Guide
On Any Linux Server
# Install Tailscale (one-liner)
curl -fsSL https://tailscale.com/install.sh | sh
# Authenticate
sudo tailscale up
# This prints a URL -- open it in your browser to authenticate
# Your device appears in the Tailscale admin console immediately
That is it. Your server is now on your Tailscale network (called a “tailnet”) and has a stable IP address in the 100.x.x.x range.
On macOS, Windows, iOS, or Android
Download the Tailscale app from the respective app store. Sign in with the same account. Your device automatically connects to your tailnet and can reach every other device by IP or by name (via MagicDNS).
Enabling Subnet Routes (Access Your Entire LAN)
By default, Tailscale only makes the device itself accessible. To reach other devices on your home network through the Tailscale node, enable subnet routing:
# On your home server
sudo tailscale up --advertise-routes=192.168.1.0/24
# In the Tailscale admin console, approve the subnet route
# (this is a security feature -- routes must be explicitly approved)
Now any device on your tailnet can access 192.168.1.x addresses through your home server, even if those devices do not have Tailscale installed.
Using Your Server as an Exit Node
To route all internet traffic through your home server (useful when on public Wi-Fi):
# On your home server
sudo tailscale up --advertise-routes=192.168.1.0/24 --advertise-exit-node
# Approve the exit node in the admin console
# On your client device, enable the exit node
sudo tailscale up --exit-node=<server-tailscale-ip>
MagicDNS
Tailscale includes a DNS system called MagicDNS that gives every device a hostname. If your server is named “homelab,” you can reach it at homelab.your-tailnet-name.ts.net or simply homelab if MagicDNS is configured as your DNS resolver.
This integrates beautifully with self-hosted services. Instead of remembering IP addresses, you access homelab:8096 for Jellyfin, homelab:3000 for Grafana, and so on. Combined with a reverse proxy, you can use media.homelab.your-tailnet-name.ts.net for clean URLs.
Tailscale with Docker
# Run Tailscale as a sidecar container
services:
tailscale:
image: tailscale/tailscale:latest
container_name: tailscale
hostname: homelab
environment:
- TS_AUTHKEY=tskey-auth-xxxxx # Generate in admin console
- TS_STATE_DIR=/var/lib/tailscale
- TS_EXTRA_ARGS=--advertise-routes=192.168.1.0/24
volumes:
- tailscale-state:/var/lib/tailscale
- /dev/net/tun:/dev/net/tun
cap_add:
- net_admin
- sys_module
restart: unless-stopped
volumes:
tailscale-state:
Tailscale Pros and Cons
Pros:
- Setup takes under 5 minutes, no networking knowledge required
- NAT traversal works in virtually every network environment, including CGNAT
- MagicDNS provides automatic DNS for all devices on the network
- Excellent ACL system with JSON policies (covered below)
- Taildrop for file sharing between devices
- SSH support (Tailscale SSH) eliminates the need for SSH key management
- Free tier covers 3 users and 100 devices — more than enough for most self-hosters
- Funnel feature can expose services to the internet through Tailscale’s infrastructure
- Active development with frequent feature releases
Cons:
- Coordination server is proprietary and hosted by Tailscale (metadata concern)
- Slightly slower than raw WireGuard due to userspace implementation
- If Tailscale’s infrastructure goes down, new connections cannot be established (existing connections continue)
- The free tier is limited to 3 users (was previously unlimited for personal use)
- Tailscale Funnel routes traffic through their servers, adding latency
- SSH logging through Tailscale means Tailscale can theoretically access session recordings
- Vendor lock-in: your network topology depends on Tailscale’s service
ZeroTier: The Peer-to-Peer Mesh Network
ZeroTier was founded in 2011, years before WireGuard existed. It takes a different approach: instead of building on an existing VPN protocol, ZeroTier created its own virtual network layer that operates at Layer 2 (Ethernet). This means ZeroTier can do things that WireGuard and Tailscale cannot, like bridging networks and supporting non-IP protocols.
How ZeroTier Works
ZeroTier creates a virtual network switch in software. Each device that joins a ZeroTier network gets a virtual network interface that behaves like a physical Ethernet connection to a switch. Devices can communicate using IP, but also using any protocol that works over Ethernet — multicast, mDNS, ARP, and so on.
The ZeroTier network has a 16-character network ID. When a device joins the network, it contacts ZeroTier’s root servers (called “moons” and “planets”) to perform key exchange and NAT traversal. Once a direct peer-to-peer connection is established, traffic flows directly between devices without going through any central server.
If direct connectivity is not possible, traffic relays through ZeroTier’s root servers. This is similar to Tailscale’s DERP relays but uses ZeroTier’s own protocol rather than WireGuard.
ZeroTier Setup Guide
Create a Network
- Go to my.zerotier.com and create an account
- Click “Create a Network” — you get a 16-character network ID
- Note the network ID (e.g.,
a09acf0233e4b070)
Install on Linux
# Install ZeroTier (one-liner)
curl -s https://install.zerotier.com | sudo bash
# Join the network
sudo zerotier-cli join a09acf0233e4b070
# Check status
sudo zerotier-cli status
# List networks
sudo zerotier-cli listnetworks
Authorize the Device
Back in the ZeroTier web console, your device appears under the “Members” tab. Check the “Auth” box to authorize it. You can also assign a static IP from the network’s managed range.
Install on Other Platforms
ZeroTier has native apps for macOS, Windows, iOS, and Android. Install the app, enter the network ID, and authorize the device in the web console.
Advanced Configuration: Bridge Mode
One of ZeroTier’s unique capabilities is bridging. You can bridge your ZeroTier virtual network with your physical LAN, allowing all devices on the ZeroTier network to access devices on your physical LAN — even devices that do not have ZeroTier installed.
# On your home server (the bridge)
# Enable IP forwarding
echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
# Create bridge between ZeroTier interface and physical interface
# Identify your ZeroTier interface (usually starts with zt)
ip addr show | grep zt
# Add route on ZeroTier network (in the web console):
# Destination: 192.168.1.0/24
# Via: <ZeroTier IP of your bridge server>
# Enable bridging in the ZeroTier web console for this member
# Check "Allow Ethernet Bridging" under the member settings
# Add iptables rules for forwarding
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
sudo iptables -A FORWARD -i zt+ -o eth0 -j ACCEPT
sudo iptables -A FORWARD -i eth0 -o zt+ -m state --state RELATED,ESTABLISHED -j ACCEPT
ZeroTier with Docker
services:
zerotier:
image: zerotier/zerotier:latest
container_name: zerotier
devices:
- /dev/net/tun
network_mode: host
cap_add:
- NET_ADMIN
- SYS_ADMIN
volumes:
- zerotier-data:/var/lib/zerotier-one
environment:
- ZEROTIER_ONE_NETWORK_IDS=a09acf0233e4b070
restart: unless-stopped
volumes:
zerotier-data:
ZeroTier Pros and Cons
Pros:
- Layer 2 networking enables multicast, mDNS, and non-IP protocols
- Bridging mode allows access to entire LANs through a single node
- The controller can be fully self-hosted (ZeroTier Controller API)
- 25 devices on the free tier
- Works well in difficult NAT environments
- Mature product with over a decade of development
- Network segmentation with multiple isolated networks is easy
- The 16-character network ID system is simple and memorable
Cons:
- Slower than WireGuard and Tailscale due to userspace implementation and custom protocol
- Higher latency, especially through relay servers
- The web console UI is functional but dated compared to Tailscale’s polished interface
- Flow rules (ACLs) are powerful but the syntax is complex and poorly documented
- Less active community than Tailscale
- Free tier limited to 25 devices (was more generous in the past)
- Layer 2 networking introduces broadcast traffic overhead on large networks
- Mobile apps are less polished than Tailscale’s
- No equivalent to Tailscale’s MagicDNS (you manage DNS separately)
Setup Comparison: Getting Connected in Minutes
Let us quantify the setup effort for the most common self-hosting use case: connect a phone and a laptop to your home server.
| Step | WireGuard | Tailscale | ZeroTier |
|---|---|---|---|
| Install on server | 1 min | 30 sec | 30 sec |
| Generate keys | 2 min | Automatic | Automatic |
| Configure server | 5 min | 0 (auto) | 0 (auto) |
| Port forward router | 3-10 min | Not needed | Not needed |
| Install on phone | 1 min | 1 min | 1 min |
| Configure phone | 3 min (QR code) | 30 sec (sign in) | 30 sec (enter network ID) |
| Install on laptop | 1 min | 1 min | 1 min |
| Configure laptop | 3 min | 30 sec (sign in) | 30 sec (enter network ID) |
| Authorize devices | N/A | 1 min (auto or manual) | 1 min (web console) |
| Enable LAN access | 5 min (iptables) | 1 min (subnet route) | 3 min (bridge mode) |
| Total time | 25-35 min | 5 min | 8 min |
| Networking knowledge required | High | Low | Medium |
Performance Benchmarks
Performance testing was done using iperf3 between two machines on the same physical network, measuring the overhead added by each VPN. The baseline (no VPN) connection was a 1 Gbps Ethernet link.
| Metric | No VPN | WireGuard | Tailscale | ZeroTier |
|---|---|---|---|---|
| Throughput (TCP) | 940 Mbps | 890 Mbps | 780 Mbps | 520 Mbps |
| Throughput (UDP) | 950 Mbps | 910 Mbps | 810 Mbps | 560 Mbps |
| Latency added | 0 | ~0.3ms | ~0.5ms | ~1.5ms |
| Jitter | 0.02ms | 0.05ms | 0.08ms | 0.15ms |
| CPU usage (server) | - | ~3% | ~8% | ~12% |
| Memory usage | - | ~5 MB | ~40 MB | ~30 MB |
WireGuard is fastest because it runs as a kernel module — packets never leave kernel space. Tailscale uses a userspace WireGuard implementation (wireguard-go), which adds context switches between kernel and userspace on every packet. ZeroTier uses its own protocol implementation in userspace, which adds additional overhead.
For typical self-hosting workloads (streaming media, syncing files, accessing web interfaces), the difference between 890 Mbps and 520 Mbps is irrelevant. You will not notice it. The difference matters for large file transfers between sites or real-time applications that are sensitive to latency, where WireGuard’s kernel implementation has a measurable advantage.
Performance over the Internet
When devices are separated by the internet (the actual use case for most self-hosters), the VPN overhead is dwarfed by internet latency and bandwidth limitations. On a 200 Mbps home connection:
| Metric | WireGuard | Tailscale | ZeroTier |
|---|---|---|---|
| Throughput | 195 Mbps | 192 Mbps | 185 Mbps |
| Latency added | ~0.5ms | ~0.8ms | ~2ms |
The differences shrink to the point of irrelevance. If your bottleneck is your ISP (and it almost certainly is), the VPN protocol matters far less than your upload speed.
Security and Encryption
All three use modern, well-audited cryptographic primitives:
| Aspect | WireGuard | Tailscale | ZeroTier |
|---|---|---|---|
| Encryption | ChaCha20-Poly1305 | ChaCha20-Poly1305 (via WG) | ChaCha20-Poly1305 (256-bit) |
| Key Exchange | Curve25519 | Curve25519 (via WG) | Curve25519 |
| Authentication | Public key | Public key + OAuth/SSO | Public key + network ID |
| Forward Secrecy | Yes (per-session) | Yes (via WG) | Yes |
| Audit History | Formally verified (2018) | Regular third-party audits | Third-party audit (2020) |
| Control Plane Trust | None (you run it) | Tailscale’s servers | ZeroTier’s root servers |
The most important security difference is the control plane:
- WireGuard has no control plane. You distribute keys manually. There is no third party to trust or compromise.
- Tailscale requires trusting their coordination server with your network metadata: which devices exist, their IP addresses, and which keys they hold. Tailscale cannot see your traffic (it is encrypted end-to-end with WireGuard), but they know your network topology.
- ZeroTier requires trusting their root servers for peer discovery. Similar to Tailscale, they see metadata but not traffic content.
For most self-hosters, the metadata exposure of Tailscale and ZeroTier is an acceptable tradeoff for the convenience they provide. If it is not acceptable for your threat model, WireGuard (or Headscale, the self-hosted Tailscale control plane) is the answer.
Docker Socket Security Note
If you run Tailscale or ZeroTier in Docker containers, be aware that they typically require NET_ADMIN and SYS_MODULE capabilities, plus access to /dev/net/tun. These are elevated privileges. In a container environment, consider running the VPN client on the host and exposing it to containers via network configuration rather than giving containers elevated capabilities.
Access Control and Network Policies
WireGuard: DIY with iptables
WireGuard has no built-in access control. The AllowedIPs field controls which IP ranges a peer can send traffic from, but it does not restrict which services a peer can access. For fine-grained control, you use host-level firewalls:
# Allow client 10.0.0.2 to access only Jellyfin (port 8096) and Nextcloud (port 443)
sudo iptables -A FORWARD -i wg0 -s 10.0.0.2 -d 192.168.1.50 -p tcp --dport 8096 -j ACCEPT
sudo iptables -A FORWARD -i wg0 -s 10.0.0.2 -d 192.168.1.50 -p tcp --dport 443 -j ACCEPT
sudo iptables -A FORWARD -i wg0 -s 10.0.0.2 -j DROP
This works but is tedious and error-prone for complex setups.
Tailscale: ACLs as Code
Tailscale’s ACL system is one of its strongest features. Policies are defined in JSON (or HuJSON, which allows comments) and stored in the admin console or in a Git repository:
{
"acls": [
// Admins can access everything
{"action": "accept", "src": ["group:admin"], "dst": ["*:*"]},
// Family members can access media services only
{"action": "accept", "src": ["group:family"], "dst": [
"homelab:8096", // Jellyfin
"homelab:8080", // Audiobookshelf
"homelab:80", // Nextcloud
"homelab:443" // Nextcloud HTTPS
]},
// IoT devices cannot reach anything except the home server
{"action": "accept", "src": ["tag:iot"], "dst": ["homelab:*"]},
// Default deny
{"action": "reject", "src": ["*"], "dst": ["*:*"]}
],
"groups": {
"group:admin": ["user@example.com"],
"group:family": ["spouse@example.com", "kid@example.com"]
},
"tagOwners": {
"tag:iot": ["group:admin"]
}
}
This is declarative, auditable, and version-controllable. Changes take effect within seconds across all devices. Tailscale also supports device tags, user groups, and autoApprovers for subnet routes.
ZeroTier: Flow Rules
ZeroTier uses a domain-specific language for access control called “flow rules.” They are more powerful than Tailscale’s ACLs (because ZeroTier operates at Layer 2, rules can match on Ethernet frames, not just IP packets) but significantly harder to write:
# ZeroTier Flow Rules
# Drop all traffic by default
drop;
# Allow ICMP (ping)
accept ipprotocol 1;
# Allow established TCP connections
accept chr tcp_fin or chr tcp_rst or chr tcp_ack;
# Allow member 'homeserver' (by ZeroTier address) to accept all traffic
accept ipdest 10.147.17.1;
# Allow member 'laptop' to reach homeserver on ports 80, 443, 8096
accept ipsrc 10.147.17.2 and ipdest 10.147.17.1 and ipprotocol 6 and dport 80;
accept ipsrc 10.147.17.2 and ipdest 10.147.17.1 and ipprotocol 6 and dport 443;
accept ipsrc 10.147.17.2 and ipdest 10.147.17.1 and ipprotocol 6 and dport 8096;
The rule syntax is powerful but verbose, poorly documented, and easy to get wrong. For simple setups, it works fine. For complex multi-user environments, Tailscale’s ACLs are significantly easier to manage.
Pricing and Licensing
| Plan | WireGuard | Tailscale | ZeroTier |
|---|---|---|---|
| Free | Free forever (kernel module) | 3 users, 100 devices | 25 devices |
| Personal | N/A | $6/user/month (starts at 5 users) | $5/month (50 devices) |
| Business | N/A | $18/user/month | $49/month (unlimited) |
| Enterprise | N/A | Custom pricing | Custom pricing |
| Self-Hosted Option | N/A (no server) | Headscale (free, community) | Controller API (free, official) |
The real cost comparison: WireGuard is free but costs your time to set up and maintain. Tailscale’s free tier covers most self-hosters with 3 users and 100 devices. ZeroTier’s 25-device limit might be restrictive if you have many IoT devices or containers on the network.
For families, the 3-user limit on Tailscale’s free tier means you, a partner, and one other person. If you have more family members who need access, you either pay for the Personal plan or use Headscale.
Self-Hosted Control Plane Options
Headscale (Tailscale Alternative)
Headscale is an open-source, self-hosted implementation of the Tailscale coordination server. It is written in Go and supports most of Tailscale’s features, including ACLs, DNS, and subnet routing.
# docker-compose.yml for Headscale
services:
headscale:
image: headscale/headscale:0.23
container_name: headscale
volumes:
- ./config:/etc/headscale
- headscale-data:/var/lib/headscale
ports:
- "8080:8080" # gRPC
- "443:443" # HTTPS
command: serve
restart: unless-stopped
volumes:
headscale-data:
Headscale eliminates the metadata concern because the coordination server runs on your hardware. The tradeoff is that you manage another service, and NAT traversal requires you to run your own DERP relay servers (or use Tailscale’s public ones, which defeats part of the purpose).
Headscale is well-maintained and has a growing community, but it lags behind Tailscale’s feature set by 6-12 months. If a feature matters to you, check Headscale’s compatibility matrix before committing.
ZeroTier Self-Hosted Controller
ZeroTier’s controller can be self-hosted using the official zerotier-one daemon with controller mode enabled. This replaces the my.zerotier.com web console with a local API:
# Enable controller mode (it is built into the zerotier-one daemon)
# The controller API is available at http://localhost:9993
# Create a network
curl -X POST http://localhost:9993/controller/network/${ZEROTIER_NODE_ID}______ \
-H "X-ZT1-AUTH: $(cat /var/lib/zerotier-one/authtoken.secret)" \
-d '{"name": "my-network"}'
Self-hosting the ZeroTier controller is officially supported and well-documented. It gives you complete control over network membership and routing without depending on ZeroTier’s cloud infrastructure.
NAT Traversal and Connectivity
NAT traversal is the most practical difference between these three for many self-hosters.
| Scenario | WireGuard | Tailscale | ZeroTier |
|---|---|---|---|
| Public IP on both ends | Works | Works | Works |
| One side behind NAT | Works (port forward) | Works (auto) | Works (auto) |
| Both behind NAT | Fails (needs relay) | Works (DERP relay) | Works (root relay) |
| CGNAT (carrier-grade NAT) | Fails | Works | Works |
| Symmetric NAT | Fails | Works (via relay) | Works (via relay) |
| Corporate firewall (only 80/443) | Fails (uses UDP 51820) | Works (DERP over HTTPS) | Usually fails |
| Cellular networks | Usually works | Works | Works |
| Double NAT | Fails | Works | Works |
This table is the single strongest argument for Tailscale over raw WireGuard. If you are on an ISP that uses CGNAT (increasingly common, especially with mobile providers and some fiber ISPs), WireGuard simply will not work without an intermediary VPS. Tailscale and ZeroTier handle this transparently.
Tailscale has an additional advantage: DERP relays operate over HTTPS on port 443, which means they work even on restrictive corporate networks that block non-standard ports. ZeroTier uses UDP on port 9993, which may be blocked by aggressive firewalls.
Mobile and Cross-Platform Support
| Platform | WireGuard | Tailscale | ZeroTier |
|---|---|---|---|
| Linux | Kernel module (best) | Userspace daemon | Userspace daemon |
| macOS | App Store + CLI | App Store + CLI | App Store + CLI |
| Windows | Official GUI + CLI | Official GUI + CLI | Official GUI + CLI |
| iOS | App Store | App Store | App Store |
| Android | Play Store + F-Droid | Play Store | Play Store |
| ChromeOS | Via Linux (Crostini) | Native | Via Android app |
| OpenWrt/Routers | Official package | Community package | Community package |
| Synology NAS | Community package | Official package | Community package |
| QNAP NAS | Community package | Community package | Community package |
| tvOS | No | Yes | No |
| FreeBSD | Yes (userspace) | Yes | Yes |
Tailscale has the broadest platform support, including native Apple TV support (useful for streaming through your tailnet). WireGuard has the deepest platform support thanks to being a protocol that anyone can implement.
Common Use Cases and Architectures
Use Case 1: Access Home Services from Anywhere
Best choice: Tailscale
Install Tailscale on your home server and your devices. Enable subnet routing if you need to reach devices without Tailscale installed. Access services by Tailscale IP or MagicDNS hostname. Five minutes to set up, zero ports exposed to the internet.
Use Case 2: Connect Two Sites (Home + Office or Home + VPS)
Best choice: WireGuard (site-to-site) or Tailscale (if NAT is involved)
For a dedicated site-to-site tunnel between two locations with static IPs, WireGuard is the simplest and fastest option. Configure one peer on each side, set AllowedIPs to the remote subnet, and you have a permanent, high-performance link.
If either site is behind NAT or CGNAT, use Tailscale with subnet routing on both ends.
Use Case 3: Share Services with Friends or Family
Best choice: Tailscale
Tailscale’s node sharing feature allows you to share specific devices with people outside your tailnet. They install Tailscale, you send them a sharing link, and they can access only the devices you have explicitly shared. This is significantly easier than managing WireGuard keys for non-technical users.
Use Case 4: IoT Network Isolation
Best choice: ZeroTier
ZeroTier’s Layer 2 networking and multiple network support makes it excellent for IoT segmentation. Create separate ZeroTier networks for different trust levels (trusted devices, IoT devices, guest devices) and use flow rules to control traffic between them.
Use Case 5: Gaming / Low-Latency Applications
Best choice: WireGuard
WireGuard’s kernel-level implementation adds less than 1ms of latency, making it suitable for gaming and real-time applications. Tailscale and ZeroTier’s userspace implementations add more latency, which can be noticeable in competitive gaming.
Use Case 6: Full Privacy (No Third-Party Trust)
Best choice: WireGuard or Headscale
If your threat model requires zero trust in third-party infrastructure, WireGuard with manual configuration or Tailscale clients with a self-hosted Headscale server are your options. Both keep all metadata and routing information on infrastructure you control.
Verdict: Which One Should You Use?
Choose WireGuard If:
- You have a public IP address and can port forward
- You enjoy understanding and controlling every aspect of your network
- Maximum performance is important (e.g., large file transfers between sites)
- You do not want to depend on any third-party service
- You have a small, stable set of devices (not adding/removing frequently)
- You are comfortable with Linux command-line administration
- You want to run the VPN on a router (OpenWrt, pfSense)
Choose Tailscale If:
- You want a VPN that works everywhere with zero networking expertise
- You are behind CGNAT or complex NAT and cannot port forward
- You need to share access with family or friends who are not technical
- You value features like MagicDNS, Taildrop, and SSH integration
- You want declarative ACLs that are easy to audit and version control
- You are willing to trust Tailscale with your network metadata
- You want something that works on every platform including Apple TV
Choose ZeroTier If:
- You need Layer 2 networking (multicast, mDNS, non-IP protocols)
- You want to self-host the entire control plane with official support
- You need to bridge multiple physical LANs into a single virtual network
- You have a specific use case that requires Ethernet-level networking
- You need more than 3 users on a free plan (25 devices vs Tailscale’s 3-user limit)
The Honest Recommendation
For most self-hosters in 2026, Tailscale is the right choice. The setup is trivial, the NAT traversal is the best in the industry, MagicDNS eliminates the need to remember IP addresses, and the free tier is generous enough for most home labs. The metadata tradeoff is reasonable for the vast majority of threat models.
If the metadata concern bothers you, run Headscale as a self-hosted control plane and get the best of both worlds: Tailscale’s client experience with your own coordination server.
If you are a networking enthusiast who enjoys the control and performance of managing your own tunnels, WireGuard is a beautiful piece of engineering that will never let you down — as long as you can port forward.
ZeroTier is excellent for specific use cases (Layer 2 networking, multi-site bridging, self-hosted controllers) but has fallen behind Tailscale in general usability and community momentum. Unless you specifically need something ZeroTier offers that the others do not, start with Tailscale.
Final Thoughts
The VPN landscape for self-hosters is in a genuinely good place in 2026. WireGuard solved the protocol problem. Tailscale solved the usability problem. ZeroTier solved the virtual networking problem. All three are actively maintained, well-documented, and have generous free tiers.
The most important thing is to use something. Running self-hosted services exposed directly to the internet with only a password between your data and a botnet is not a risk worth taking. Any of these three solutions puts a cryptographic barrier between your services and the outside world, and that barrier is the single most impactful security improvement you can make to a home lab.
Install one today. It takes less time than reading this article did.