← Back to DevBytes

Troubleshooting ZeroTier VPN: Common Issues and Fixes

Troubleshooting ZeroTier VPN: Common Issues and Fixes

ZeroTier is a software-defined networking solution that creates secure, peer-to-peer virtual networks across virtually any infrastructure. Unlike traditional VPNs that route all traffic through a central server, ZeroTier attempts to establish direct peer-to-peer connections between nodes, falling back to relay servers only when necessary. While this architecture delivers impressive performance and flexibility, it also introduces a unique set of troubleshooting challenges that developers and network administrators must understand.

Why Troubleshooting ZeroTier Matters

When ZeroTier works, it feels almost magical — devices on opposite sides of the planet communicate as if they were on the same local network. When it breaks, however, the decentralized nature of the system can make root causes difficult to identify. Misconfigured firewalls, NAT traversal failures, stale network states, and identity conflicts can all manifest as vague connectivity issues. A systematic troubleshooting approach is essential to minimize downtime, especially in production environments where ZeroTier might be backing remote access to internal services, IoT fleets, or multi-cloud infrastructure.

Understanding the ZeroTier Architecture

Before diving into specific issues, it helps to understand the components involved. Each ZeroTier node has a 10-digit node ID derived from its identity keypair. Networks are identified by a 16-digit network ID. Communication happens over UDP, typically on port 9993. The ZeroTier controller (hosted at my.zerotier.com or self-hosted) manages network membership and configuration, while root servers (also called "planets") assist with peer discovery and relaying when direct connections fail.

Key Diagnostic Commands

The ZeroTier CLI is your primary troubleshooting tool. On most systems, it is available as zerotier-cli and requires root or administrator privileges. Here are the commands you will use most frequently:

# Check the ZeroTier service status
sudo zerotier-cli status

# List all joined networks and their status
sudo zerotier-cli listnetworks

# List all known peers and their connection paths
sudo zerotier-cli listpeers -j

# Get detailed info about a specific network
sudo zerotier-cli info -j

# Leave a network
sudo zerotier-cli leave <network-id>

# Join a network
sudo zerotier-cli join <network-id>

The listpeers command is particularly valuable because it shows whether peers are connected directly (DIRECT), through a relay (RELAY), or not at all. This single piece of information often points you toward the root cause of connectivity problems.

Common Issue 1: Node Cannot Join a Network

One of the most frequent problems is a node that appears to join a network but never receives an IP address or never shows as authorized in the ZeroTier Central dashboard. This typically stems from one of several causes.

Checking Authorization Status

By default, ZeroTier networks require manual authorization of each joining node. After running zerotier-cli join, you must log into the ZeroTier Central web interface and authorize the new member. If the node remains unauthorized, it will not receive a network configuration or IP address.

# After joining, check the network status
sudo zerotier-cli listnetworks

# Output will look something like:
# 200 listnetworks <nwid> <name> <mac> <status> <type> <dev> <managed ips>
# 200 listnetworks 1a2b3c4d5e6f7g8h zerotier-net aa:bb:cc:dd:ee:ff ACCESS_DENIED zt0 -

If the status reads ACCESS_DENIED, the node has not been authorized on the controller. Navigate to the network's members page in ZeroTier Central and check the box next to the node's ID. Within a few seconds, the node should receive its configuration.

Verifying the ZeroTier Service is Running

If the join command itself fails, the ZeroTier daemon may not be running. Check the service status using your system's service manager:

# On systemd-based Linux distributions
sudo systemctl status zerotier-one

# On macOS
sudo launchctl list | grep zerotier

# On Windows (PowerShell)
Get-Service ZeroTierOneService

If the service is stopped, start it and check the logs for errors:

# Start the service on Linux
sudo systemctl start zerotier-one

# View recent logs on Linux
sudo journalctl -u zerotier-one -n 50 --no-pager

# View logs on macOS
cat /Library/Application\ Support/ZeroTier/One/zerotier-one.log

