Site-to-Site

Site-to-Site connects two networks through routing peers at each end. Neither end-device needs NetBird installed — the routing peers forward traffic across the NetBird tunnel.

Architecture

Site A device ──► Routing Peer ──► NetBird Tunnel ──► Routing Peer ──► Site B device
 (no NetBird)       (peer)                              (peer)         (no NetBird)

Prerequisites

  • A NetBird account (cloud or self-hosted)
  • An always-on device at each site to act as the routing peer (server, VM, Raspberry Pi, NAS with Docker)
  • Different subnets at each site. If both sites use the same range (e.g. 192.168.1.0/24), see Overlapping Routes

Example

Two sites, A and B:

  • Site A: 10.0.0.0/24, routing peer group site-a-routers
  • Site B: 10.1.0.0/24, routing peer group site-b-routers

Step 1: Create setup keys for each site

Create one setup key per site with an auto-assigned group for that site's routing peers.

  1. SettingsSetup KeysCreate Setup Key
  2. For Site A: name "Site A Routing Peer", auto-assign group site-a-routers
  3. Repeat for Site B with group site-b-routers

Step 2: Install NetBird on the routing peers

On each site's routing peer:

curl -fsSL https://pkgs.netbird.io/install.sh | sh
sudo netbird up --setup-key YOUR_SETUP_KEY

Step 3: Create network routes

Add one route per site under Network RoutingRoutesAdd Route:

Site A:

  • Network range: 10.0.0.0/24
  • Routing Peer: the site-a-routers group (or a specific peer)
  • Distribution Groups: site-b-routers
  • Access Control Groups: site-a-routers (optional — see Access Control)
  • Network Identifier: site-a
  • Enable Masquerade under Additional Settings (recommended — see Advanced Configuration for the disabled case)

Site B: swap the values — 10.1.0.0/24, site-b-routers as routing peer, site-a-routers in distribution.

Step 4: Create bidirectional policies

Site-to-Site requires two policies — one for each direction:

site-a-routers → site-b-routers (All protocols)
site-b-routers → site-a-routers (All protocols)

Tighten by protocol/port if needed.

Step 5: Tell clientless devices about the remote subnet

Devices without NetBird need a static route pointing to the local routing peer.

Router-level (recommended) — add a static route on the site's router so all devices inherit it:

Destination: 10.1.0.0/24       # remote network
Gateway:     10.0.0.50         # local routing peer

Per-device fallback — if you can't touch the router, add the route on each device instead.

Windows (PowerShell as Administrator) — -p makes it persistent:

route -p add 10.1.0.0 mask 255.255.255.0 10.0.0.50

Linux — first test the route (this form disappears on the next reboot):

sudo ip route add 10.1.0.0/24 via 10.0.0.50

Once a peer at the other site is reachable, make it permanent. The method depends on which network manager the device uses — check with:

ls /etc/netplan/

Follow only one of the two methods below — the one that matches what ls showed. They're alternatives, not consecutive steps: if you see .yaml files use Netplan (most Ubuntu hosts); if the directory is empty or missing use systemd-networkd (Debian, minimal installs). Don't mix them — on Netplan hosts, systemd-networkd config you add by hand is silently ignored.

Both methods need your LAN interface name — find it with ip -br addr (look for the connection carrying the device's local IP, e.g. eth0 or ens18). Substitute it wherever the steps below show <IFACE>.

Option A — Netplan (you saw .yaml files) — open the file ls showed (e.g. 50-cloud-init.yaml) in a text editor. nano is the simplest; this command opens the file in it (run sudo apt install nano first if it's missing):

sudo nano /etc/netplan/50-cloud-init.yaml

Find your interface under ethernets: and add the route. If a routes: list is already there, add the - to: lines to it — don't create a second routes: key:

network:
  version: 2
  ethernets:
    <IFACE>:                         # your interface, from ip -br addr
      dhcp4: true                    # whatever was already here
      routes:                        # add this block (or reuse an existing routes: list)
        - to: 10.1.0.0/24            #   remote network
          via: 10.0.0.50             #   local routing peer

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

Option B — systemd-networkd (the /etc/netplan/ directory was empty) — create a drop-in for your interface. Replace both <IFACE> below with your interface name, then paste the block — it creates the file and reloads in one go:

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=10.1.0.0/24
Gateway=10.0.0.50
EOF
sudo networkctl reload

Step 6: Verify

From Site A, ping a device at Site B:

ping 10.1.0.100

Reverse from Site B to confirm both directions work.

Cloud routing peers

When the routing peer is a cloud instance, the VPC needs to allow it to forward traffic on behalf of other addresses:

  • AWS: Disable the source/destination check on the routing peer's ENI. Add a VPC route table entry with the remote CIDR as the destination and the routing peer's ENI as the target. Security groups must allow traffic from the routing peer.
  • GCP: Enable IP forwarding on the instance. Add a custom route in the VPC with the remote CIDR as the destination and the routing peer instance as the next hop. Firewall rules must allow traffic from the routing peer's internal IP.
  • Azure: Enable IP forwarding on the routing peer's NIC. Add a route table entry with the remote CIDR pointing at the routing peer. Network security groups must allow the traffic.

Next steps