Skip to content

Pinning & Rotation

By default the gateway spreads your connections across every healthy exit node using an L4 ECMP hash. Some operations need the opposite - every packet from a single source IP. Pinning gives you that without tearing down the tunnel.

When you need to pin

  • nmap OS detection (-O) and version/script scans that correlate multiple probes - the target must see them all from one address.
  • Session-based work where a login or token is bound to the source IP.
  • Reproducing a finding you first saw from a specific node's IP.

Pin to one exit

Pin by the node's last octet (the number in its ipip-<octet> tunnel, visible in exitfleet status):

exitfleet pin 11        # all operator traffic now exits ipip-11

This replaces the ECMP default route in the exitfleet table with a single nexthop and writes a marker at /run/exitfleet.pin. The convergence daemon sees that marker and leaves the route alone - it will not restore ECMP while you are pinned, so your source IP stays put across daemon ticks.

Confirm from the operator station:

exitfleet test 5
#   1/5: 198.51.100.22
#   2/5: 198.51.100.22
#   3/5: 198.51.100.22   <- same IP every time

Return to rotation

exitfleet unpin

This removes the marker; the next daemon tick (≤30s) rebuilds the full ECMP route over all healthy nodes. The pin marker lives in /run (tmpfs), so a gateway reboot also clears it automatically.

Safety rails

The daemon validates the pin on every tick. If the marker is empty or names a tunnel that no longer exists (for example, you pinned a node and then removed it), the daemon deletes the stale marker and restores ECMP on its own - you are never left pinned to a dead exit.

exitfleet pin refuses to pin to a tunnel that doesn't exist:

exitfleet pin 99
# [exitfleet] FATAL: Tunnel ipip-99 does not exist (is node 99 deployed and healthy?)

How rotation distributes traffic

ECMP hashes (src_ip, src_port, dst_ip, dst_port) to choose a nexthop, so a connection sticks to one exit for its lifetime while different connections land on different exits. That is why curl ifconfig.me in a loop returns a spread of IPs but a single long-lived TCP session does not flap between nodes mid-connection. The L4 hash is enabled by net.ipv4.fib_multipath_hash_policy=1, which the daemon sets in preflight; without it the kernel would fall back to an L3 (src/dst IP only) hash.