Skip to content

ZeroTier Advanced Configuration

This guide covers advanced ZeroTier configuration topics for RouterOS deployments: flow rules for traffic steering on the ZeroTier controller, customising how managed routes integrate with RouterOS routing, extending ZeroTier to local networks via Layer 2 bridging, and diagnosing connectivity problems.

Familiarity with ZeroTier fundamentals is assumed.

ZeroTier networks support a rules engine that can filter, tag, and steer traffic at the controller level. Rules apply to all members of a network before traffic is forwarded — similar to an ACL on a managed switch, but enforced across the virtual network.

Flow rules use a condition-action syntax. Each rule is a statement terminated by a semicolon. Rules are evaluated top-to-bottom; the first matching rule’s action applies.

Basic structure:

[condition ...] action;

Conditions match packet attributes. Multiple conditions on one line are ANDed together:

ConditionDescription
ethertype ipv4Ethernet frame type is IPv4
ethertype arpEthernet frame type is ARP
ethertype ipv6Ethernet frame type is IPv6
dport 22Destination TCP/UDP port 22
sport 22Source TCP/UDP port 22
ipprotocol tcpIP protocol is TCP
ipprotocol udpIP protocol is UDP
not <condition>Negate a condition

Actions determine what happens when conditions match:

ActionDescription
acceptAllow the packet
dropSilently discard the packet
redirect <zt-address>Redirect traffic to a specific member
breakStop rule evaluation without accept or drop

Allow only IPv4, IPv6, and ARP — drop everything else:

accept ethertype ipv4;
accept ethertype ipv6;
accept ethertype arp;
drop;

Block Telnet across the network:

drop dport 23 ipprotocol tcp;
accept;

Block SSH originating from a specific ZeroTier member (using ZeroTier address):

drop chr a84ac5c10a dport 22;
accept;

The chr (check route) condition matches packets from a specific ZeroTier node address.

Restrict traffic to IPv4 only — block raw Ethernet broadcasts and non-IP:

drop not ethertype ipv4 and not ethertype arp and not ethertype ipv6;
accept;

In ZeroTier Central:

  1. Open your network and navigate to the Flow Rules tab
  2. Enter rules in the text editor (one statement per line, semicolon-terminated)
  3. Click Save — the controller pushes rules to all online members within seconds

For self-hosted controllers, POST the rules string to the controller API:

PUT /controller/network/<network-id>
{
"rules": "<rules string>"
}

ZeroTier supports a tagging system for finer-grained rule matching without hardcoding ZeroTier addresses.

Tags are key-value pairs assigned to members in ZeroTier Central. Rules can match on tag values:

# Drop traffic between members where tag 1 values differ
drop tand 1;
accept;

Capabilities grant members permission to override rules. A member with a capability can perform actions that rules would otherwise block. Capabilities are assigned per-member in ZeroTier Central and referenced in rules using cap:

# Members without capability 2 cannot reach port 22
drop not cap 2 dport 22;
accept;

This pattern is useful for jump hosts or management systems that need broader access than ordinary members.


ZeroTier Central pushes managed routes to all authorized members. RouterOS installs these as dynamic routes in the main routing table, where they participate in standard route selection alongside static and protocol-learned routes.

Managed routes from ZeroTier default to a distance that may conflict with or override existing static routes. Adjust the route distance to control preference:

/zerotier interface set [find] route-distance=50

Lower values are preferred. Set a higher distance (e.g., 50 or 100) to make ZeroTier managed routes function as backup paths, only used when no lower-distance route exists for the same destination.

If the ZeroTier controller advertises a default route (0.0.0.0/0), RouterOS installs it in the routing table, which can redirect all traffic through the ZeroTier network. To prevent this:

/zerotier interface set [find] route-distance=200

Or disable route installation entirely and manage routes manually:

# Do not install controller-pushed routes; manage routing manually
/ip route add dst-address=10.147.17.0/24 gateway=zerotier1 comment="ZeroTier subnet"

A single RouterOS router can participate in multiple ZeroTier networks simultaneously. Each membership creates a separate ZeroTier interface with its own IP address and route set:

# Join first network
/zerotier interface add network=a84ac5c21a88c768 name=zt-corp
# Join second network
/zerotier interface add network=b12de4f89c11a221 name=zt-iot

