The architecture
- management server — the brain: stores peers, ACLs, manages config. Talks to clients over gRPC.
- signal server — coordinates WireGuard public-key exchange + NAT-traversal hints between peers.
- TURN server (coturn) — relay for peers behind symmetric NATs that can't NAT-traverse directly. Fallback only.
- dashboard — web UI for managing the network.
- clients — per-OS WireGuard wrapper that authenticates against your OIDC provider.
Install via docker compose
NetBird publishes a setup script that templates a full compose file:
curl -fsSL https://github.com/netbirdio/netbird/releases/latest/download/getting-started-with-zitadel.sh \
-o getting-started.sh
chmod +x getting-started.sh
# Required env: your domain + admin email
NETBIRD_DOMAIN=netbird.example.com \
NETBIRD_LETSENCRYPT_EMAIL=admin@example.com \
./getting-started.sh
The script generates a compose file with:
- NetBird management server
- Signal server
- TURN server (coturn)
- Dashboard (web UI)
- Zitadel as the bundled OIDC IdP (if you don't already have one)
- Caddy for TLS termination + reverse proxy
For BYO OIDC (Authentik / Keycloak / Auth0), skip the Zitadel container and configure the management server to use your existing IdP via env vars.
Using your existing OIDC IdP
# Authentik example - in NetBird's management.json
{
"HttpConfig": {
"AuthIssuer": "https://auth.example.com/application/o/netbird/",
"AuthAudience": "<client-id from Authentik>",
"AuthKeysLocation": "https://auth.example.com/application/o/netbird/jwks/",
"OIDCConfigEndpoint": "https://auth.example.com/application/o/netbird/.well-known/openid-configuration"
},
"IdpManagerConfig": {
"ManagerType": "authentik",
"ClientConfig": {
"Issuer": "https://auth.example.com/application/o/netbird/",
"TokenEndpoint": "...",
"ClientID": "<client-id>",
"ClientSecret": "<client-secret>"
}
}
}
Configure a NetBird application in Authentik (see Authentik tutorial) with the redirect URIs, copy client ID + secret, restart NetBird. Users log into the NetBird client via SSO; new peers join the mesh after auth.
Install a client
# Linux
sudo curl -fsSL https://pkgs.netbird.io/install.sh | sh
sudo apt install netbird
# macOS
brew install netbirdio/tap/netbird-ui
# Windows / iOS / Android
# Download from the NetBird site or app stores
# Connect (opens a browser to your OIDC IdP)
sudo netbird up --management-url https://netbird.example.com
# Verify
sudo netbird status
After login, the client requests a WireGuard public key, registers with NetBird's management server, and gets a peer ID + ACL group assignments. All other peers in the same network can now reach this one via WireGuard.
The dashboard
Browse to https://netbird.example.com. Login with SSO. The dashboard shows:
- All peers + their connection status + last-seen time
- Groups (per-user, per-team, or arbitrary labels)
- Access policies (which groups can reach which groups, on which ports)
- Activity log (who joined / left / failed auth)
- Setup keys (for headless / unattended joins)
Group-based ACLs
Tailscale-style ACLs are per-tag JSON. NetBird's ACLs are visual / declarative:
- Create groups: "engineers", "servers-prod", "servers-dev", "support"
- Assign peers to groups via OIDC claims (auto-mapped) or manually in the UI
- Write policies: "engineers can SSH (port 22) to servers-prod"; "support can reach servers-dev:80,443"
Policies are evaluated at the WireGuard layer; non-matching traffic is dropped. No per-peer firewalls to maintain.
Setup keys for headless joins
For CI / Kubernetes pods / IoT devices that can't do interactive OIDC:
# In the dashboard: Setup Keys → Create new
# Pick: reusable / one-time, validity window, assigned groups
# On the headless machine
sudo netbird up --management-url https://netbird.example.com \
--setup-key <key>
One-shot keys auto-expire on first use; reusable keys can onboard whole batches. Useful for Terraform-provisioned VMs that join the mesh automatically at boot.
Routing networks (exit nodes / subnet routes)
For "expose this LAN subnet to mesh peers":
# On a peer that's on the LAN you want to expose
sudo netbird routes add --network 10.0.5.0/24
# Or via the dashboard: configure a network route on that peer
# Other peers in matching ACL groups can now reach 10.0.5.0/24 via this peer
Combined with ACLs, this is the canonical "remote employees can reach office LAN" pattern.
NetBird vs alternatives
- Tailscale — commercial SaaS; polished UX; free tier limited. Use if you want zero-ops.
- Headscale — open-source Tailscale control-plane reimplementation. Drop-in for Tailscale clients. ACLs are Tailscale JSON. Smaller scope than NetBird (no built-in dashboard for general users).
- NetBird — self-hostable; OIDC-first; group-based ACLs; nicer admin UI than Headscale. Different client (not compatible with Tailscale clients).
- Nebula — Slack's mesh VPN. Lower-level; no central management plane; certificate-based. Different shape.
- OpenZiti — richer policy engine; less WireGuard-specific.
- Plain WireGuard (see that tutorial) — static config; no NAT traversal coordination; doesn't scale beyond ~10 peers without an orchestration layer.
When NetBird is the right pick
- Team of 5-500 + already has an OIDC IdP.
- Want self-hosted (not SaaS).
- Want a dashboard for ACL management, not Tailscale-JSON files.
- Mixed-OS fleet (NetBird clients exist for every major OS).
When it isn't
- For a 2-person homelab, plain WireGuard is fine.
- For a team already deep in Tailscale, switching to NetBird means re-onboarding everyone.
- For very-high-throughput links (multi-Gbps continuous), raw WireGuard without NetBird's management overhead may win on per-packet latency.