# View logs on Windows
Get-EventLog -LogName Application -Source "ZeroTierOne" -Newest 20

Common Issue 2: Peers Stuck in RELAY Mode

When two ZeroTier nodes cannot establish a direct UDP connection, they fall back to relaying traffic through ZeroTier's root servers. This works, but latency increases significantly and throughput drops. If listpeers shows your peers as RELAY instead of DIRECT, you likely have a NAT or firewall problem.

Diagnosing NAT and Firewall Issues

ZeroTier uses UDP hole punching to traverse NATs, which requires outbound UDP traffic on port 9993 to be allowed. Many corporate firewalls and some home routers block or throttle this traffic. Start by confirming that the node can reach ZeroTier's root servers:

# Check if UDP port 9993 is reachable from your node
# On Linux/macOS, use nc (netcat):
echo -n "test" | nc -u -w2 50.7.252.138 9993

# Alternatively, check if the ZeroTier process is listening
sudo netstat -ulnp | grep 9993
# or
sudo ss -ulnp | grep 9993

If the ZeroTier process is not listening on port 9993, there may be a configuration problem or a port conflict. Check for conflicting services:

# Find any process using port 9993
sudo lsof -i :9993
sudo fuser 9993/udp

Configuring Port Forwarding for Difficult NATs

In environments with symmetric NAT (common in some cellular networks and corporate setups), UDP hole punching may fail consistently. In these cases, manually forwarding UDP port 9993 to the ZeroTier node can force a direct connection. The exact steps depend on your router, but the general approach is:

# After configuring port forwarding, restart ZeroTier
sudo systemctl restart zerotier-one

# Wait a few seconds, then check peer connections
sleep 5
sudo zerotier-cli listpeers | grep -v RELAY

If peers still show as RELAY after port forwarding, the issue may be on the remote node's side. Both endpoints need to be able to communicate for a direct connection to form.

Common Issue 3: Connected But No IP Address

Sometimes a node shows as OK in listnetworks but has no managed IP address assigned. This usually means the network configuration on the controller does not include an IP assignment for the node, or there is a subnet conflict on the local machine.

Checking IP Assignments in ZeroTier Central

In the ZeroTier Central dashboard, navigate to the network's settings and verify that an IP address pool is configured under "IPv4 Auto-Assign." If you are using managed IPs, ensure each member has an address assigned. You can also check the local configuration:

# Get detailed network info in JSON format
sudo zerotier-cli listnetworks -j | python3 -m json.tool

# Check the local network interface
ip addr show zt0
# or on macOS:
ifconfig zt0

Resolving Subnet Conflicts

If the ZeroTier network's subnet overlaps with a physical network the node is already connected to, the operating system may refuse to add the route. For example, if your office Wi-Fi uses 192.168.1.0/24 and your ZeroTier network also uses that range, routing conflicts will occur. The fix is to change the ZeroTier network to use a non-overlapping subnet, such as 10.147.17.0/24 or 172.29.0.0/24.

# Check all routes to identify conflicts
ip route show
# or on macOS:
netstat -rn

# Look for overlapping subnets between zt0 and other interfaces
ip route | grep -E "192\.168\.|10\.|172\.(1[6-9]|2[0-9]|3[01])\."

Common Issue 4: Identity Conflicts and Cloned Nodes

ZeroTier identities are stored in a file called identity.secret. If you clone a virtual machine or container that already has ZeroTier installed, the clone will have the same identity as the original. This causes both nodes to fight over the same peer identity, leading to intermittent connectivity and bizarre routing behavior.

Detecting Identity Clones

If two nodes report the same node ID but behave inconsistently, you likely have an identity conflict. Check the node ID on each machine:

# Get the node ID
sudo zerotier-cli info

# Output: 200 info <node-id> <version> <online status>
# Example: 200 info 1a2b3c4d5e 1.12.2 ONLINE

Fixing Cloned Identities