Each interface appears independently in the routing table. Routes from each network are tagged with their respective interface:

/ip route print where gateway~"zt-"

When the same prefix is reachable via multiple ZeroTier networks, route distance and interface order determine which path is preferred.

By default, ZeroTier managed routes affect all traffic matching those prefixes. Use RouterOS policy routing to restrict ZeroTier-learned routes to specific source traffic.

ROS v7 — routing tables and rules:

# Create a dedicated routing table for ZeroTier-bound traffic
/routing table add name=to-zt fib
# Add a route to a remote ZeroTier-connected subnet in the policy table
/ip route add dst-address=10.147.17.0/24 gateway=zt-corp routing-table=to-zt
# Apply the policy table only to traffic from the guest VLAN
/routing rule add src-address=192.168.50.0/24 action=lookup table=to-zt

Alternative: mangle-based mark-routing:

# Mark routing for traffic from a specific subnet
/ip firewall mangle add chain=prerouting \
src-address=192.168.60.0/24 \
action=mark-routing new-routing-mark=to-zt passthrough=no
# Route marked traffic through the ZeroTier interface
/ip route add dst-address=0.0.0.0/0 gateway=zt-corp routing-mark=to-zt

This pattern routes a subnet’s traffic through ZeroTier without affecting the rest of the router’s forwarding.


Bridging connects the ZeroTier virtual network at Layer 2, extending the same Ethernet broadcast domain to local devices. This allows ZeroTier members to communicate with LAN devices as if on the same physical switch.

Before configuring RouterOS, enable bridging permissions in ZeroTier Central:

  1. Open your ZeroTier network settings
  2. Under Advanced, enable Allow Bridging for the member that will bridge
  3. Also enable Allow Global IPs if bridged devices need IPs outside the ZeroTier managed range

Without these controller-side permissions, bridged traffic is dropped by ZeroTier’s rules engine.

Create a bridge and add both the ZeroTier interface and local LAN ports:

# Create bridge
/interface bridge add name=zt-bridge protocol-mode=none
# Add local LAN interface (adjust to your interface name)
/interface bridge port add bridge=zt-bridge interface=ether2
# Add ZeroTier interface to the bridge
/interface bridge port add bridge=zt-bridge interface=zt-corp

Assign an IP to the bridge interface for router management access:

/ip address add address=192.168.88.1/24 interface=zt-bridge

RouterOS does not apply the forward chain to bridged traffic by default. If you use the RouterOS firewall to filter bridged packets, enable bridge firewall processing:

/ip settings set rp-filter=no
/ip firewall filter
add chain=forward in-interface=zt-bridge action=accept comment="ZeroTier bridge traffic"

For environments requiring filtering, use the bridge firewall instead:

/interface bridge settings set use-ip-firewall=yes

With L2 bridging active, DHCP and ARP cross the ZeroTier boundary. ZeroTier members on the remote side of the bridge send ARP requests that traverse the virtual network to the bridged LAN.

If a DHCP server runs on the bridged LAN, remote ZeroTier members that use their ZeroTier-assigned IP (rather than a bridged IP) will not receive DHCP leases — they are already IP-addressed by the ZeroTier controller. This is expected behavior.

To give remote ZeroTier members IPs from the LAN subnet rather than the ZeroTier pool, remove or disable ZeroTier-managed IP assignment for those members and rely on the LAN DHCP server instead.


Start troubleshooting by checking interface and peer state:

# Full interface status including ZeroTier node ID, network, and auth state
/zerotier interface print detail
# Peer list with latency and path type (DIRECT or RELAY)
/zerotier peer print

Expected healthy output:

/zerotier peer print
Flags: E - enabled
# ZT-ADDRESS LATENCY ROLE PATH
0 E a84ac5c10a 8ms LEAF DIRECT
1 E a84ac5c10b 45ms LEAF DIRECT
2 E a84ac5c10c 180ms LEAF RELAY

Peers showing RELAY are reachable but traversing ZeroTier’s relay infrastructure instead of a direct path.

Enable ZeroTier log topics to capture detailed events:

