How to Connect Remote Ubuntu Servers with ZeroTier

Written by: Bagus Facsi Aginsa
Published at: 12 May 2026


You have two servers. One is a VPS in Frankfurt, another is a machine sitting in your home lab. You want them to talk to each other as if they are on the same LAN, but punching through NAT, firewalls, and different ISPs to get there is a real headache. You could set up WireGuard, but then you have to manage key distribution, routing tables, and a dedicated gateway machine. You need something simpler.

That is exactly the problem ZeroTier solves. It creates an encrypted overlay network between your devices, and it does the hard work of NAT traversal automatically. No dedicated VPN server required. Two commands to install, a few clicks to authorize, and your machines are on the same virtual network.

In this tutorial, you will set up ZeroTier on two Ubuntu servers, join them to a shared virtual network, and verify that they can reach each other by private IP. By the end, you will have a working private network that you can extend to as many machines as you need.


What is ZeroTier?

ZeroTier is an open-source, software-defined networking tool. It lets you build virtual layer 2/layer 3 networks across the internet. Every device running ZeroTier gets a virtual network interface (typically named ztXXXXXXXX) and an IP address on your private network, regardless of where that device physically sits.

A few things make ZeroTier different from a traditional VPN:

  • No gateway server to manage. In a traditional VPN like WireGuard or OpenVPN, you need a central server that all clients connect through. With ZeroTier, peers establish direct connections to each other when possible. The ZeroTier coordination servers (called planet and moon nodes) only help with discovery; they do not relay your traffic in normal operation.
  • Works through NAT automatically. ZeroTier uses a technique similar to STUN/TURN (called path selection) to find the best route between two peers, including punching through NAT without port forwarding.
  • Centralized access control. Every ZeroTier network has a controller that manages which devices are allowed in. The free hosted controller at my.zerotier.com works for most use cases. You can also self-host a controller if you need to keep everything in-house.
  • Scales easily. Adding a new machine to the network takes two commands and one click in the dashboard.

ZeroTier works by assigning every device a 10-digit Node ID (a globally unique identifier derived from its public key). Networks are identified by a 16-digit Network ID. When a device joins a network and gets authorized, it receives a managed IP address on that virtual network.


Prerequisites

Before starting, you need:

  1. Two Ubuntu machines running Ubuntu 20.04 or 22.04. Both should have internet access. They can be VMs, VPS instances, or bare-metal servers.
  2. Root or sudo access on both machines.
  3. A ZeroTier account at my.zerotier.com. The free plan supports up to 25 devices, which is more than enough for this tutorial.
  4. Basic familiarity with the Linux terminal — running commands, editing files, and understanding IP addresses.

In this tutorial:

  • Server A is a VPS with a public IP (e.g., hosted on DigitalOcean or Hetzner)
  • Server B is a machine in a home lab, behind a NAT router
  • ZeroTier network subnet: 192.168.100.0/24
  • Server A ZeroTier IP: 192.168.100.1
  • Server B ZeroTier IP: 192.168.100.2

The subnet and IPs are assigned by the controller; you will configure them in the dashboard.


Step 1: Create a ZeroTier Network

Before installing anything on your servers, create the virtual network that they will join.

  1. Log in to my.zerotier.com.
  2. Click Create A Network. ZeroTier generates a 16-digit Network ID like a84ac5c10a3e8e2c.
  3. Click on the network to open its settings.
  4. Under Basics, give it a name (e.g., homelab-network) so you can identify it later.
  5. Under Advanced > IPv4 Auto-Assign, choose a subnet. Select 192.168.100.0/24 from the list (or any private subnet that does not overlap with your existing networks). Make sure Auto-Assign is enabled so ZeroTier hands out IPs automatically when nodes join.
  6. Under Access Control, leave it set to Private (the default). This means new devices will not get network access until you explicitly authorize them in the dashboard.

Copy the Network ID. You will use it in the next steps.


Step 2: Install ZeroTier on Both Servers

Run the following commands on both Server A and Server B. ZeroTier maintains an official install script that adds the correct APT repository for your Ubuntu version and installs the package.

curl -s https://install.zerotier.com | sudo bash