To fix this, generate a new identity on the cloned node. Stop the ZeroTier service, remove the identity files, and restart:

# Stop the ZeroTier service
sudo systemctl stop zerotier-one

# Remove the identity files (Linux paths shown)
sudo rm /var/lib/zerotier-one/identity.secret
sudo rm /var/lib/zerotier-one/identity.public

# Restart the service - it will generate a new identity
sudo systemctl start zerotier-one

# Verify the new node ID
sleep 3
sudo zerotier-cli info

After generating a new identity, you will need to rejoin all networks and re-authorize the node in ZeroTier Central. This is why it is critical to never clone running ZeroTier installations without first removing identity files.

Common Issue 5: Connectivity Drops Intermittently

Intermittent disconnections are among the hardest issues to troubleshoot because they are transient. Common causes include aggressive NAT timeouts, flapping network interfaces, and DNS resolution problems for the ZeroTier root servers.

Tuning Keepalive and NAT Settings

Some NAT devices close UDP mappings quickly if no traffic flows. ZeroTier sends keepalive packets, but you may need to tune the frequency. Check the local configuration file:

# View the local ZeroTier configuration
cat /var/lib/zerotier-one/local.conf

# If it does not exist, create a minimal config with tuned settings
sudo tee /var/lib/zerotier-one/local.conf << 'EOF'
{
  "settings": {
    "primaryPort": 9993,
    "secondaryPort": 0,
    "tertiaryPort": 0,
    "portMappingEnabled": true,
    "softwareUpdate": "disable",
    "allowManagementFrom": []
  }
}
EOF

# Restart to apply changes
sudo systemctl restart zerotier-one

Monitoring Connection Stability

For ongoing monitoring, you can script periodic checks of peer status and log the results. This helps correlate drops with external events:

#!/bin/bash
# zero-tier-monitor.sh - Log ZeroTier peer status every 60 seconds

LOGFILE="/var/log/zerotier-monitor.log"

while true; do
    TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
    STATUS=$(sudo zerotier-cli status | awk '{print $3}')
    PEERS=$(sudo zerotier-cli listpeers | tail -n +2 | wc -l)
    DIRECT=$(sudo zerotier-cli listpeers | grep DIRECT | wc -l)
    RELAY=$(sudo zerotier-cli listpeers | grep RELAY | wc -l)
    
    echo "$TIMESTAMP status=$STATUS peers=$PEERS direct=$DIRECT relay=$RELAY" >> "$LOGFILE"
    
    sleep 60
done

Run this script in the background or as a systemd service, and review the log after a day or two to identify patterns in connectivity drops.

Common Issue 6: DNS Resolution Problems

ZeroTier does not automatically provide DNS for network members unless you configure it. If nodes can ping each other by IP but cannot resolve hostnames, you need to set up DNS within the ZeroTier network configuration.

Configuring Managed DNS

In ZeroTier Central, navigate to your network settings and look for the DNS section. You can specify a DNS server and a domain suffix. However, managed DNS requires the ZeroTier client to support it, and some older versions or certain operating systems may not honor the setting. As an alternative, you can configure DNS manually on each node:

# On Linux, add DNS for the ZeroTier interface using systemd-resolved
# First, find the zt interface name
ZT_IFACE=$(sudo zerotier-cli listnetworks | awk 'NR>1 {print $7}')
echo "ZeroTier interface: $ZT_IFACE"

# Set DNS server for the ZeroTier interface
sudo resolvectl dns "$ZT_IFACE" 10.147.17.1
sudo resolvectl domain "$ZT_IFACE" ~zerotier.local

# Verify
resolvectl status "$ZT_IFACE"

Best Practices for ZeroTier Reliability

Beyond fixing specific issues, following best practices will prevent many problems from occurring in the first place. A well-architected ZeroTier deployment is far easier to maintain and troubleshoot.

Use Consistent Naming and Documentation

