(AI generated description after quite some time spent debugging)
Environment
- OS: Arch Linux (kernel 7.0.10-arch1-1)
- ZeroTier version: 1.16.1
- Network: Behind CGNAT (Orange ISP, Poland) with a consumer router (Orange Funbox 3.0)
- Firewall: firewalld (nftables backend)
Problem
On the same machine and network, ZeroTier on Windows established DIRECT connections to peers with no issues. After switching to Linux, the same peer is permanently on RELAY and direct connections cannot be established.
Root cause identified
The surfaceAddresses field in zerotier-cli info -j on Linux shows only CGNAT-mangled random ports:
"surfaceAddresses": [
"2a01:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/9995",
"79.184.236.195/35445",
"79.184.236.195/35424",
"79.184.236.195/36174"
]
These random ports (35445, 35424, 36174) are assigned by CGNAT for outgoing connections and have no corresponding port forwarding — making it impossible for peers to reach this node directly.
On Windows, ZeroTier correctly mapped port 9993 via UPnP and advertised <external_ip>:9993 as a surface address, which peers could successfully reach. On Linux, despite UPnP mappings existing on the router, the mapped ports never appear in IPv4 surface addresses.
Key observation
ZeroTier on Linux successfully creates UPnP mappings on the router (e.g., port 9995 for the tertiary port), but 79.184.236.195:9995 does not appear in surface addresses. Linux ZeroTier appears to discover surface addresses exclusively from what PLANET servers reflect (outgoing NAT-mangled ports), while Windows ZeroTier additionally uses the UPnP-reported external IP + mapped port to construct surface addresses.
Steps taken on Linux to try to fix this
- Opened firewalld ports for ZeroTier:
9993/udp, 9994/udp, 9995/udp
- Confirmed UPnP works — router IGD is discoverable via
upnpc -m eno1 -l
- Added fixed secondary and tertiary ports in
/var/lib/zerotier-one/local.conf:
{
"settings": {
"secondaryPort": 9994,
"tertiaryPort": 9995,
"portMappingEnabled": true
}
}
- Manually added UPnP mappings for ports 9993 and 9994 via
upnpc (since ZeroTier only maps secondary/tertiary itself)
- Created a systemd service to re-add UPnP mappings for 9993/9994 on every boot
- Confirmed UPnP entries exist on router for 9993, 9994, 9995
- Confirmed firewalld allows traffic from router IP (required for UPnP discovery)
Despite all of the above, surface addresses still show only CGNAT-mangled random ports, and the peer remains on RELAY.
Expected behavior
Same as Windows — ZeroTier should use UPnP-mapped port + external IP from the UPnP IGD to construct IPv4 surface addresses, allowing peers to reach this node directly through the UPnP-forwarded port.
Peer status
<ztaddr> <ver> <role> <lat> <link>
28bd3f4a10 1.16.1 LEAF -1 RELAY
Peer API response (/peer/<addr>)
{"address":"28bd3f4a10","paths":[],"role":"LEAF","tunneled":false}
No paths are ever discovered even when the peer is actively sending traffic.
(AI generated description after quite some time spent debugging)
Environment
Problem
On the same machine and network, ZeroTier on Windows established DIRECT connections to peers with no issues. After switching to Linux, the same peer is permanently on RELAY and direct connections cannot be established.
Root cause identified
The
surfaceAddressesfield inzerotier-cli info -jon Linux shows only CGNAT-mangled random ports:These random ports (35445, 35424, 36174) are assigned by CGNAT for outgoing connections and have no corresponding port forwarding — making it impossible for peers to reach this node directly.
On Windows, ZeroTier correctly mapped port 9993 via UPnP and advertised
<external_ip>:9993as a surface address, which peers could successfully reach. On Linux, despite UPnP mappings existing on the router, the mapped ports never appear in IPv4 surface addresses.Key observation
ZeroTier on Linux successfully creates UPnP mappings on the router (e.g., port 9995 for the tertiary port), but
79.184.236.195:9995does not appear in surface addresses. Linux ZeroTier appears to discover surface addresses exclusively from what PLANET servers reflect (outgoing NAT-mangled ports), while Windows ZeroTier additionally uses the UPnP-reported external IP + mapped port to construct surface addresses.Steps taken on Linux to try to fix this
9993/udp,9994/udp,9995/udpupnpc -m eno1 -l/var/lib/zerotier-one/local.conf:{ "settings": { "secondaryPort": 9994, "tertiaryPort": 9995, "portMappingEnabled": true } }upnpc(since ZeroTier only maps secondary/tertiary itself)Despite all of the above, surface addresses still show only CGNAT-mangled random ports, and the peer remains on RELAY.
Expected behavior
Same as Windows — ZeroTier should use UPnP-mapped port + external IP from the UPnP IGD to construct IPv4 surface addresses, allowing peers to reach this node directly through the UPnP-forwarded port.
Peer status
Peer API response (
/peer/<addr>){"address":"28bd3f4a10","paths":[],"role":"LEAF","tunneled":false}No paths are ever discovered even when the peer is actively sending traffic.