geek.sonde.uk updated:
Networking VPN Linux

WireGuard to Netbird Migration

Migrate a multi-cluster WireGuard setup to a Netbird mesh overlay network using per-cluster maintenance VMs as subnet routers — without installing any agent on every individual host.

~20 min read Linux / Windows Difficulty: Intermediate
01

Why migrate to Netbird

WireGuard is a fantastic kernel-level VPN, but managing it across multiple clusters quickly becomes painful: you write config files by hand, distribute keys out-of-band, maintain per-host wg0.conf updates, and have no central view of who is connected to what. Netbird wraps WireGuard in an automated mesh control plane that solves all of this.

Key advantages over raw WireGuard:

  • Zero-touch mesh — peers register automatically; no manual key exchange.
  • NAT traversal built in — direct peer-to-peer tunnels even behind strict NAT, with TURN relay as fallback.
  • Subnet routing — one agent on a gateway VM can expose an entire cluster subnet; other hosts need no agent at all.
  • Central ACL dashboard — fine-grained policy (which peer can reach which network) without SSHing into every machine.
  • Self-hostable — management, signal and relay servers can all run on your own infrastructure.
  • No admin privileges required on clients — the agent runs in userspace on both Linux and Windows.

The main trade-offs to be aware of:

  • The management server is a new dependency — if it goes down, existing tunnels stay up but you can't change policy or onboard new peers.
  • Self-hosting adds operational overhead (management + signal + TURN).
  • Slightly more latency when the direct path fails and traffic is relayed via TURN.
ℹ️
WireGuard is still underneath

Netbird uses WireGuard as its data-plane transport. All the performance characteristics of WireGuard (kernel bypass, ChaCha20 encryption, minimal attack surface) are preserved.

02

Recommended architecture

The recommended pattern for a 3-cluster environment is the subnet router gateway model. You install the Netbird agent only on the maintenance VM of each cluster. That VM advertises the cluster's internal subnet into the Netbird overlay network. All other hosts in the cluster remain untouched — they simply route traffic through the maintenance VM as they would for any other gateway.

The components involved are:

  • Netbird Management Server — stores peer config, issues credentials, evaluates ACL policy. Can be self-hosted (Docker Compose) or use app.netbird.io.
  • Signal Server — facilitates the initial peer-to-peer hole-punching handshake. Bundled with the management server in self-hosted mode.
  • TURN/Relay Server — relays traffic when direct P2P is not possible (e.g. symmetric NAT). Based on Coturn.
  • Maintenance VM (×3) — one per cluster; runs the Netbird agent and is configured as a subnet router for that cluster's internal CIDR.

The three maintenance VMs form a full-mesh of WireGuard tunnels between each other, coordinated by the management server. Traffic from Host A in Cluster 1 destined for Host B in Cluster 2 travels: Host A → Maintenance VM 1 (WireGuard) → Maintenance VM 2 → Host B. Fully transparent, no changes on Host A or Host B.

⚠️
IP forwarding required

The maintenance VM must have kernel IP forwarding enabled (net.ipv4.ip_forward=1) for subnet routing to work. Netbird will remind you if it is missing.

03

Prerequisites

Before you begin, make sure you have the following:

  • 3 clusters, each with a Linux maintenance VM (Ubuntu 20.04+ or any systemd-based distro recommended).
  • Outbound internet access from each maintenance VM (ports 443 TCP and 3478/49152-65535 UDP for TURN).
  • A dedicated VM or server to host the Netbird management stack (if self-hosting) — 1 vCPU / 1 GB RAM is sufficient for small deployments.
  • Docker and Docker Compose installed on the management server.
  • sudo / root access on the maintenance VMs for the initial agent installation.
  • The internal subnet CIDR of each cluster noted down (e.g. 10.1.0.0/24, 10.2.0.0/24, 10.3.0.0/24).
ℹ️
Skipping self-hosting

If you don't need full on-premise control, you can skip sections 4 and 5 and use app.netbird.io (free up to 5 peers). Jump straight to section 6 in that case.

04

Deploy the management server (self-hosted)

Netbird provides an official Docker Compose bundle that brings up the management API, the signal server, and a Caddy reverse proxy with automatic TLS. Run the following on your dedicated management VM.

bash
# Download the setup script
curl -fsSL https://github.com/netbirdio/netbird/releases/latest/download/getting-started-with-zitadel.sh \
  | bash

The script will prompt you for your domain name and will configure Caddy, Zitadel (the built-in identity provider), and the Netbird management service. Once complete, the dashboard will be reachable at https://<your-domain>.

bash
# Verify all containers are running
docker compose ps

You should see the following services in running state: management, signal, caddy, and zitadel.

ℹ️
TURN server

For environments where maintenance VMs sit behind symmetric NAT, also deploy a Coturn server and reference it in the management server's management.json under the TURNConfig block. See the official Netbird docs for the exact config keys.

05

Create a setup key

A setup key is a one-time (or reusable) token that authorises a new peer to join your network. Create one setup key per cluster so you can track which peers belong to which cluster.

  1. Open the Netbird dashboard and navigate to Setup Keys.
  2. Click Create Setup Key.
  3. Give it a descriptive name (e.g. cluster-1-gateway).
  4. Set the key type to Reusable if you plan to re-enrol the same VM (e.g. after a rebuild).
  5. Copy the generated key — you will use it in the next section.