This script:

  1. Detects your OS version
  2. Adds the ZeroTier GPT key and APT repository
  3. Installs the zerotier-one package
  4. Starts and enables the zerotier-one systemd service

Verify the service is running:

sudo systemctl status zerotier-one

You should see active (running). The ZeroTier daemon is now running and has generated a unique Node ID for this machine.

Check the Node ID:

sudo zerotier-cli info

Example output:

200 info 89a3f5b1c7 1.14.0 ONLINE

The 10-character string (89a3f5b1c7 in this example) is the Node ID for this machine. Write it down — you will need it to authorize this node in the dashboard.

Run this on both servers and note both Node IDs.


Step 3: Join the Network on Both Servers

Now tell each server to join the network you created. Use the Network ID from Step 1.

On both servers, run:

sudo zerotier-cli join a84ac5c10a3e8e2c

Replace a84ac5c10a3e8e2c with your actual Network ID.

Expected output:

200 join OK

At this point the nodes have sent a join request to the network controller, but they are not yet authorized to communicate. The network is set to Private, so access is blocked until you approve each node.


Step 4: Authorize the Nodes in the Dashboard

Go back to the ZeroTier web dashboard and open your network. Scroll down to the Members section. You should see both servers listed there with a status of REQUESTING_CONFIG or similar, along with their Node IDs.

For each server:

  1. Check the Auth? checkbox to authorize the node.
  2. Optionally, assign a static IP from your subnet by typing 192.168.100.1 (for Server A) and 192.168.100.2 (for Server B) in the Managed IPs field, then clicking the + button to add it.

Once authorized, the node status will change to show its assigned IP address.

Back on the servers, confirm the assignment was received:

sudo zerotier-cli listnetworks

Example output:

200 listnetworks a84ac5c10a3e8e2c homelab-network 89:a3:f5:b1:c7:d2 OK PRIVATE zt3jnl8y7a 192.168.100.1/24

The OK status and the IP address (192.168.100.1/24) confirm that the node is authorized and has received its managed IP. You should also see the ZeroTier virtual interface:

ip addr show zt3jnl8y7a
5: zt3jnl8y7a: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 2800 qdisc fq_codel state UNKNOWN
    link/ether 89:a3:f5:b1:c7:d2 brd ff:ff:ff:ff:ff:ff
    inet 192.168.100.1/24 brd 192.168.100.255 scope global zt3jnl8y7a

Step 5: Verify Connectivity Between Servers

From Server A, ping Server B’s ZeroTier IP:

ping 192.168.100.2

Expected output:

PING 192.168.100.2 (192.168.100.2) 56(84) bytes of data.
64 bytes from 192.168.100.2: icmp_seq=1 ttl=64 time=4.87 ms
64 bytes from 192.168.100.2: icmp_seq=2 ttl=64 time=4.21 ms

If you see replies, the connection is working. ZeroTier has established a direct, encrypted tunnel between the two machines.

Check whether ZeroTier is using a direct path or relaying through its coordination servers:

sudo zerotier-cli peers
200 peers
<id>           VER  R  LATENCY  PATH                       
89a3f5b1c7    1.14 -  4ms      DIRECT 203.0.113.10/9993

The DIRECT label means traffic is flowing peer-to-peer without going through ZeroTier’s relay infrastructure. If you see RELAY, the peers cannot find a direct path yet (usually because of strict NAT or firewall rules) and traffic is being relayed — this still works, but with higher latency.


Step 6: Allow ZeroTier Traffic Through UFW (if Applicable)

If you have UFW (Uncomplicated Firewall) enabled on your servers, you may need to allow traffic on the ZeroTier interface explicitly.

Allow all traffic originating from the ZeroTier network interface:

sudo ufw allow in on zt3jnl8y7a
sudo ufw allow out on zt3jnl8y7a

Replace zt3jnl8y7a with the actual name of your ZeroTier interface (visible in ip addr output).

If you want to restrict access more tightly, for example only allow SSH over ZeroTier, you can do:

sudo ufw allow in on zt3jnl8y7a to any port 22 proto tcp

After adding rules, reload UFW:

sudo ufw reload

Step 7: Optional — Access Services by ZeroTier IP

With the network working, you can now use ZeroTier IPs wherever you previously needed public IPs or SSH tunnels.

