Introduction

This post serves as a personal reference and guide for setting up a tunnel and NAT configuration using ZeroTier and an EdgeRouter. The goal is to route certain machines from my home network through a virtual server in a different country. My set-up is a bit more complicated than is described here (using a VLAN and different wireless BSSID) but hopefully this simplified example will help anyone else trying to accomplish something similar.

ZeroTier Configuration

The setup begins with ZeroTier running on the EdgeRouter. I’ve configured ZT Managed routes to ensure the 192.168.4.0/24 network is accessible from any ZT host. An essential step in this configuration is verifying the connectivity to the virtual server (one of the ZT hosts) located abroad. This virtual server’s ZeroTier address should be pingable from devices on my home network, regardless of whether they have ZeroTier installed. Similarly the reverse should be true, the virtual server needs to be able to ping hosts residing behind the EdgeRouter.

Managed Routes

EdgeRouter Configuration

The EdgeRouter is configured to modify traffic using a specific table. This isn’t applied to any traffic by default but serves as a rule that we can apply to things we select:

protocols {
     static {
         table 20 {
             description "route over virtual server"
             route 0.0.0.0/0 {
                 next-hop 10.147.19.62 {
                 }
             }
         }
     }
 }

Now we can build a modify policy for the firewall that will select all traffic that originates from a selected IP range, and applies the modify table that we just defined. This lets us select packets with a specific origin and set the next hop to be the virtual server.

firewall {
  modify SOURCE_ROUTE {
    enable-default-log

    rule 10 {
        action modify
        description "Select traffic for virtaul server by source"
        modify {
            table 20
        }
        source {
            address 192.168.4.128/25
        }
    }
  }
}

Next we need to actually apply that firewall rule to real traffic. Here I apply it to all traffic coming in from eth1 (my local network interface), but note that I actually only modify the source route on half that range. So address 192.168.4.1-192.168.4.127 end up going out my usual default interface, but those in 192.168.4.128-192.168.4.255 are routed over the VPN tunnel.

interfaces {
     ethernet eth1 {
        address 192.168.4.1/24
        description "Local Network"
          firewall {
              in {
                  modify SOURCE_ROUTE
              }
          }
         
     }
 }

VPS Configuration

On the virtual server, IP forwarding needs to be enabled and NAT applied:

echo 1 > /proc/sys/net/ipv4/ip_forward

To make this permanent, add net.ipv4.ip_forward = 1 in /etc/sysctl.conf and apply the changes with sudo sysctl -p.

Setup NAT with iptables assuming eth0 is the internet interface and zt0 is the ZeroTier interface:

sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
sudo iptables -A FORWARD -i zt0 -o eth0 -j ACCEPT
sudo iptables -A FORWARD -i eth0 -o zt0 -m state --state ESTABLISHED,RELATED -j ACCEPT

Don’t forget to persist IP Tables when you are done

Results

Devices on my LAN within the 192.168.4.128-255 range (assignable via DHCP) have their traffic routed through the virtual server, effectively appearing as if located in another country. On my Edgerouter POE-5, the tunnel achieves around 9Mbit/s. While Wireguard was slightly faster, this setup offers better manageability.