docs: add Site-to-VPN scenario guide (#748)

* docs: add Site-to-VPN scenario guide

New dedicated guide for letting clientless devices on a local network
initiate connections to NetBird peers (the reverse of VPN-to-Site).
Covers static-route and DNAT options, DNS resolution via dnsmasq, and
explains why the target peer always observes the routing peer's NetBird
IP as the source.

- Add src/pages/manage/network-routes/use-cases/by-scenario/site-to-vpn.mdx
- Wire it into NavigationDocs.jsx
- Update the site-to-site overview table row to point at the new page
- Replace the stub Site-to-VPN subsection in site-to-site-office.mdx
  with a pointer to the new guide

* docs(site-to-vpn): correct source-IP section, add firewall and interface notes

- Source IP Behavior: remove the option that suggested emptying the
  destination peer's policies. That doesn't preserve source IP; it just
  tears down the wireguard pairing. Replace with an honest "not possible
  with legacy Network Routes."
- Step 3: call out that hosts with FORWARD-DROP firewalls (UFW, firewalld)
  need an explicit ACCEPT rule between the site interface and wt0.
- Option B: prefix the DNAT step with `ip -br addr` so customers find the
  right site-facing interface instead of assuming eth0.
- Step 1: use "Name" for the setup key field instead of the route-only
  "Network Identifier".

* docs(site-to-vpn): tighten prereqs, firewall step, and source-IP wording

- Drop generic prereqs (account, routing peer hardware, target peer)
- Reduce Step 3 to the host-firewall FORWARD rule
- Label Networks-feature Site-to-VPN as 'not possible' rather than limited
- Rename topology arrow to 'NetBird Overlay'
- Clarify masquerade lives on the routing peer in troubleshooting

* 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

* docs(site-to-vpn): make static route the only Step 6 path; move DNAT to appendix

The static-route approach is the canonical setup; the per-service DNAT
option is a fallback for sites where routing changes aren't possible.
Treat it that way in the doc to keep the main flow linear.

- Step 6 now describes only the static-route approach (former Option A)
- Add a one-line pointer at the end of Step 6 to the appendix for sites
  where the route can't be set
- Move the DNAT instructions to a new appendix at the bottom of the page
- Simplify Test Connectivity to a single curl
- Trim the Option-A/Option-B framing from the Troubleshooting "Connection
  times out" entry

* docs(site-to-vpn): drop Source IP Behavior section

The "Outbound SNAT requirement" section already covers why the source IP
ends up as the routing peer's NetBird IP; a separate Source IP Behavior
section was repeating the same point and adding a speculative paragraph
about future Networks support. Drop both, plus the up-front Warning that
pointed at the removed section.

* docs(site-to-vpn): drop the Networks-vs-Network-Routes note

The guide is written around Networks; the side-note suggesting Network
Routes as an alternative path adds noise without value. The Step 4 inline
note keeps the Network Routes equivalent for anyone who needs it.

* docs(site-to-vpn): drop the inline Network Routes equivalent note

The guide is Networks-only now. Pointing readers at Network Routes mid-flow
just creates two paths to maintain without serving the reader who's
following the steps in front of them.

* docs(site-to-vpn): move page under Networks → Use Cases

The page describes a Networks-based setup; living under Network Routes
mis-categorised it.

- git mv to /manage/networks/use-cases/site-to-vpn.mdx (as a direct
  child of Use Cases, not under By Scenario)
- Navigation: remove entry from Network Routes → By Scenario, add under
  Networks → Use Cases
- Redirect old URL (/manage/network-routes/use-cases/by-scenario/site-to-vpn)
  to new URL, permanent
- Update in-tree links in use-cases/site-to-site/index.mdx and
  network-routes/use-cases/by-scenario/site-to-site-office.mdx

* docs(site-to-site): drop Network Routes mentions for Site-to-VPN

The Site-to-VPN guide is Networks-only; the overview page shouldn't
still be listing Network Routes alongside it.

* 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

* docs(site-to-vpn): drop sysctl ip_forward instruction on Linux

NetBird handles IP forwarding itself on Linux; the manual sysctl was
unnecessary noise. Keep the host-firewall FORWARD-ACCEPT note since
UFW/firewalld setups still need it.

* docs(site-to-vpn): route the account's /16, not the entire /10 CGNAT range

NetBird assigns each account one /16 block out of 100.64.0.0/10 (chosen
randomly, customisable). Routing the whole /10 sends unrelated CGNAT
addresses through the routing peer; the correct target is the account's
own /16.

Step 6 now:
- Explains the /16-per-account model with the 64-block context
- Shows how to read the account's /16 from `netbird status` on any peer
- Switches the Linux / Windows / DHCP-option-121 examples to a concrete
  /16 example (100.121.0.0/16) with a note to substitute your own

* docs(site-to-vpn): clarify when the target peer uses a setup key

Setup keys are for service / appliance peers; user peers (laptops,
workstations) enroll through SSO and inherit groups from existing
assignments. Reword the target-peer instruction to reflect that
distinction.

* docs(site-to-vpn): rename target peer to overlay-peer / overlay-peers

The previous backup-collector / backup-collectors naming carried
scenario-specific framing into the step examples. Use the generic
overlay-peer / overlay-peers throughout to keep the guide universal.

* chore: add trailing commas in Kubernetes nav entries

* Revert "chore: add trailing commas in Kubernetes nav entries"

This reverts commit d11b7eb7d0.
This commit is contained in:
Jack Carter
2026-05-13 13:19:15 +02:00
committed by GitHub
parent effe99bb4f
commit 2f46f5e4dc
5 changed files with 425 additions and 19 deletions
+5
View File
@@ -31,6 +31,11 @@ const nextConfig = {
destination: '/manage/networks',
permanent: true,
},
{
source: '/manage/network-routes/use-cases/by-scenario/site-to-vpn',
destination: '/manage/networks/use-cases/site-to-vpn',
permanent: true,
},
{
source: '/docs/getting-started/installation',
destination: '/get-started/install',
+4
View File
@@ -232,6 +232,10 @@ export const docsNavigation = [
},
],
},
{
title: 'Site-to-VPN',
href: '/manage/networks/use-cases/site-to-vpn',
},
],
},
],
@@ -178,21 +178,11 @@ ping 10.0.0.100 # HQ server
## Site-to-VPN: Office Systems Reaching Remote Workers
Some scenarios require office systems to initiate connections to remote workers (monitoring, management tools, etc.).
### Configuration
1. Create a network route for the office network (as above)
2. On the office system that needs to reach remote workers, add a route to the NetBird network:
```bash
# Route to NetBird network through the routing peer
sudo ip route add 100.64.0.0/10 via 10.0.0.50
```
Where `10.0.0.50` is the routing peer's office IP.
3. Create two access policies allowing traffic in both directions
Some scenarios require office systems without NetBird to initiate
connections to NetBird-connected peers (monitoring, backups, management
tools, etc.). See [Site-to-VPN](/manage/networks/use-cases/site-to-vpn)
for the full step-by-step guide, including DNS resolution and the
per-service port-forwarding alternative.
## Best Practices for Business Deployments
@@ -0,0 +1,407 @@
import { Note, Warning } from '@/components/mdx'
# Site-to-VPN: Clientless Devices Reaching NetBird Peers
This guide shows how to let a device that does **not** have NetBird installed
initiate a connection to a NetBird peer over the overlay — the reverse of the
more common VPN-to-Site direction.
## What You'll Achieve
After following this guide, a clientless device on your local network can
reach a NetBird peer by its overlay IP or NetBird DNS name. Typical examples:
- An on-premise monitoring system pushing metrics to a NetBird-connected
collector
- A legacy server initiating outbound backups to a NetBird peer in the cloud
- An office printer reporting status to a NetBird-connected management
application
```
Clientless Device ──► Routing Peer ──► NetBird Overlay ──► NetBird Peer
(no NetBird) (peer) (peer)
```
<Warning>
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>
## Prerequisites
- 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
## Example Setup
- **Local site:** `192.168.50.0/24`
- **Routing peer (`site-router`):** site IP `192.168.50.10`, NetBird IP
assigned at enrollment
- **Clientless device:** `192.168.50.20`
- **Target NetBird peer (`overlay-peer`):** runs the NetBird client; we
reach it on TCP port `8080`
## Step 1: Create Setup Keys with Groups
Before installing NetBird on the routing peer, create a setup key with an
auto-assigned group so the peer lands in the right place:
1. Go to **Setup Keys** in the NetBird dashboard
2. Click **Create Setup Key**
3. Configure:
- Name: "Site Routing Peer"
- Auto-assigned groups: create and add `site-routing-peers`
4. Click **Create** and note the key
The target peer is a regular NetBird peer; nothing special needs to be
configured on it for this scenario. If the target peer is a service or
appliance (not a user device), create a second setup key for it the same
way and add it to a group like `overlay-peers`. User peers — laptops
and workstations — enroll through SSO instead and pick up their group via
your existing group assignments.
## Step 2: Deploy the Routing Peer
Install NetBird on the routing peer and enroll it:
```bash
curl -fsSL https://pkgs.netbird.io/install.sh | sh
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: Configure the Outbound SNAT (If applicable)
The routing peer must SNAT site traffic onto its NetBird interface so the
overlay peer's access control sees a NetBird IP it recognises. See
[Outbound SNAT requirement](#outbound-snat-requirement) for the reasoning.
**On Linux:** no manual SNAT configuration is needed. NetBird enables IP
forwarding and installs the SNAT itself when masquerade is enabled on the
routing peer (Step 4).
The only Linux-side caveat is if you run a host firewall (UFW, firewalld)
with the `FORWARD` chain default set to `DROP` — in that case, allow
forwarding between the site-facing interface and `wt0`:
```bash
sudo iptables -I FORWARD 1 -i <site-iface> -o wt0 -j ACCEPT
```
**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`
to the interface address. Switch outbound NAT mode to **Manual** (or
**Hybrid**) so this rule is honoured.
For MikroTik (RouterOS):
```
/ip firewall nat add chain=srcnat src-address=192.168.50.0/24 \
out-interface=wt0 action=masquerade
```
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 **Networks** and click **Add Network**
2. Name: `site-50-network`
3. Click **Create Network**
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**
## Step 5: Create the Access Policy
The routing peer needs to be allowed to reach the target peer over the
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:
- **Name:** `Site Router to Overlay Peer`
- **Protocol:** `TCP`
- **Ports:** `8080` (or `All` to allow any port)
- **Source Groups:** `site-routing-peers`
- **Destination Groups:** `overlay-peers`
3. Click **Add Policy**
## Step 6: Direct Site Traffic Through the Routing Peer
Tell the clientless device — or the site's upstream router — to send
traffic destined for your account's NetBird IP range through the routing
peer.
### 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
site's static route — not the whole `/10` — so you don't route unrelated
CGNAT addresses through the routing peer.
Read it off any enrolled peer:
```bash
$ netbird status | grep "NetBird IP"
NetBird IP: 100.121.195.4/16
# → this account's block is 100.121.0.0/16
```
In the examples below, replace `100.121.0.0/16` with your own block.
### Install the route
**On a Linux clientless device:**
```bash
sudo ip route add 100.121.0.0/16 via 192.168.50.10
# Persist via /etc/network/interfaces, netplan, or NetworkManager
```
**On Windows:**
```powershell
route -p add 100.121.0.0 mask 255.255.0.0 192.168.50.10
```
**On a site router that issues DHCP:** add a classless static route option
(DHCP option 121) pointing your account's `/16` to the routing peer. Every
device on the network will then learn the route automatically.
The clientless device can now reach the target peer by its NetBird IP:
```bash
curl http://<TARGET_PEER_NETBIRD_IP>:8080/
```
To use NetBird's DNS names instead of IPs, see
[Resolving NetBird DNS Names](#resolving-netbird-dns-names) below.
If you cannot add a static route on the clientless device or the site
router — or you only need to expose a small number of specific services —
see [Appendix: Per-Service Port Forwarding](#appendix-per-service-port-forwarding)
for a DNAT-based alternative.
## Test Connectivity
From the clientless device:
```bash
curl -v http://<TARGET_PEER_NETBIRD_IP>:8080/
```
Verify on the target peer that the request arrived:
```bash
sudo ss -tnp | grep :8080
```
The connection's remote address on the target peer will be the **routing
peer's NetBird IP**, not the clientless device's local IP.
## Resolving NetBird DNS Names
By default, the clientless device has no way to resolve `*.netbird.cloud`
hostnames — that lookup happens locally on each NetBird peer. You can
publish those names to the site by running a forwarding resolver on the
routing peer.
A minimal `dnsmasq` configuration on the routing peer:
```ini
# /etc/dnsmasq.d/netbird.conf
bind-interfaces
listen-address=192.168.50.10
interface=eth0
# Forward NetBird-managed names to this peer's local NetBird resolver.
# The NetBird daemon listens on the peer's NetBird IP, port 53.
server=/netbird.cloud/<ROUTING_PEER_NETBIRD_IP>
# Everything else to upstream
server=8.8.8.8
server=1.1.1.1
```
Then point the clientless device's DNS at `192.168.50.10` (via DHCP,
`/etc/resolv.conf`, or static configuration) and use the NetBird hostname
directly:
```bash
curl http://overlay-peer.netbird.cloud:8080/
```
<Note>
The NetBird daemon binds its DNS resolver on the peer's own NetBird IP,
not on `127.0.0.1`. Substitute the routing peer's actual NetBird IP into
the `server=/netbird.cloud/...` line — you can find it with
`netbird status` on the routing peer.
</Note>
## Outbound SNAT requirement
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 running in kernel mode, NetBird installs the SNAT
itself via the kernel netfilter hooks when masquerade is enabled on the
routing peer. On any other platform — pfSense, OPNsense, MikroTik,
Windows, macOS, or Linux in userspace mode — that hook isn't available, so
the SNAT must be configured manually on the routing peer or on its
upstream firewall, as shown in [Step 3](#step-3-configure-the-outbound-snat).
## Troubleshooting
**Connection times out from the clientless device.**
Check that the static route is in place:
```bash
ip route get <TARGET_PEER_NETBIRD_IP>
# Should show "via 192.168.50.10 dev <iface>"
```
If you are using the appendix DNAT alternative instead, verify the
forwarding rule on the routing peer:
```bash
sudo iptables -t nat -L PREROUTING -n -v
# Should show your DNAT rule with non-zero packet counters when traffic flows
```
**Routing peer receives packets but they don't reach the target peer.**
Check that IP forwarding is enabled and confirm the target peer is reachable
from the routing peer directly:
```bash
# On the routing peer
cat /proc/sys/net/ipv4/ip_forward # should be 1
curl http://<TARGET_PEER_NETBIRD_IP>:8080/ # should succeed
```
If the second command fails, the access policy is wrong — verify the policy
allows `site-routing-peers` → target peer's group on the required port.
**Target peer receives packets but drops them.**
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 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 the routing peer is Linux in kernel mode and masquerade is enabled but
the SNAT counters stay at zero, drop in an explicit rule as a fallback:
```bash
sudo iptables -t nat -A POSTROUTING -s 192.168.50.0/24 -o wt0 -j MASQUERADE
```
**DNS resolution returns NXDOMAIN.**
Confirm the routing peer's NetBird IP is correct in `dnsmasq.conf` (it
changes if the peer is re-enrolled), and that `dnsmasq` is not bound to
`lo` — binding loopback causes it to refuse forwarding to its own
`127.0.0.1`-co-located NetBird resolver.
## 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)
- [Site-to-Site Overview](/use-cases/site-to-site)
## Appendix: Per-Service Port Forwarding
If you cannot change routing on the site — for example, the clientless
device's IP stack is fixed and the upstream router is out of your control —
you can still expose individual NetBird services through the routing peer
using DNAT. This avoids the [Step 6](#step-6-direct-site-traffic-through-the-routing-peer)
static route entirely, but each service has to be configured explicitly.
First identify the routing peer's site-facing interface:
```bash
ip -br addr
# Pick the interface that holds the routing peer's site IP (e.g. eth0, ens18).
```
Then install the DNAT rule on the routing peer:
```bash
sudo iptables -t nat -A PREROUTING -i <site-iface> -p tcp --dport 18080 \
-j DNAT --to-destination <TARGET_PEER_NETBIRD_IP>:8080
# Persist via iptables-persistent / netfilter-persistent
```
The clientless device now reaches the service through the routing peer's
local IP and the forwarded port:
```bash
curl http://192.168.50.10:18080/
```
The outbound SNAT configured in [Step 3](#step-3-configure-the-outbound-snat)
applies to this traffic as well — the target peer still observes the
routing peer's NetBird IP as the source.
Each forwarded service needs its own DNAT rule. This pattern is a good fit
for a small number of well-known services; for general overlay access, use
the static-route approach in Step 6 instead.
+4 -4
View File
@@ -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:** See the [Site-to-VPN guide](/manage/networks/use-cases/site-to-vpn) for the full setup with [Networks](/manage/networks).
### 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-site-office) only |
| Let an office server connect to my laptop | Site-to-VPN | [Networks](/manage/networks/use-cases/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