A complete guide to deploying your own Zero Trust network using NetBird and Authentik as identity provider. No port forwarding, no VPN concentrator, no exposed attack surface — just encrypted WireGuard tunnels between your machines, anywhere in the world.
How NetBird works
NetBird separates control plane from data plane. The VPS runs the control plane — it never sees your decrypted traffic. Data travels directly between peers via encrypted WireGuard, or relayed through coturn when direct connection is impossible (symmetric NAT). In both cases, traffic remains end-to-end encrypted.
Reference architecture
A VPS (Hetzner) hosts NetBird and Authentik. An OPNsense firewall on-site acts as routing peer, giving all authenticated peers access to every internal subnet — without NetBird clients on the machines themselves.
| Host | Role | Address | NetBird client |
|---|---|---|---|
| VPS (Hetzner) | NetBird management + Authentik sidecar | Public IP | Authentik container has one |
| OPNsense | Firewall + Routing Peer (all VLANs) | 192.168.1.1 / .10.1 / .20.1 | Yes — official plugin |
| Raspberry Pi | Nextcloud, Pi-hole | 192.168.10.10 | Optional |
| NAS | Storage (TrueNAS) | 192.168.10.20 | Optional |
| Desktop | Work machine | 192.168.1.50 | Yes |
| Laptop | Mobile peer — access from anywhere | Variable (DHCP) | Yes |
1. Prerequisites & DNS
VPS — NetBird only
1 vCPU · 2 GB RAM · 20 GB SSD
Ubuntu 22.04 LTS — Hetzner CX22
VPS — NetBird + Authentik
2 vCPU · 4 GB RAM · 20 GB SSD
Authentik alone needs ~2 GB RAM.
Firewall ports
| Port | Proto | Purpose | Note |
|---|---|---|---|
80 | TCP | HTTP → HTTPS redirect | Required for Let’s Encrypt TLS challenge |
443 | TCP | Everything — Dashboard, API, Signal | All proxied by Traefik |
3478 | UDP | STUN / TURN | coturn NAT traversal |
49152–65535 | UDP | TURN relay range | coturn relay ports |
DNS records
| Type | Name | Value | Note |
|---|---|---|---|
A | netbird | YOUR.VPS.IP | Main NetBird domain |
CNAME | *.netbird | netbird.your-domain.com | Wildcard — required for proxy subdomains |
cloud.netbird.your-domain.com resolve to the VPS.VPS dependencies
# Install Docker
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# Required tools
sudo apt install -y jq curl
2. Install NetBird
The official install script handles everything: generates a complete docker-compose.yml, sets up Traefik with automatic TLS, configures coturn, and optionally enables the built-in reverse proxy.
Run the official install script
curl -fsSL https://github.com/netbirdio/netbird/releases/latest/download/getting-started.sh | bash
When prompted, enter your domain name — e.g. netbird.your-domain.com.
Choose Traefik as reverse proxy
Press **Enter** to accept the default `[0] Traefik`. Traefik is bundled in the compose file and handles Let's Encrypt certificates automatically.Enable the NetBird Proxy service
Do you want to enable the NetBird Proxy service? [y/N]: y
Enables the Reverse Proxy feature in the dashboard, used later to expose Authentik and internal apps without any direct port exposure.
Verify all containers are running
cd /opt/netbird
docker compose ps
# Expected: management, signal, relay, coturn, traefik, proxy, dashboard
Create the initial local admin account
Open `https://netbird.your-domain.com/setup` — create an admin account with email + password. This temporary account will be replaced by Authentik later./setup page is only available when no users exist.Generated files
| File | Purpose |
|---|---|
docker-compose.yml | Full stack: management, signal, relay, coturn, traefik, dashboard, proxy |
config.yaml | Combined server config |
dashboard.env | Dashboard container environment variables |
proxy.env | Proxy container config |
3. Deploy Authentik as a sidecar
Authentik runs in its own Docker stack on the same VPS, with a NetBird client container added to it. That client container registers as a peer and acts as routing peer for the Authentik Docker subnet. The NetBird reverse proxy then exposes Authentik — no ports opened on the VPS.
Create the Authentik directory
mkdir /opt/authentik && cd /opt/authentik
curl -fsSL https://goauthentik.io/docker-compose.yml -o docker-compose.yml
Generate credentials
# PostgreSQL password
echo "PG_PASS=$(openssl rand -base64 36 | tr -d '=+/')" >> .env
# Authentik secret key — min 50 characters required
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -hex 32)" >> .env
cat .env # verify both values are present
Create a Setup Key for the Authentik sidecar
NetBird dashboard → **Setup Keys → Add Setup Key**:| Field | Value |
|---|---|
| Name | vps-services |
| Type | Reusable |
| Expiry | 90 days |
Copy the generated key — you’ll use it in the next step.
Add the NetBird client sidecar to docker-compose.yml
Add the network stanza to `postgresql`, `server`, and `worker` services:networks:
authentik-net:
ipv4_address: 172.20.0.10 # .10 server / .20 postgres / .30 worker
Then append the sidecar service and top-level network definition:
netbird:
image: netbirdio/netbird:latest
cap_add: [NET_ADMIN, SYS_ADMIN]
sysctls:
- net.ipv6.conf.all.disable_ipv6=0
environment:
- NB_SETUP_KEY=<paste-setup-key-here>
- NB_MANAGEMENT_URL=https://netbird.your-domain.com
restart: unless-stopped
networks:
authentik-net:
ipv4_address: 172.20.0.2
networks:
authentik-net:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/24
172.20.0.10:9000) to forward traffic correctly.Start Authentik
docker compose up -d
docker compose logs -f server | grep -i startup
After ~1 minute, the vps-services peer should appear in the NetBird dashboard under Peers.
Complete Authentik initial setup
Temporarily open port `9000` on your VPS firewall, then navigate to:http://YOUR.VPS.IP:9000/if/flow/initial-setup/
Create the Authentik admin account. Once done, close port 9000 immediately.
4. Expose Authentik via NetBird Reverse Proxy
Before linking Authentik as an IdP, it needs to be accessible via a stable HTTPS URL. The NetBird reverse proxy handles this — no direct internet exposure, TLS automatic via Traefik.
Create the VPS Services network
NetBird dashboard → **Networks → Add Network**:| Field | Value |
|---|---|
| Name | VPS Services |
| Resource | Add subnet 172.20.0.0/24 |
| Routing Peer | Select vps-services |
Add Authentik as a Reverse Proxy service
Dashboard → **Reverse Proxy → Services → Add HTTP/S Service**:| Tab | Field | Value |
|---|---|---|
| Service | Subdomain | auth → full URL: auth.netbird.your-domain.com |
| Service | Proxy Peer | vps-services |
| Authentication | Auth method | None — Authentik manages its own auth |
| Advanced | Pass Host Header | Enable |
Add Target
| Field | Value |
|---|---|
| Protocol | http:// |
| IP | 172.20.0.10 |
| Port | 9000 |
Verify and close port 9000
Navigate to `https://auth.netbird.your-domain.com` — you should see the Authentik login page over HTTPS with a valid certificate. Then **close port 9000** on the VPS firewall permanently.5. Configure Authentik as NetBird IdP
A four-step OIDC handshake: create the provider in Authentik, create the application, get the redirect URL from NetBird, paste it back into Authentik.
Create the OAuth2/OpenID provider in Authentik
Authentik → **Admin Interface → Applications → Providers → Create**:| Field | Value |
|---|---|
| Type | OAuth2/OpenID Provider |
| Name | NetBird |
| Authorization flow | default-provider-authorization-explicit-consent |
| Client type | Confidential |
| Redirect URIs | Leave empty for now |
| Signing Key | Select any cert (authentik Self-signed Certificate) |
Note the Client ID and Client Secret from the provider detail page.
Create the Authentik application
| Field | Value |
|---|---|
| Name | NetBird |
| Slug | netbird |
| Provider | Select the NetBird provider |
Add Authentik as IdP in NetBird — copy the Redirect URL
NetBird → **Settings → Identity Providers → Add Identity Provider**:| Field | Value |
|---|---|
| Type | Generic OIDC |
| Client ID | From Authentik step 1 |
| Client Secret | From Authentik step 1 |
| Issuer | https://auth.netbird.your-domain.com/application/o/netbird/ |
Copy the Redirect URL that NetBird generates — do not click “Add Provider” yet.
Paste the Redirect URL back into Authentik
Authentik → **Providers → NetBird → Edit** → under **Redirect URIs/Origins** → Add → mode: **Strict** → paste the URL → Update.Complete the NetBird IdP configuration
Return to the NetBird tab and click **Add Provider**. Authentik is now configured as the identity provider.6. User management & ownership transfer
Test the Authentik login flow
Open a private browser window → navigate to `https://netbird.your-domain.com`. Click the **Authentik** button, authenticate with your Authentik credentials.Approve the pending user
Switch back to the local admin account → **Team → Users** → approve the pending Authentik user.Transfer ownership
In **Team → Users**, find the Authentik-managed user and change their role to **Owner**.Verify, then delete the local account
Log out → log back in using Authentik → confirm full admin access. Only then delete the original local user.7. JWT group sync
NetBird can automatically mirror Authentik group memberships into NetBird groups via the JWT token’s groups claim. Adding a user to a group in Authentik instantly grants them the corresponding NetBird access.
Enable "Include claims in id_token" in the Authentik provider
Authentik → **Providers → NetBird → Edit** → under **Advanced protocol settings** → enable **Include claims in id_token**. Ensure the `profile` and `groups` scopes are listed.Enable JWT group sync in NetBird
NetBird → **Settings → Groups**:| Field | Value |
|---|---|
| JWT group sync | Enable |
| JWT claim | groups |
| JWT allow groups | Optional — restrict to specific groups only |
8. Peers & Setup Keys
A peer is any machine with the NetBird client installed. Once registered, each peer gets a stable IP in the 100.64.0.0/10 CGNAT range and communicates via encrypted WireGuard tunnels.
Install the client
# Linux — Debian / Ubuntu
curl -fsSL https://pkgs.netbird.io/install.sh | sh
netbird up --management-url https://netbird.your-domain.com
# OPNsense — official plugin
# System → Firmware → Plugins → search "netbird" → install os-netbird
# Then: VPN → NetBird → Settings → Management URL: https://netbird.your-domain.com
Setup Keys
One-time key
Used once, then consumed. Ideal for manually registering a specific machine.
Reusable key
Multiple uses until expiry. Ideal for Ansible, Terraform, or Docker-based deployments.
# Register a peer non-interactively
netbird up \
--management-url https://netbird.your-domain.com \
--setup-key XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
9. Networks & Resources
A Network is NetBird’s top-level logical grouping. It contains Resources (subnets), one or more Routing Peers (gateways), and optionally Services (reverse proxy endpoints). Access Policies control which peer groups can reach the Network.
| Network Routes (legacy) | Networks (recommended) | |
|---|---|---|
| Granularity | One CIDR at a time | Full site — multiple CIDRs grouped |
| Reverse Proxy | Not integrated | Integrated as “Services” |
| Access Control | Per route | Per Network — covers all resources |
| Best for | 1–2 simple subnets | Any multi-subnet site |
10. Routing Peers
A routing peer announces one or more subnets to the mesh. Remote peers send traffic for those subnets to the routing peer, which forwards it natively. OPNsense is the ideal routing peer for a homelab — it already routes all VLANs natively.
The golden rule: the routing peer must be the machine that can natively reach the subnet it announces — ideally the default gateway of that subnet.
11. Reverse Proxy — clientless ZTNA
The Reverse Proxy exposes an internal app via a public HTTPS URL with SSO auth, without the end user needing to install the NetBird client. The proxy peer is the machine that makes the TCP connection — it must reach the destination natively.
Configure a service
Add HTTP/S Service
| Field | Value | Notes |
|---|---|---|
| Subdomain | cloud | Full URL: cloud.netbird.your-domain.com |
| Proxy Peer | opnsense | The machine making the TCP connection |
Authentication tab → Add SSO
Select Authentik. Users must authenticate via Authentik + MFA before the request is forwarded.Add Target — always select Resource, not Peer
| Field | Value | Notes |
|---|---|---|
| Type | Resource | Allows entering an internal LAN IP |
| Resource | VLAN 10 Services | |
| Protocol | http:// | |
| IP | 192.168.10.10 | |
| Port | 80 | |
| Skip TLS | Off | Enable only for self-signed certs (e.g. Proxmox :8006) |
12. Access Control Policies
Policies define which peer groups can reach which Networks or Resources. The default is deny all — without a policy, no peer can access any Network.
13. Split DNS
NetBird can push nameserver configuration to peers so internal hostnames resolve while connected to the mesh.
DNS → Add Nameserver
| Field | Value |
|---|---|
| Nameserver IP | 192.168.1.1 — OPNsense / Unbound |
| Domain | home (or lan, internal) |
| Groups | admins, family |
Configure host overrides in OPNsense Unbound
nas.home → 192.168.10.20
nextcloud.home → 192.168.10.10
opnsense.home → 192.168.1.1
Test from any peer
nslookup nas.home # → 192.168.10.20
nslookup nextcloud.home # → 192.168.10.10
nslookup google.com # → still resolves via public DNS
14. OPNsense firewall rules
This is the most commonly missed step. OPNsense blocks all inter-interface traffic by default. Without these rules, routing peer traffic will be silently dropped — even though everything in NetBird is correctly configured.
Rule 1 — Allow NetBird peers to reach your subnets
Firewall → Rules → [WireGuard / NetBird interface] → Add rule:
| Field | Value |
|---|---|
| Action | Pass |
| Interface | WireGuard / NetBird (wg0) |
| Protocol | Any |
| Source | 100.64.0.0/10 — NetBird CGNAT range |
| Destination | 192.168.0.0/16 — your homelab subnets |
Rule 2 — Exclude NetBird traffic from NAT masquerade
Firewall → NAT → Outbound → switch to Hybrid mode → add a No-NAT rule:
| Field | Value |
|---|---|
| Interface | LAN (and each VLAN interface) |
| Source | 100.64.0.0/10 |
| Destination | Your homelab subnets |
| Translation | No NAT |
15. Use cases
Full admin access from anywhere
netbird up
# → Authentik login + MFA
# → full access to 192.168.1.0/24, 192.168.10.0/24, 192.168.20.0/24
ssh user@192.168.10.10 # Raspberry Pi
ssh user@192.168.10.20 # NAS shell
Share Nextcloud with a friend — no client needed
Create a user in Authentik → assign to group guests (synced via JWT) → send them https://cloud.netbird.your-domain.com. They open a browser, log in via Authentik, complete MFA, and access Nextcloud. Nothing installed on their side.
Remote access for family members
Family members install the NetBird client on their phones → authenticate via Authentik → JWT sync assigns them to the family group → they get access to LAN + VLAN 10 only, not the management VLAN or IoT network.