Install ZeroTier Mesh VPN on Linux VPS
ZeroTier is an open-source software-defined networking tool that lets you build a virtual LAN across the internet in minutes — effectively connecting multiple VPS instances from different data centers as if they shared a single physical switch, with no firewall rules or port-forwarding required on either end.
Unlike WireGuard or OpenVPN which require a dedicated gateway server, ZeroTier operates as a full mesh network where every node can connect directly to every other node using peer-to-peer connections with built-in NAT traversal. All traffic is encrypted with Curve25519/AES-256-GCM.
How ZeroTier Works
ZeroTier consists of three layers:
| Component | Role | Location |
|---|---|---|
| Planet / Moon | Root server for peer bootstrap and discovery | my.zerotier.com (or self-hosted) |
| Controller | Manages Network IDs and member authorization | my.zerotier.com or local ZeroTierOne |
| Node (Member) | Each VPS or device joining the network | Your servers |
When two nodes join the same network, ZeroTier first attempts a direct P2P tunnel. If NAT prevents this, it falls back to a relay server — but in both cases traffic is end-to-end encrypted. You can run your own Moon (relay) server to reduce dependency on ZeroTier's infrastructure.
Prerequisites
You need at least two VPS instances (or one VPS + a local machine) running Ubuntu 22.04/24.04 or Debian 11/12:
- Minimum 512 MB RAM per node
- Kernel 3.10+ (Ubuntu 20.04+ ships with a compatible kernel)
- Outbound UDP port 9993 must not be blocked by your firewall
- A free account at my.zerotier.com to create your Network ID
Step 1: Create a ZeroTier Network
Go to my.zerotier.com → click Create A Network. The dashboard will generate a 16-character hex Network ID (e.g., a09acf02337b9b1c).
Configure the new network:
- Access Control: Set to Private (recommended — requires manual authorization of each member)
- Managed Routes: Leave as auto (default subnet is 172.22.0.0/16)
- IPv4 Auto-Assign: Keep enabled to automatically assign IPs to members
Step 2: Install ZeroTier on Each VPS
Repeat these steps on every VPS you want to connect:
# Install ZeroTier (supports Ubuntu, Debian, RHEL, Alpine, and more)
curl -s https://install.zerotier.com | sudo bash
# Verify the service is running
sudo systemctl status zerotier-one
# Check your node's ZeroTier address
sudo zerotier-cli info
The zerotier-cli info command will output something like:
200 info 1a2b3c4d5e 1.14.0 ONLINE
The 10-character hex string (1a2b3c4d5e) is this node's Node ID. Note it down — you'll need it to authorize the node in the next step.
Step 3: Join Your Network
On each VPS, run the following command replacing NETWORK_ID with your actual Network ID:
sudo zerotier-cli join a09acf02337b9b1c
Then go to my.zerotier.com → select your network → scroll to Members. Your new node will appear — tick the Auth checkbox to authorize it.
Step 4: Verify Peer Connectivity
After authorization, verify that ZeroTier has assigned an IP and that peers can communicate:
# Show your ZeroTier IP and interface
ip addr show | grep zt
# or
sudo zerotier-cli listnetworks
# List all peers and connection type
sudo zerotier-cli peers
The listnetworks output should look like:
200 listnetworks a09acf02337b9b1c OK PRIVATE zt7xxxxxxx 172.22.0.1/16
Step 5: Test Connectivity
From the first VPS, test connection to the second VPS using its ZeroTier IP:
# Ping via ZeroTier IP
ping 172.22.0.2
# SSH directly over ZeroTier
ssh [email protected]
# Benchmark bandwidth
iperf3 -s # on VPS 2
iperf3 -c 172.22.0.2 # on VPS 1
Using ZeroTier as a Private Network for Databases
One of the most practical uses of ZeroTier is keeping databases off the public internet. Instead of binding to 0.0.0.0, bind only to the ZeroTier interface:
# Configure MariaDB/MySQL to bind only to the ZeroTier IP
sudo nano /etc/mysql/mariadb.conf.d/50-server.cnf
# Change bind-address to your ZeroTier IP
bind-address = 172.22.0.1
sudo systemctl restart mariadb
# Test from the app server (over ZeroTier)
mysql -h 172.22.0.1 -u myuser -p
Configure UFW to Allow ZeroTier Traffic
If you use UFW, add rules for the ZeroTier interface:
# Allow traffic on the ZeroTier network interface
sudo ufw allow in on ztxxxxxxxx
sudo ufw allow out on ztxxxxxxxx
# Or allow the entire ZeroTier subnet
sudo ufw allow from 172.22.0.0/16
# Verify
sudo ufw status verbose
Self-Hosted Relay with a ZeroTier Moon
To eliminate dependency on ZeroTier's cloud infrastructure, you can run your own Moon (relay) server on a VPS with a public IP:
# On the VPS that will become the Moon
cd /var/lib/zerotier-one
sudo zerotier-idtool initmoon identity.public > moon.json
# Edit moon.json — add your VPS's real public IP to stableEndpoints
sudo nano moon.json
# "stableEndpoints": ["203.0.113.10/9993"]
# Generate the .moon file
sudo zerotier-idtool genmoon moon.json
# Creates: 000000xxxxxxxxxx.moon
# Get your Moon ID
sudo zerotier-cli info | awk '{print $3}'
# On every node that should use this Moon
sudo mkdir -p /var/lib/zerotier-one/moons.d
sudo cp 000000xxxxxxxxxx.moon /var/lib/zerotier-one/moons.d/
sudo systemctl restart zerotier-one
# Verify the Moon is orbited
sudo zerotier-cli listpeers | grep MOON
Verifying ZeroTier Works Correctly
# Check service status
sudo systemctl status zerotier-one
# List all joined networks
sudo zerotier-cli listnetworks
# Show all peers with connection type (DIRECT or RELAY)
sudo zerotier-cli peers
# Show ZeroTier interfaces and IPs
ip addr show | grep zt
# Test ping over ZeroTier
ping -c 4 172.22.0.2
# Follow logs in real time
sudo journalctl -u zerotier-one -f
peers output, DIRECT means a true peer-to-peer connection (low latency), while RELAY means traffic is going through ZeroTier's relay servers (higher latency). Setting up a Moon server on your own VPS is the best fix for persistent relay connections.Troubleshooting Common Issues
Error: "Unable to connect to ZeroTier service"
The ZeroTier daemon is not running or its socket is unresponsive:
# Check and restart the service
sudo systemctl status zerotier-one
sudo systemctl restart zerotier-one
# Verify socket file exists
ls -la /var/lib/zerotier-one/zerotier-one.port
Node joins but stays at REQUESTING_CONFIGURATION — no IP assigned
This almost always means the node hasn't been authorized yet in the web dashboard:
# Check current network status
sudo zerotier-cli listnetworks
# Authorized shows: OK PRIVATE
# Unauthorized shows: ACCESS_DENIED PRIVATE
Ping works but latency is very high (>100ms)
The connection is going through a relay instead of peer-to-peer. Usually caused by symmetric NAT or a firewall blocking UDP 9993:
# Check connection type
sudo zerotier-cli peers
# RELAY = via relay server, DIRECT = peer-to-peer
# Open UDP 9993 outbound
sudo ufw allow 9993/udp
# If behind strict NAT, set up a Moon server
Error: "zerotier-cli: command not found" after install
The binary may be in a different path depending on the distribution:
which zerotier-cli
ls /usr/sbin/zerotier-cli
# Reinstall if not found
curl -s https://install.zerotier.com | sudo bash
ZeroTier interface disappears after reboot
The service is not configured to start automatically:
sudo systemctl enable zerotier-one
sudo systemctl start zerotier-one
Frequently Asked Questions
How does ZeroTier compare to WireGuard?
WireGuard requires a central gateway server with a public IP — all nodes route traffic through it, and you must manually exchange keys. ZeroTier creates a full mesh where nodes connect directly to each other, has zero manual key exchange, and handles NAT traversal automatically. WireGuard has marginally lower overhead and higher raw throughput for simple hub-and-spoke topologies, while ZeroTier is far easier to manage for dynamic, multi-node networks.
Is ZeroTier production-ready?
Yes. ZeroTier uses Curve25519 for key exchange and AES-256-GCM for encryption — both are industry-standard cryptographic primitives. Many enterprises use ZeroTier in production for multi-cloud and hybrid infrastructure. Always use Private networks and regularly audit the member list.
How do I achieve full self-hosting with ZeroTier?
Set up a Moon on your own VPS as described above to eliminate relay dependency. For full controller self-hosting, run ztncui (ZeroTier Network Controller UI) or a compatible open-source alternative. This means traffic metadata never touches ZeroTier's cloud servers.