docs(site-to-vpn): trust NetBird's automatic SNAT on Linux kernel mode

On Linux in kernel mode, NetBird installs the SNAT itself when masquerade
is enabled on the routing peer — the user does not need a manual iptables
rule. Reframe Step 3 around this:

- Linux: enable ip_forward only; NetBird does the SNAT
- Non-Linux (pfSense / OPNsense / MikroTik / Windows / macOS / userspace):
  configure manual outbound SNAT on the routing peer or upstream firewall
- Tighten the "Outbound SNAT requirement" appendix accordingly
- Move the explicit Linux iptables MASQUERADE rule into a troubleshooting
  fallback for the case where NetBird's automatic SNAT doesn't fire
This commit is contained in:
Jack Carter
2026-05-13 12:42:25 +02:00
parent 7b9ec1c998
commit beb2e6e12f

View File

@@ -83,20 +83,16 @@ group.
## Step 3: Configure the Outbound SNAT ## Step 3: Configure the Outbound SNAT
This is the most commonly missed step. The routing peer must SNAT site The routing peer must SNAT site traffic onto its NetBird interface so the
traffic onto its NetBird interface so the overlay peer's access control sees overlay peer's access control sees a NetBird IP it recognises. See
a NetBird IP it recognises. NetBird does not install this for you reliably
outside of Linux kernel mode — see
[Outbound SNAT requirement](#outbound-snat-requirement) for the reasoning. [Outbound SNAT requirement](#outbound-snat-requirement) for the reasoning.
**On a Linux routing peer (any mode):** **On Linux:** NetBird installs the SNAT automatically when masquerade is
enabled on the routing peer (Step 4). Just enable IP forwarding:
```bash ```bash
sudo sysctl -w net.ipv4.ip_forward=1 sudo sysctl -w net.ipv4.ip_forward=1
echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-netbird-routing.conf echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-netbird-routing.conf
sudo iptables -t nat -A POSTROUTING -s 192.168.50.0/24 -o wt0 -j MASQUERADE
# Persist with iptables-persistent / netfilter-persistent or your distro's mechanism
``` ```
If you run a host firewall (UFW, firewalld) with the `FORWARD` chain default If you run a host firewall (UFW, firewalld) with the `FORWARD` chain default
@@ -107,21 +103,25 @@ set to `DROP`, also allow forwarding between the site-facing interface and
sudo iptables -I FORWARD 1 -i <site-iface> -o wt0 -j ACCEPT sudo iptables -I FORWARD 1 -i <site-iface> -o wt0 -j ACCEPT
``` ```
**On pfSense / OPNsense:** add an outbound NAT rule on the `wt0` (or **On any other platform** — pfSense, OPNsense, MikroTik, Windows, macOS, or
Linux running in userspace mode — NetBird does not install the SNAT for
you. Configure it manually on the routing peer or its upstream firewall.
For pfSense / OPNsense, add an outbound NAT rule on the `wt0` (or
equivalent) interface that translates traffic sourced from `192.168.50.0/24` equivalent) interface that translates traffic sourced from `192.168.50.0/24`
to the interface address. Switch outbound NAT mode to **Manual** (or to the interface address. Switch outbound NAT mode to **Manual** (or
**Hybrid**) so this rule is honoured. **Hybrid**) so this rule is honoured.
**On MikroTik (RouterOS):** For MikroTik (RouterOS):
``` ```
/ip firewall nat add chain=srcnat src-address=192.168.50.0/24 \ /ip firewall nat add chain=srcnat src-address=192.168.50.0/24 \
out-interface=wt0 action=masquerade out-interface=wt0 action=masquerade
``` ```
**On other platforms:** any outbound source NAT mechanism that rewrites the Any outbound source NAT mechanism that rewrites the site-CIDR source to the
site-CIDR source to the routing peer's NetBird IP (or to the `wt0` routing peer's NetBird IP (or to the `wt0` interface address) on the
interface address) on the NetBird egress path is sufficient. NetBird egress path is sufficient.
## Step 4: Create the Network ## Step 4: Create the Network
@@ -262,9 +262,6 @@ the `server=/netbird.cloud/...` line — you can find it with
## Outbound SNAT requirement ## Outbound SNAT requirement
Why is [Step 3](#step-3-configure-the-outbound-snat) necessary, and why
isn't the dashboard's masquerade toggle enough?
NetBird's per-peer access control on the destination peer matches inbound NetBird's per-peer access control on the destination peer matches inbound
traffic against an ipset of allowed source IPs. The ipset is populated from traffic against an ipset of allowed source IPs. The ipset is populated from
the **NetBird IPs of peers in the policy's source group** — it cannot the **NetBird IPs of peers in the policy's source group** — it cannot
@@ -277,14 +274,12 @@ enters the overlay, replacing the site IP with the routing peer's NetBird
IP. That NetBird IP **is** in the policy's source group, so the access IP. That NetBird IP **is** in the policy's source group, so the access
control matches and the packet is accepted. control matches and the packet is accepted.
On a Linux routing peer in kernel mode, NetBird's daemon can install this On a Linux routing peer running in kernel mode, NetBird installs the SNAT
SNAT itself via the kernel netfilter hooks when masquerade is enabled on itself via the kernel netfilter hooks when masquerade is enabled on the
the route/router. **In every other case** — userspace mode, non-Linux routing peer. On any other platform — pfSense, OPNsense, MikroTik,
peers, or environments where NetBird's marks aren't being set on outbound Windows, macOS, or Linux in userspace mode — that hook isn't available, so
packets — the SNAT must be configured manually on the routing peer (or on the SNAT must be configured manually on the routing peer or on its
its upstream firewall), as shown in Step 3. This is a real, observable upstream firewall, as shown in [Step 3](#step-3-configure-the-outbound-snat).
limitation rather than a quirk: without the SNAT, the dashboard masquerade
flag has no effect on the wire.
## Troubleshooting ## Troubleshooting
@@ -333,9 +328,12 @@ sudo tcpdump -ni wt0 'src net 192.168.50.0/24'
# Seeing site IPs here means SNAT is NOT firing; the target peer will drop. # Seeing site IPs here means SNAT is NOT firing; the target peer will drop.
``` ```
If you have the dashboard masquerade flag enabled but counters stay at If the routing peer is Linux in kernel mode and masquerade is enabled but
zero, NetBird's mark-driven SNAT isn't installing — fall back to the the SNAT counters stay at zero, drop in an explicit rule as a fallback:
explicit `iptables -t nat -A POSTROUTING` rule from Step 3.
```bash
sudo iptables -t nat -A POSTROUTING -s 192.168.50.0/24 -o wt0 -j MASQUERADE
```
**DNS resolution returns NXDOMAIN.** **DNS resolution returns NXDOMAIN.**