⚠️
Treat setup keys as secrets

Anyone with a valid setup key can register a peer into your network. Rotate or expire keys after use if your security policy requires it.

06

Install the Netbird agent on each maintenance VM

Repeat these steps on each of the three maintenance VMs. The agent will auto-register with the management server using the setup key and establish WireGuard tunnels to the other peers.

bash
# Add the Netbird repository and install the agent
curl -fsSL https://pkgs.netbird.io/install.sh | sh

Once installed, bring the agent up and point it at your management server:

bash
# Replace the placeholders with your actual values
netbird up \
  --management-url https://<your-management-domain> \
  --setup-key <your-setup-key>

If you are using the hosted app.netbird.io service, omit the --management-url flag — the agent defaults to the cloud endpoint.

bash
# Verify the agent is connected
netbird status

You should see the peer listed as Connected and an assigned Netbird IP in the 100.64.0.0/10 range (or your custom range).

Peer registered

The maintenance VM will also appear in the Netbird dashboard under Peers within a few seconds of running netbird up.

07

Enable subnet routing on each maintenance VM

This is the key step that lets each maintenance VM act as a gateway for its entire cluster subnet. Hosts inside the cluster do not need to run the Netbird agent — they will reach other clusters through the maintenance VM.

First, enable IP forwarding at the OS level:

bash
# Enable IP forwarding (persistent)
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

Then advertise the cluster subnet as a route via the Netbird CLI or the dashboard.

Via CLI (on each maintenance VM, substituting the correct CIDR):

bash
# Cluster 1 — maintenance VM 1
netbird routes add \
  --network 10.1.0.0/24 \
  --description "Cluster 1 internal subnet"

# Cluster 2 — maintenance VM 2
netbird routes add \
  --network 10.2.0.0/24 \
  --description "Cluster 2 internal subnet"

# Cluster 3 — maintenance VM 3
netbird routes add \
  --network 10.3.0.0/24 \
  --description "Cluster 3 internal subnet"

Via dashboard: navigate to Network RoutesAdd Route, set the CIDR, and select the corresponding maintenance VM as the routing peer.

ℹ️
Default gateway on cluster hosts

For hosts inside the cluster to route inter-cluster traffic correctly, their default gateway (or a static route) must point to the maintenance VM. This is usually already the case if the maintenance VM is the cluster gateway — no change needed.

08

Define access control policy

By default, Netbird creates an allow all policy between peers in the same account. You can restrict this from the dashboard under Access Control → Policies.

A typical setup for 3 isolated clusters that need selective cross-cluster access:

  • Create a Group per cluster (e.g. cluster-1, cluster-2, cluster-3) and assign the respective maintenance VM to each group.
  • Create policies between the groups you want to allow. For example, to allow Cluster 1 and Cluster 2 to communicate bidirectionally, create a policy with source cluster-1 and destination cluster-2, protocol All.
  • Leave Cluster 3 out of that policy if it should remain isolated.
ℹ️
Policies apply to the Netbird overlay, not the cluster subnet

ACL policies govern which Netbird peers (i.e. maintenance VMs) can communicate. Traffic from cluster hosts travels through those VMs, so the policy effectively controls cluster-to-cluster reachability.

09

Migration strategy from WireGuard

You don't need to cut over all three clusters at once. A safe rolling migration looks like this:

  1. Stand up Netbird in parallel — install the agent on Cluster 1's maintenance VM while WireGuard is still running. The two can coexist since Netbird uses a different network interface (wt0) and a different subnet.
  2. Test Cluster 1 in isolation — verify that the Netbird overlay is reachable, the route is advertised correctly, and internal hosts can reach the management server via the maintenance VM.
  3. Enrol Cluster 2 and Cluster 3 — repeat the agent installation and subnet route steps on the other two maintenance VMs.
  4. Validate cross-cluster connectivity — ping a host in Cluster 2 from a host in Cluster 1 before touching WireGuard.
  5. Remove WireGuard — once validated, bring down the WireGuard interfaces cluster by cluster and remove the old config files.
bash
# Bring down WireGuard on a host (after Netbird is validated)
sudo wg-quick down wg0
sudo systemctl disable wg-quick@wg0
⚠️
Keep WireGuard configs as backup

Archive your /etc/wireguard/ directory before removing anything. If you need to roll back quickly, a wg-quick up wg0 will restore connectivity instantly.

10

Verification

Run the following checks to confirm the migration is complete and healthy.

Check agent status on each maintenance VM:

bash
netbird status --detail

Expected output: all three maintenance VMs listed as peers with status Connected and a valid direct or relayed connection type.

Test cross-cluster reachability from a regular host:

bash
# From a host in Cluster 1, ping a host in Cluster 2
ping -c 4 10.2.0.50

# Trace the path — first hop should be the maintenance VM
traceroute 10.2.0.50

Verify routes are advertised:

bash
netbird routes list
Migration complete

If cross-cluster pings succeed and all three peers show Connected in netbird status, your migration from WireGuard to Netbird is complete.

ℹ️
Connection type: relayed vs direct

If netbird status --detail shows relayed instead of direct between two maintenance VMs, the peers cannot hole-punch through their respective NATs. Deploy a Coturn TURN server and configure it in the management server's settings to fix this.