Assign descriptive names to every node in ZeroTier Central. When you have dozens or hundreds of members, trying to identify nodes by their 10-digit ID is error-prone. Use a naming convention that includes the hostname, role, and location.

Pin Stable Subnets

Always choose ZeroTier subnets that do not conflict with common private ranges used by home routers, office networks, and cloud VPCs. The ranges 10.147.17.0/24 and 172.29.x.0/24 are good candidates because they are rarely used by default configurations.

Automate Deployment with Configuration Management

For fleets of nodes, use configuration management tools to ensure consistent ZeroTier installations. Here is an example Ansible task that installs ZeroTier and joins a network:

- name: Install ZeroTier repository key
  apt_key:
    url: https://download.zerotier.com/contact%40zerotier.com.gpg
    state: present
  when: ansible_os_family == "Debian"

- name: Add ZeroTier repository
  apt_repository:
    repo: "deb http://download.zerotier.com/debian/{{ ansible_distribution_release }} {{ ansible_distribution_release }} main"
    state: present
  when: ansible_os_family == "Debian"

- name: Install ZeroTier
  apt:
    name: zerotier-one
    state: present
    update_cache: yes
  when: ansible_os_family == "Debian"

- name: Ensure ZeroTier service is running
  service:
    name: zerotier-one
    state: started
    enabled: yes

- name: Join ZeroTier network
  command: zerotier-cli join {{ zerotier_network_id }}
  register: join_result
  changed_when: "'200 join OK' in join_result.stdout"

Regularly Update ZeroTier

ZeroTier is actively developed, and updates frequently include improvements to NAT traversal, peer discovery, and stability. Keep your nodes updated, but test updates in a staging environment first to avoid introducing regressions across your entire fleet.

# Check current version
sudo zerotier-cli info

# Update on Debian/Ubuntu
sudo apt update && sudo apt install --only-upgrade zerotier-one

# Update on macOS (if installed via Homebrew)
brew upgrade zertier

# Update on Windows - download the latest installer from zerotier.com

Implement Logging and Alerting

For production deployments, integrate ZeroTier status checks into your existing monitoring stack. A simple health check script can feed data into Prometheus, Datadog, or any other monitoring system:

#!/usr/bin/env python3
"""ZeroTier health check for monitoring systems."""

import json
import subprocess
import sys

def get_zerotier_status():
    try:
        result = subprocess.run(
            ["zerotier-cli", "status", "-j"],
            capture_output=True, text=True, timeout=5
        )
        return json.loads(result.stdout)
    except Exception as e:
        print(f"zerotier_status:0|g\n# error: {e}")
        sys.exit(1)

def get_network_status():
    try:
        result = subprocess.run(
            ["zerotier-cli", "listnetworks", "-j"],
            capture_output=True, text=True, timeout=5
        )
        return json.loads(result.stdout)
    except Exception:
        return []

def main():
    status = get_zerotier_status()
    online = 1 if status.get("online") else 0
    print(f"zerotier_online:{online}|g")

    networks = get_network_status()
    for net in networks:
        nwid = net.get("id", "unknown")
        net_status = 1 if net.get("status") == "OK" else 0
        print(f"zerotier_network_{nwid}_status:{net_status}|g")

if __name__ == "__main__":
    main()

Conclusion

ZeroTier is a powerful tool for building virtual networks, but its peer-to-peer architecture means that troubleshooting requires a different mindset than traditional VPNs. By understanding the roles of node identities, network authorization, NAT traversal, and relay fallbacks, you can systematically diagnose and resolve the vast majority of issues you will encounter. The key is to start with the diagnostic commands — status, listnetworks, and listpeers — and work outward from there. Combine this with solid operational practices like consistent naming, non-overlapping subnets, automated deployments, and proactive monitoring, and your ZeroTier networks will remain reliable and easy to manage even as they scale to hundreds of nodes across diverse network environments.

— Ad —

Google AdSense will appear here after approval

← Back to all articles