# General ZeroTier events (recommended starting point)
/system logging add topics=zerotier action=memory
# Enable debug-level logging (verbose — disable after capture)
/system logging add topics=zerotier,debug action=memory
# Read captured logs
/log print where topics~"zerotier"

Remove debug logging after investigation:

/system logging remove [find topics~"zerotier"]

RELAY Path — Peers Not Establishing Direct Connections

Section titled “RELAY Path — Peers Not Establishing Direct Connections”

RELAY means ZeroTier cannot establish a direct UDP path between peers. Traffic still flows but with higher latency and lower throughput.

Causes and fixes:

CauseFix
Upstream firewall blocks UDP 9993Allow outbound UDP 9993 on the router’s WAN
Symmetric NAT on upstream ISP/routerForward UDP 9993 from WAN to the RouterOS router
RouterOS firewall drops incoming UDP 9993Add input chain accept rule (see below)
CGNAT (carrier-grade NAT)Request a public IP or use a ZeroTier moon (relay anchor)

Add the firewall rule to permit ZeroTier traffic on the router input:

/ip firewall filter add \
chain=input \
protocol=udp \
dst-port=9993 \
action=accept \
comment="ZeroTier UDP" \
place-before=0

For port forwarding if RouterOS is behind an upstream NAT:

/ip firewall nat add \
chain=dstnat \
protocol=udp \
dst-port=9993 \
action=dst-nat \
to-addresses=<RouterOS-WAN-IP> \
to-ports=9993

Traffic Flows Between Peers but Not to LAN

Section titled “Traffic Flows Between Peers but Not to LAN”

If ZeroTier peers can ping each other’s ZeroTier IP but cannot reach LAN devices on the far side:

1. Verify allow-forwarding is enabled:

/zerotier interface print detail

If allow-forwarding=no, enable it:

/zerotier interface set [find] allow-forwarding=yes

2. Check forward chain rules:

/ip firewall filter print chain=forward

Add rules to permit traffic between ZeroTier and LAN if missing:

/ip firewall filter
add chain=forward in-interface=zt-corp out-interface=bridge-local \
action=accept comment="ZeroTier to LAN"
add chain=forward in-interface=bridge-local out-interface=zt-corp \
action=accept comment="LAN to ZeroTier"

3. Check routes are present on both routers:

/ip route print where dst-address=192.168.20.0/24

If the remote LAN route is missing, add it manually or verify the controller’s managed routes include it.

4. Verify NAT is not interfering:

If srcnat/masquerade covers the ZeroTier interface, remote routers see the ZeroTier IP as the source and may lack a return route. Remove masquerade for ZeroTier-to-ZeroTier traffic:

/ip firewall nat print chain=srcnat

Add a no-masquerade exception if needed:

/ip firewall nat add \
chain=srcnat \
src-address=192.168.10.0/24 \
dst-address=192.168.20.0/24 \
action=accept \
place-before=0 \
comment="No NAT for ZeroTier routed traffic"

ZeroTier encapsulates traffic in UDP, reducing the effective MTU. If connections work for small packets (ping) but fail or stall for larger transfers, MTU mismatch is the likely cause.

ZeroTier’s default path MTU is typically 1280–1400 bytes depending on the path. Clamp TCP MSS to match:

/ip firewall mangle add \
chain=forward \
protocol=tcp \
tcp-flags=syn \
in-interface=zt-corp \
action=change-mss \
new-mss=clamp-to-pmtu \
comment="ZeroTier MSS clamp"
/ip firewall mangle add \
chain=forward \
protocol=tcp \
tcp-flags=syn \
out-interface=zt-corp \
action=change-mss \
new-mss=clamp-to-pmtu \
comment="ZeroTier MSS clamp outbound"

Alternatively, test with an explicit MSS value:

/ip firewall mangle set [find comment~"ZeroTier MSS"] new-mss=1280
# Ping a remote ZeroTier peer by its ZeroTier IP
/ping 10.147.17.2 interface=zt-corp count=5
# Ping a device on the remote LAN
/ping 192.168.20.1 src-address=192.168.10.1 count=5
# Traceroute to diagnose where packets stop
/tool traceroute 192.168.20.1 src-address=192.168.10.1

If traceroute stops at the remote ZeroTier IP, the remote router lacks a return route or has a firewall rule blocking the traffic.