For example, SSH from Server A to Server B using its ZeroTier IP:

Or access a web service running on Server B from Server A:

curl http://192.168.100.2:8080/api/health

This is useful when your services should not be exposed on a public IP at all. You can bind your applications to the ZeroTier interface IP, and they will only be reachable by authorized members of the ZeroTier network.

To bind a service (for example, a simple Python HTTP server) specifically to the ZeroTier IP:

python3 -m http.server 8080 --bind 192.168.100.2

Common Mistakes and Troubleshooting

Ping works but SSH refuses connection. The server’s firewall (UFW or iptables) is probably blocking SSH on the ZeroTier interface. Run sudo ufw allow in on ztXXXXXXXX to any port 22 proto tcp as shown in Step 6.

listnetworks shows ACCESS_DENIED instead of OK. You have not authorized the node in the dashboard yet. Go to my.zerotier.com, open the network, find the node in the Members list, and check the Auth? box.

listnetworks shows OK but no IP address. Auto-assign is not enabled, or you have not manually assigned an IP in the Managed IPs field. Open the network in the dashboard, check IPv4 Auto-Assign is on, and check that the node has an IP in the Members table.

Ping times out even though both nodes show OK. Check if a firewall is blocking UDP port 9993. ZeroTier uses UDP 9993 for its traffic. On the server side: sudo ufw allow 9993/udp. If ZeroTier is falling back to relay (RELAY in zerotier-cli peers), the ping will still work but latency will be higher — this is not an error, just a NAT traversal limitation.

zerotier-one service fails to start. Check the system journal: sudo journalctl -u zerotier-one -n 50. The most common cause is a missing or corrupt identity file. Stop the service, delete /var/lib/zerotier-one/identity.secret, and restart. The daemon will generate a new identity.

sudo systemctl stop zerotier-one
sudo rm /var/lib/zerotier-one/identity.secret
sudo systemctl start zerotier-one

Note: this gives the node a new Node ID, so you will need to re-authorize it in the dashboard.


Best Practices

Use Private networks, never Public. When you create a network, keep it set to Private. Public networks auto-authorize any device that joins, which means anyone who guesses your Network ID can join. Always use Private and authorize nodes manually.

Revoke access when a node is decommissioned. When you retire a server, deauthorize and delete it from the Members list in the dashboard. Simply uninstalling ZeroTier from the server is not enough if you want immediate revocation.

Bind sensitive services to the ZeroTier IP only. If a service (database, internal API, metrics endpoint) should only be accessed by trusted machines, bind it to 192.168.100.X rather than 0.0.0.0. This ensures it is never accidentally exposed on the public interface.

Assign static managed IPs. Auto-assign is convenient, but for servers that other services depend on, assign fixed IPs in the dashboard. This prevents an IP change if a node ever leaves and rejoins the network.

Keep ZeroTier updated. ZeroTier ships security updates through the APT repository it adds during installation. Run sudo apt update && sudo apt upgrade zerotier-one periodically to stay current.

Consider a self-hosted controller for sensitive environments. The free hosted controller at my.zerotier.com is operated by ZeroTier Inc. If your organization’s security policy requires keeping all control-plane data on-premises, ZeroTier supports running a self-hosted network controller. The zerotier-one daemon itself includes a built-in controller that can be managed via a local API.


Conclusion

You now have two Ubuntu servers connected over an encrypted ZeroTier overlay network. From here, both machines can reach each other by private IP as if they were on the same LAN, regardless of their physical location or the NAT situation between them.

What you accomplished:

  • Created a private ZeroTier network with a dedicated subnet
  • Installed and configured ZeroTier on two Ubuntu servers
  • Authorized both nodes and assigned static IPs
  • Verified direct peer-to-peer connectivity
  • Configured firewall rules to allow ZeroTier traffic

From this foundation, you can:

  • Add more machines (development workstations, CI runners, cloud VMs) to the same network
  • Run private services (databases, monitoring agents, internal APIs) that communicate over ZeroTier IPs without exposing them to the public internet
  • Explore ZeroTier’s flow rules (managed routes and traffic rules in the dashboard) to control routing behavior in more complex topologies
  • Look into self-hosting a ZeroTier network controller if you need full control over the coordination infrastructure