mirror of
https://github.com/netbirdio/docs.git
synced 2026-08-25 09:11:26 +02:00
docs(site-to-vpn): switch primary path to Networks; document outbound SNAT requirement
Verified in the lab that Networks supports Site-to-VPN with the same shape as Network Routes (Resource + Routing Peer + peer-group policy). The differentiating factor is not the feature but the routing peer platform: NetBird's masquerade flag does not install a working outbound SNAT on non-Linux peers or in userspace mode, so the user must configure it explicitly on the routing peer or upstream firewall. Doc changes: - Lead with Networks; Network Routes is now framed as an equivalent alternative rather than the only option - New Step 3 dedicated to the outbound SNAT (Linux iptables, pfSense / OPNsense, MikroTik examples) - New section "Outbound SNAT requirement" explaining why the destination peer's access control rejects unrewritten site IPs and where the dashboard masquerade flag is and isn't sufficient - Up-front Warning calls out the platform requirement so customers don't silently misconfigure - Troubleshooting entry updated to point at SNAT counters and tcpdump - Updated Source IP Behavior section to reflect that the behavior is the same on both Networks and Network Routes Parent page changes: - /use-cases/site-to-site: Scenario Support table now shows Site-to-VPN as Yes on both Networks and Network Routes; "Which Scenario Do I Need" row points at both implementations
This commit is contained in:
@@ -23,19 +23,36 @@ Clientless Device ──► Routing Peer ──► NetBird Overlay ──► Net
|
||||
```
|
||||
|
||||
<Note>
|
||||
Site-to-VPN is implemented with [Network Routes](/manage/network-routes). The newer [Networks](/manage/networks) feature does not yet expose
|
||||
the routed CIDR as a policy source, which is required for this scenario.
|
||||
This scenario works with both [Networks](/manage/networks) (recommended) and
|
||||
[Network Routes](/manage/network-routes) — the configuration is the same in
|
||||
substance, only the dashboard surface differs. Use Networks unless you
|
||||
already have an established Network Routes setup. This guide uses Networks.
|
||||
</Note>
|
||||
|
||||
<Warning>
|
||||
With Network Routes, the overlay peer will always observe the **routing
|
||||
peer's NetBird IP** as the source of the request, not the clientless
|
||||
device's local IP. See [Source IP Behavior](#source-ip-behavior) below for
|
||||
the details and why this is the case.
|
||||
The routing peer must perform **outbound source NAT** for site traffic
|
||||
entering the NetBird overlay. NetBird performs this automatically only when
|
||||
the routing peer is **Linux running in kernel mode**. On any other platform
|
||||
(pfSense, OPNsense, MikroTik, Windows, macOS, or Linux in userspace mode),
|
||||
you must configure the outbound NAT yourself on the routing peer or on its
|
||||
upstream firewall. Without this, the overlay peer drops the traffic at its
|
||||
access control. See [Outbound SNAT requirement](#outbound-snat-requirement).
|
||||
</Warning>
|
||||
|
||||
<Warning>
|
||||
The overlay peer will always observe the **routing peer's NetBird IP** as
|
||||
the source of the request, not the clientless device's local IP. See
|
||||
[Source IP Behavior](#source-ip-behavior) below for the details.
|
||||
</Warning>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A [NetBird cloud account](https://app.netbird.io/) or [self-hosted instance](/selfhosted/selfhosted-quickstart)
|
||||
- A device on the local network to serve as the routing peer. **Linux is
|
||||
strongly recommended** for the routing peer because it can install the
|
||||
required outbound SNAT automatically (see the warning above).
|
||||
- A separate device running the NetBird client that the clientless device
|
||||
needs to reach
|
||||
- The ability to either add a static route on the clientless device (or its
|
||||
upstream router), or to install a port-forwarding rule on the routing peer
|
||||
— both options are covered below
|
||||
@@ -77,44 +94,89 @@ sudo netbird up --setup-key YOUR_SITE_SETUP_KEY
|
||||
Confirm the peer appears in the dashboard and shows the `site-routing-peers`
|
||||
group.
|
||||
|
||||
## Step 3: Allow Forwarding Through a Host Firewall (if applicable)
|
||||
## Step 3: Configure the Outbound SNAT
|
||||
|
||||
If you run a host firewall (UFW, firewalld, custom iptables policy) on the
|
||||
routing peer with the `FORWARD` chain default set to `DROP`, allow
|
||||
forwarding between the site-facing interface and `wt0`. For example with
|
||||
`iptables`:
|
||||
This is the most commonly missed step. The routing peer must SNAT site
|
||||
traffic onto its NetBird interface so the overlay peer's access control sees
|
||||
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.
|
||||
|
||||
**On a Linux routing peer (any mode):**
|
||||
|
||||
```bash
|
||||
sudo sysctl -w net.ipv4.ip_forward=1
|
||||
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
|
||||
set to `DROP`, also allow forwarding between the site-facing interface and
|
||||
`wt0`:
|
||||
|
||||
```bash
|
||||
sudo iptables -I FORWARD 1 -i <site-iface> -o wt0 -j ACCEPT
|
||||
```
|
||||
|
||||
If no host firewall is in the way, no extra rules are needed — NetBird
|
||||
handles IP forwarding and source NAT on the routing peer.
|
||||
**On pfSense / OPNsense:** add an outbound NAT rule on the `wt0` (or
|
||||
equivalent) interface that translates traffic sourced from `192.168.50.0/24`
|
||||
to the interface address. Switch outbound NAT mode to **Manual** (or
|
||||
**Hybrid**) so this rule is honoured.
|
||||
|
||||
## Step 4: Create the Network Route
|
||||
**On MikroTik (RouterOS):**
|
||||
|
||||
```
|
||||
/ip firewall nat add chain=srcnat src-address=192.168.50.0/24 \
|
||||
out-interface=wt0 action=masquerade
|
||||
```
|
||||
|
||||
**On other platforms:** any outbound source NAT mechanism that rewrites the
|
||||
site-CIDR source to the routing peer's NetBird IP (or to the `wt0`
|
||||
interface address) on the NetBird egress path is sufficient.
|
||||
|
||||
## Step 4: Create the Network
|
||||
|
||||
In the NetBird dashboard:
|
||||
|
||||
1. Go to **Network Routes** and click **Add Route**
|
||||
2. Configure:
|
||||
- **Network Identifier:** `site-50`
|
||||
- **Network range:** `192.168.50.0/24`
|
||||
- **Routing Peer:** `site-router` (or use the `site-routing-peers` group)
|
||||
- **Distribution Groups:** `backup-collectors` (the group containing the
|
||||
peers the clientless device will reach)
|
||||
- **Masquerade:** **Enabled** (required — see
|
||||
[Source IP Behavior](#source-ip-behavior))
|
||||
- **Access Control Groups:** leave empty for site-to-VPN (these only
|
||||
apply to the VPN-to-Site direction)
|
||||
3. Click **Add Route**
|
||||
1. Go to **Networks** and click **Add Network**
|
||||
2. Name: `site-50-network`
|
||||
3. Click **Create Network**
|
||||
|
||||
The route advertises the site's CIDR onto the overlay, which gives the
|
||||
target peer a return path for any traffic that originates from the site.
|
||||
Now add the site CIDR as a resource:
|
||||
|
||||
1. In the new network, click **Add Resource**
|
||||
2. Configure:
|
||||
- **Name:** `site-50`
|
||||
- **Address:** `192.168.50.0/24`
|
||||
- **Type:** Subnet
|
||||
- **Groups:** create and add `site-50-cidr` (this group represents the
|
||||
site CIDR for use in policies)
|
||||
3. Click **Add Resource**
|
||||
|
||||
Attach the routing peer:
|
||||
|
||||
1. In the network, click **Add Routing Peer**
|
||||
2. Select `site-router` (or the `site-routing-peers` group)
|
||||
3. **Masquerade:** Enabled is fine, but does not replace
|
||||
[Step 3](#step-3-configure-the-outbound-snat) — this dashboard flag does
|
||||
not install a working SNAT on non-Linux routing peers and is unreliable in
|
||||
userspace mode
|
||||
4. Click **Save**
|
||||
|
||||
<Note>
|
||||
If you prefer Network Routes, the equivalent is **Network Routes → Add
|
||||
Route** with: network range `192.168.50.0/24`, routing peer `site-router`,
|
||||
distribution group `backup-collectors`, masquerade enabled. The rest of this
|
||||
guide applies unchanged.
|
||||
</Note>
|
||||
|
||||
## Step 5: Create the Access Policy
|
||||
|
||||
The routing peer needs to be allowed to reach the target peer over the
|
||||
overlay:
|
||||
overlay. Because Step 3's SNAT rewrites the source to the routing peer's
|
||||
NetBird IP, the policy uses peer groups:
|
||||
|
||||
1. Go to **Access Control** → **Policies** and click **Add Policy**
|
||||
2. Configure:
|
||||
@@ -125,10 +187,6 @@ overlay:
|
||||
- **Destination Groups:** `backup-collectors`
|
||||
3. Click **Add Policy**
|
||||
|
||||
Because the route has masquerade enabled, traffic from the clientless
|
||||
device will appear on the overlay as originating from the routing peer's
|
||||
NetBird IP. The policy authorises that flow.
|
||||
|
||||
## Step 6: Direct Site Traffic Through the Routing Peer
|
||||
|
||||
You have two options for getting the clientless device's traffic to the
|
||||
@@ -209,7 +267,6 @@ curl -v http://192.168.50.10:18080/
|
||||
Verify on the target peer that the request arrived:
|
||||
|
||||
```bash
|
||||
# Replace with whatever the target peer is listening with
|
||||
sudo ss -tnp | grep :8080
|
||||
```
|
||||
|
||||
@@ -255,34 +312,45 @@ the `server=/netbird.cloud/...` line — you can find it with
|
||||
`netbird status` on the routing peer.
|
||||
</Note>
|
||||
|
||||
## 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
|
||||
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
|
||||
contain a routed CIDR like `192.168.50.0/24`. So when a packet from
|
||||
`192.168.50.20` arrives at the overlay peer, the access control has no
|
||||
matching entry and the packet is dropped.
|
||||
|
||||
The fix is to rewrite the source IP at the routing peer before the packet
|
||||
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
|
||||
control matches and the packet is accepted.
|
||||
|
||||
On a Linux routing peer in kernel mode, NetBird's daemon can install this
|
||||
SNAT itself via the kernel netfilter hooks when masquerade is enabled on
|
||||
the route/router. **In every other case** — userspace mode, non-Linux
|
||||
peers, or environments where NetBird's marks aren't being set on outbound
|
||||
packets — the SNAT must be configured manually on the routing peer (or on
|
||||
its upstream firewall), as shown in Step 3. This is a real, observable
|
||||
limitation rather than a quirk: without the SNAT, the dashboard masquerade
|
||||
flag has no effect on the wire.
|
||||
|
||||
## Source IP Behavior
|
||||
|
||||
With Network Routes, the target peer always sees the **routing peer's
|
||||
NetBird IP** as the source — regardless of which clientless device on the
|
||||
site initiated the connection. Two routes lead to this:
|
||||
Because of the outbound SNAT above, the target peer always observes the
|
||||
**routing peer's NetBird IP** as the source — regardless of which clientless
|
||||
device on the site initiated the connection.
|
||||
|
||||
- With **masquerade enabled** on the route, NetBird installs a MASQUERADE
|
||||
rule on the routing peer's outbound wireguard interface, rewriting the
|
||||
source IP at the routing peer.
|
||||
- With **port forwarding (Option B)**, the routing peer SNATs the DNAT'd
|
||||
flow so that return traffic comes back to the routing peer.
|
||||
|
||||
You **cannot** preserve the clientless device's local IP all the way to
|
||||
the target peer through Network Routes. The target peer's per-peer access
|
||||
control list matches sources by NetBird IP, and there is no field on a
|
||||
legacy Network Route that registers the site CIDR as a policy source.
|
||||
Disabling masquerade does not help here: the target peer will receive
|
||||
packets with the site source IP, but they will be dropped by its access
|
||||
control because that IP is not in any allowed source group.
|
||||
|
||||
Preserving the original source IP is **not possible** with legacy Network
|
||||
Routes. Removing all policies that target the destination peer does not
|
||||
"open" it — it simply tears down the wireguard pairing with the routing
|
||||
peer, and the connection fails to establish at all. The newer
|
||||
[Networks](/manage/networks) feature is built around CIDR-bearing Resource
|
||||
groups and is the future path for preserved-source scenarios; the Site-to-VPN
|
||||
direction is not yet supported there. Track the
|
||||
[Networks documentation](/manage/networks) for updates.
|
||||
Preserving the original site source IP all the way to the target peer is
|
||||
**not currently possible**. Removing the access policy that targets the
|
||||
destination peer does not "open" it; it simply tears down the wireguard
|
||||
pairing between the routing peer and the destination, and the connection
|
||||
fails to establish at all. Future versions of [Networks](/manage/networks)
|
||||
may expose Resource groups as policy sources for the Site-to-VPN direction
|
||||
— track the Networks documentation for updates.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
@@ -316,17 +384,22 @@ allows `site-routing-peers` → target peer's group on the required port.
|
||||
|
||||
**Target peer receives packets but drops them.**
|
||||
|
||||
If you disabled masquerade on the routing peer, the target peer will see
|
||||
the raw site source IP and drop the packets at its per-peer access
|
||||
control. Enable masquerade on the routing peer to fix this.
|
||||
The outbound SNAT in [Step 3](#step-3-configure-the-outbound-snat) is
|
||||
missing or not effective. On the routing peer, packets going out `wt0` must
|
||||
have their source IP rewritten to the routing peer's NetBird IP:
|
||||
|
||||
```bash
|
||||
# On the target peer, watch for drops:
|
||||
sudo iptables -L INPUT -n -v | grep DROP
|
||||
# DROP counter on the wt0 interface increasing means the packet
|
||||
# was rejected by access control.
|
||||
# On the routing peer, verify packet counters on the MASQUERADE rule:
|
||||
sudo iptables -t nat -L POSTROUTING -n -v
|
||||
# Or watch overlay traffic on the way out:
|
||||
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.
|
||||
```
|
||||
|
||||
If you have the dashboard masquerade flag enabled but counters stay at
|
||||
zero, NetBird's mark-driven SNAT isn't installing — fall back to the
|
||||
explicit `iptables -t nat -A POSTROUTING` rule from Step 3.
|
||||
|
||||
**DNS resolution returns NXDOMAIN.**
|
||||
|
||||
Confirm the routing peer's NetBird IP is correct in `dnsmasq.conf` (it
|
||||
@@ -336,7 +409,7 @@ changes if the peer is re-enrolled), and that `dnsmasq` is not bound to
|
||||
|
||||
## Related
|
||||
|
||||
- [Networks — Concept](/manage/networks)
|
||||
- [Network Routes — Concept](/manage/network-routes)
|
||||
- [Site-to-Site: Office Networks](/manage/network-routes/use-cases/by-scenario/site-to-site-office)
|
||||
- [Configuring Routes with Access Control](/manage/network-routes/use-cases/by-configuration/access-control)
|
||||
- [Site-to-Site Overview](/use-cases/site-to-site)
|
||||
|
||||
@@ -42,7 +42,7 @@ Office Server ──────► Routing Peer ──────► NetBird T
|
||||
- On-premise servers initiating backups to cloud peers
|
||||
- Legacy systems that must initiate outbound connections
|
||||
|
||||
**Implementation:** Requires [Network Routes](/manage/network-routes) (Networks does not currently support this)
|
||||
**Implementation:** Use [Networks](/manage/networks) (recommended) or [Network Routes](/manage/network-routes). See the [Site-to-VPN guide](/manage/network-routes/use-cases/by-scenario/site-to-vpn).
|
||||
|
||||
### Site-to-Site
|
||||
|
||||
@@ -82,7 +82,7 @@ Your Laptop ──────► NetBird Tunnel ──────► Exit Node
|
||||
|-------------|----------|----------------|
|
||||
| Access home devices from my laptop | VPN-to-Site | [Networks](/manage/networks/use-cases/by-scenario/access-home-devices) |
|
||||
| Access office resources while traveling | VPN-to-Site | [Networks](/manage/networks/use-cases/by-scenario/remote-worker-access) |
|
||||
| Let an office server connect to my laptop | Site-to-VPN | [Network Routes](/manage/network-routes/use-cases/by-scenario/site-to-vpn) only |
|
||||
| Let an office server connect to my laptop | Site-to-VPN | [Networks](/manage/networks) or [Network Routes](/manage/network-routes/use-cases/by-scenario/site-to-vpn) |
|
||||
| Connect two home networks together | Site-to-Site | [Network Routes](/manage/network-routes/use-cases/by-scenario/site-to-site-home) only |
|
||||
| Link branch offices | Site-to-Site | [Network Routes](/manage/network-routes/use-cases/by-scenario/site-to-site-office) only |
|
||||
| Bridge cloud VPC with on-premise network | Site-to-Site | [Network Routes](/manage/network-routes/use-cases/by-scenario/site-to-site-cloud) only |
|
||||
@@ -158,14 +158,14 @@ NetBird offers two features for routing traffic to private networks: [Networks](
|
||||
|
||||
**Use Networks** for VPN-to-Site scenarios where you want a guided setup experience and per-resource access policies.
|
||||
|
||||
**Use Network Routes** when you need Site-to-VPN or Site-to-Site connectivity, or require advanced options like disabling masquerade.
|
||||
**Use Network Routes** when you need Site-to-Site connectivity, or require advanced options like disabling masquerade.
|
||||
|
||||
### Scenario Support
|
||||
|
||||
| Scenario | Networks | Network Routes |
|
||||
|----------|----------|----------------|
|
||||
| VPN-to-Site | Yes | Yes |
|
||||
| Site-to-VPN | No | Yes |
|
||||
| Site-to-VPN | Yes | Yes |
|
||||
| Site-to-Site | No | Yes |
|
||||
|
||||
### Detailed Comparison
|
||||
|
||||
Reference in New Issue
Block a user