Masquerade
Updated
Masquerade is on by default. The routing peer SNATs forwarded traffic to its own LAN-side IP, so the destination network does not need any awareness of NetBird. Turn it off when you need:
- Source IP visibility for auditing, compliance, or application logic.
- The destination network's existing firewalls to filter NetBird peers by their overlay IP.
What changes when masquerade is off
- The original NetBird overlay IP is preserved end-to-end.
- A return route for the NetBird CIDR (default
100.64.0.0/10) must point at the routing peer's LAN IP. Put it on the destination host, or on that subnet's default gateway when the host is not yours to change. - High availability takes extra work, because the return route has to follow a failover. See High availability with masquerade off.
Masquerade can only be turned off on Linux routing peers.
Disable masquerade on the routing peer
In the dashboard: Network Routing → Networks → your network → the routing peer row → toggle Masquerade off. The change takes effect within seconds; the routing peer stops SNATing forwarded traffic for this network.
You can also flip it through the API:
curl -X PUT https://api.netbird.io/api/networks/<NETWORK_ID>/routers/<ROUTER_ID> \
-H "Authorization: Token <API_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"peer": "<PEER_ID>", "masquerade": false, "metric": 9999, "enabled": true}'
The rest of this page covers the return-route prerequisite the destination network needs once masquerade is off.
The steps below add the route on the destination host itself. If that host is not yours to configure, put the same route on the subnet's default gateway instead. This works even when the gateway and the routing peer sit on the same subnet: replies leave the host, reach the gateway, and are sent back out of the interface they arrived on.
Inputs to substitute
The examples below use placeholders. Swap in:
100.64.0.0/10— default NetBird CIDR. See Find your account's NetBird range below for the narrower/16you should use in practice.<PEER_LAN_IP>— the routing peer's IP on the destination subnet.<IFACE>— the LAN interface on the destination host. Useip -br addrto identify it.
Find your account's NetBird range
NetBird assigns each account a single /16 block from inside the 100.64.0.0/10 CGNAT range (one of 64 possible blocks such as 100.64.0.0/16, 100.121.0.0/16, 100.127.0.0/16, …). The block is chosen randomly per account and can be customised. Use that /16 for the return route below — not the whole /10 — so you don't funnel unrelated CGNAT ranges through your routing peer.
Read it off any enrolled peer:
$ netbird status | grep "NetBird IP"
NetBird IP: 100.121.195.4/16
# → this account's block is 100.121.0.0/16
Wherever the examples below show 100.64.0.0/10, use your account's /16 instead.
Test the route before making it persistent
Add the route temporarily on the destination host:
sudo ip route add 100.64.0.0/10 via <PEER_LAN_IP>
From a NetBird peer, confirm reachability with a protocol/port your NetBird policy allows — for example curl http://<destination-ip>:<port>, or nc -zv <destination-ip> <port> for a non-HTTP service. Then remove the test route before committing the persistent version:
sudo ip route del 100.64.0.0/10 via <PEER_LAN_IP>
Persistent configuration
Follow only one of the two methods below — they're alternatives, not consecutive steps. Check which network manager your host uses:
ls /etc/netplan/
- If you see
.yamlfiles, use Netplan (most Ubuntu hosts). - If the directory is empty or missing, use systemd-networkd (Debian Server, minimal installs, or hosts using systemd-networkd directly without a netplan frontend).
Don't mix them — on Netplan hosts, systemd-networkd config you add by hand is silently ignored.
Both methods need the destination host's LAN interface name — find it with ip -br addr (e.g. eth0 or ens18). Substitute it wherever the steps below show <IFACE>.
Netplan (Ubuntu 18.04+)
On Ubuntu Server, /etc/netplan/ usually already has a yaml from cloud-init (50-cloud-init.yaml) or the installer (00-installer-config.yaml). Open the file ls showed in a text editor — nano is the simplest (run sudo apt install nano first if it's missing):
sudo nano /etc/netplan/50-cloud-init.yaml
Append the new route to the interface's existing routes: list (don't add a second routes: key — YAML won't accept that). The addresses: and default-route values shown below are placeholders for whatever is already in your file — not values to copy as-is:
network:
version: 2
ethernets:
<IFACE>: # destination's LAN interface, e.g. eth0
addresses: [192.168.1.50/24] # existing
routes:
- to: default # existing
via: 192.168.1.1
- to: 100.64.0.0/10 # add this
via: <PEER_LAN_IP> # routing peer's local IP on this subnet
If /etc/netplan/ is empty (uncommon, but possible on minimal installs or when netplan was just apt installed), create /etc/netplan/01-netbird.yaml with the full stanza, substituting real values for addresses: and the default gateway.
Save and exit. In nano: press Ctrl+O then Enter to write the file, then Ctrl+X to quit. Then apply the change:
sudo netplan apply
Recent netplan versions require 0600 permissions on yaml files under /etc/netplan/. Set with sudo chmod 0600 /etc/netplan/*.yaml if netplan apply warns.
systemd-networkd
Create a drop-in for your interface (replace <IFACE> with your LAN interface, e.g. eth0). This block creates the file and reloads in one paste:
sudo mkdir -p /etc/systemd/network/<IFACE>.network.d
sudo tee /etc/systemd/network/<IFACE>.network.d/100-netbird.conf > /dev/null <<'EOF'
[Route]
Destination=100.64.0.0/10
Gateway=<PEER_LAN_IP>
EOF
sudo networkctl reload
The drop-in path only takes effect when a .network file already matches the interface. Run networkctl status <IFACE> and check the Network File line to confirm which one — on netplan-managed hosts it's generated under /run/systemd/network/.
Verify after reboot
ip route show 100.64.0.0/10
Expect output like (where 192.168.1.10 stands for the routing peer's LAN IP — not the destination's own address):
100.64.0.0/10 via 192.168.1.10 dev eth0
Trailing fields such as proto static, onlink, or metric 100 may appear depending on the network manager — those are normal.
Then send a request from a NetBird peer and confirm the destination logs the original overlay IP:
# from a NetBird peer
curl http://<destination-ip>:<port>
# on the destination, tail the relevant log or capture briefly:
sudo tcpdump -ni <IFACE> "src net 100.64.0.0/10 and port <port>"
The source IP should fall inside your account's /16 (e.g. 100.121.x.x), not the routing peer's LAN IP.
High availability with masquerade off
The return route points at one peer, so it has to follow whichever routing peer is currently active. NetBird moves clients to the standby on its own, but it cannot change a route inside your network: left alone, the route keeps pointing at the peer that failed and replies are dropped.
Two steps:
- Give the routing peers different metrics, so the active peer is the same one for every client. With equal metrics each client picks its own by latency, and then no single next hop is correct for all of them. See High availability.
- Make the route's next hop follow the active peer. Either a shared virtual IP across the peers (VRRP, using
keepalivedon Linux, which needs them on the same subnet), or a router that moves the route when a health check fails. The mechanism lives outside NetBird. Whichever you choose, make its health check reach a destination through the tunnel rather than testing the peer itself: a routing peer whose agent is running and whose WireGuard interface is present can still be unable to forward, and neither NetBird nor an interface check notices.
Do not point the return route at both peers at once, as two static routes or an equal-cost pair. Replies reaching the peer a client is not using are silently discarded, so both ends look healthy while traffic fails.
Established TCP connections behave better here than with masquerade on. Because nothing translates them, their addresses do not change when a different peer takes over, so a held connection can stall through the failover and then continue rather than resetting. Expect the stall to outlast the failover itself, since the sender waits for its next retransmit before trying again: in our testing a 6 second failover stalled held connections for 6 to 13 seconds. Applications with short timeouts will still give up on their own.
New connections fail until both sides have converged. Recovery then costs a second brief interruption, because clients return to the primary faster than the route does, and you cannot avoid that by pinning the virtual IP to the standby: the client's switch back is automatic.
If you do not need source IP visibility, leaving masquerade on gives you high availability with none of this to operate, which is why it is the default.
Security considerations
The return route exposes the destination subnet to whatever NetBird range you configured — your account's /16 if you narrowed it (recommended), otherwise the full 100.64.0.0/10. The OS-level route does no filtering on its own — source IP transparency is the whole reason masquerade is off, so tighten access at the NetBird policy layer with source groups, ports, and posture checks. If only a subset of the destination subnet should reach NetBird peers, add host-level firewall rules (iptables, nftables, firewalld) alongside the route.

