ZeroTier is a cool bit of software (and associated infrastructure-as-a-service), and provides a nice way to create a global Layer 2 "LAN" with non-trivial encryption, NAT traversal, a mostly-decentralized mesh topology, and lots of other modern features.
I spent a while reading various HOWTO documents in order to forward ports through it, though. This is a record of what I found to work on my setup.
GOALS: Have a single, cheap VPS with a routable IPv4 address, and have it act as:
1. The egress point for Internet-bound traffic coming from anywhere on the ZeroTier network, so that I can use ZT like a traditional VPN, to get around obnoxious hotel / free-WiFi / shitty-ISP port restrictions and other filters;
2. The entry point for services I want to expose to the Internet, which may not actually run on the VPS, but I want to serve from that IP address. E.g. I don't want to pay for a VPS powerful enough to act as a TAK Server, but I do think it would be cool to run a TAK Server (on some hardware in my basement), and have it accessible via the VPS' routable IPv4. This requires a port forward from the VPS, over the ZeroTier network, to the actual hardware running the server software.
These notes assume Linux servers running Debian or Ubuntu, with the "UFW" firewall manager. (This is the default on Ubuntu 22.04, at least I'm pretty sure it is. Not sure if it's the default on stock Debian or not.)
In `/etc/ufw/rules.before`:
I *think* this is all that should be required to get the NAT/gateway functionality working, and let the VPS act as an exit node for any node on the ZeroTier network that wants to use it as a gateway.
But at the end of the file is a general routing block, which I must have inserted at some other point:
# ZeroTier forwarding -A FORWARD -i zt+ -s 172.25.0.0/16 -d 0.0.0.0/0 -j ACCEPT -A FORWARD -i en+ -s 0.0.0.0/0 -d 172.25.0.0/16 -j ACCEPT COMMIT
To be honest, I'm not entirely sure if these last two FORWARD lines are entirely necessary. The documentation I've read seems to differ on whether forwarding is basically implied by the addition of a POSTROUTING NAT rule. It would make sense if it did, but it also doesn't seem obviously harmful to include it. (Open to suggestions if anyone knows for sure what best practice is here.)
Also in `rules.before`:
If redirecting all traffic through ZeroTier is acceptable, the ZT "Global Route" feature can be used. It inserts a route similar to this:
➜ ~ ip r 0.0.0.0/1 via 172.25.1.1 dev zt0 proto static metric 5000 default via 192.168.122.1 dev en0 proto dhcp src 192.168.122.231 metric 100
It might not be apparent at first glance why this works (it wasn't to me), since the route metric on the `zt0` route is 5000 while the metric on `en0` is only 100, and lower metrics prevail. But the metric only comes into play when the two routes are considered otherwise equivalent, and these two aren't: "0.0.0.0/1" is considered a 'more specific' route than "default", even though they're functionally the same.
Anyway, this seems to work for the moment, but certainly isn't perfect.
Date Written: 2023-09-24
Tags: Linux, networking, ZeroTier