NetBird
Deploy NetBird on Kubernetes as a self-hosted WireGuard overlay control plane for device management, identity-aware access, and peer coordination.
Overview
The HelmForge NetBird chart follows the current upstream combined self-hosted architecture:
netbirdio/netbird-server:0.75.0for the management API, gRPC endpoint, signal, relay, metrics, health, and UDP STUN servicenetbirdio/dashboard:v2.90.3for the web dashboard- Secret-backed
config.yaml, either generated from values or supplied throughserver.config.existingSecret - HelmForge PostgreSQL subchart as the default production store
- persistent server data under
/var/lib/netbird - separate server and dashboard Services
- Ingress and Gateway API HTTPRoute support
- UDP
3478Service exposure for STUN - External Secrets Operator, NetworkPolicy, PDB, dual-stack service fields, and Helm tests
Configuration Reference
Server:
server.image.repository,server.image.tag,server.image.pullPolicy: official pinned NetBird server image.server.replicaCount: server pod count. Keep1with the default sqlite store.server.publicUrl: externally reachable URL for dashboard, API, gRPC, signal, and relay traffic.server.authSecret: shared server auth secret. Replace the default before production use.server.disableAnonymousMetrics,server.disableGeoliteUpdate: upstream telemetry and GeoLite controls.server.config.existingSecret,server.config.existingSecretKey,server.config.extraYaml: generated or externally suppliedconfig.yaml.server.auth.issuer,server.auth.localAuthDisabled,server.auth.signKeyRefreshEnabled: embedded or external OIDC settings.server.auth.owner.email,server.auth.owner.password: optional local owner bootstrap.server.store.engine,server.store.dsn,server.store.encryptionKey: legacy direct sqlite, postgres, or mysql store settings.server.service.type,server.service.httpPort,server.service.stunPort,server.service.metricsPort,server.service.healthPort.server.probes.enabled: opt-in health probes for environments where first boot completes within the configured timeout.
Database:
database.mode:auto,sqlite,postgresql, orexternal.database.external.engine: externalpostgresormysql.database.external.host,database.external.port,database.external.name,database.external.username.database.external.password,database.external.existingSecret,database.external.existingSecretPasswordKey,database.external.dsn.postgresql.enabled,postgresql.auth,postgresql.standalone.persistence: bundled HelmForge PostgreSQL store.
Dashboard:
dashboard.enabled: deploy the dashboard UI.dashboard.image.repository,dashboard.image.tag,dashboard.image.pullPolicy: official pinned dashboard image.dashboard.replicaCount: dashboard pod count.dashboard.auth.clientId,dashboard.auth.audience,dashboard.auth.supportedScopes: dashboard OIDC identity and scopes.dashboard.auth.redirectUri,dashboard.auth.silentRedirectUri: interactive and silent dashboard callbacks.dashboard.auth.tokenSource,dashboard.auth.useAuth0: dashboard token and provider mode.dashboard.securityContext: dashboard-specific runtime security context for upstream supervisord and nginx.dashboard.service.type,dashboard.service.port,dashboard.service.annotations,dashboard.service.ipFamilyPolicy,dashboard.service.ipFamilies.
Shared operations:
imagePullSecrets,commonLabels,nameOverride,fullnameOverride.persistence.enabled,persistence.size,persistence.storageClass,persistence.accessModes,persistence.existingClaim,persistence.mountPath.serviceAccount.create,serviceAccount.name,serviceAccount.annotations,serviceAccount.automountServiceAccountToken.ingress.enabled,ingress.ingressClassName,ingress.annotations,ingress.hosts,ingress.tls.gatewayAPI.enabled,gatewayAPI.httpRoutes.externalSecrets.enabled,externalSecrets.items.pdb.enabled,pdb.minAvailable.networkPolicy.enabled,networkPolicy.ingressFrom,networkPolicy.extraEgress.resources,podSecurityContext,securityContext,nodeSelector,tolerations,affinity.topologySpreadConstraints,priorityClassName,terminationGracePeriodSeconds.podLabels,podAnnotations,extraVolumes,extraVolumeMounts,extraManifests.
Installation
helm repo add helmforge https://repo.helmforge.dev
helm repo update
helm install netbird helmforge/netbird --namespace netbird --create-namespace
OCI install:
helm install netbird oci://ghcr.io/helmforgedev/helm/netbird --namespace netbird --create-namespace
Production Example
The embedded identity provider expects dashboard and server callbacks on the
same public hostname. The defaults use the netbird-dashboard client and the
/nb-auth and /nb-silent-auth callback paths:
server:
publicUrl: https://netbird.example.com
authSecret: replace-with-a-strong-random-secret
auth:
issuer: https://netbird.example.com/oauth2
store:
encryptionKey: replace-with-a-persistent-encryption-key
dashboard:
auth:
clientId: netbird-dashboard
audience: netbird-dashboard
supportedScopes: openid profile email groups
redirectUri: /nb-auth
silentRedirectUri: /nb-silent-auth
database:
mode: postgresql
postgresql:
enabled: true
auth:
database: netbird
username: netbird
persistence:
enabled: true
size: 20Gi
ingress:
enabled: true
ingressClassName: nginx
hosts:
- host: netbird.example.com
paths:
- path: /
pathType: Prefix
service: dashboard
- path: /api
pathType: Prefix
service: server
tls:
- secretName: netbird-tls
hosts:
- netbird.example.com
Expose UDP 3478 for STUN with a LoadBalancer Service, Gateway implementation, or infrastructure-specific UDP listener. Kubernetes Ingress does not handle UDP.
Prefer separate hosts for production ingress: route the NetBird backend host to the server service and the dashboard host to the dashboard service. If you use one host with path-based routing, send /api, /oauth2, /relay, /ws-proxy/management, /ws-proxy/signal, /signalexchange.SignalExchange/, /management.ManagementService/, and /management.ProxyService/ to the server service before any dashboard route. Configure the ingress controller or gateway to preserve HTTP/2 or h2c behavior for gRPC routes.
External Secrets
Use External Secrets for a full upstream config.yaml or sensitive bootstrap data:
server:
config:
existingSecret: netbird-config
externalSecrets:
enabled: true
items:
- name: config
spec:
secretStoreRef:
kind: ClusterSecretStore
name: production
target:
name: netbird-config
creationPolicy: Owner
data:
- secretKey: config.yaml
remoteRef:
key: apps/netbird/config.yaml
Scaling
The v1 chart defaults to PostgreSQL through the HelmForge PostgreSQL subchart.
Use database.mode=external for a managed PostgreSQL or MySQL database. Use
database.mode=sqlite with postgresql.enabled=false only for lab or small
single-replica installs.
Even with PostgreSQL or MySQL, scaling server.replicaCount above 1 requires a complete HA topology for the combined server components. Plan signal, relay, and STUN exposure with load-balancer affinity and protocol-aware routing before enabling multiple server replicas. If that topology is not in place, keep server.replicaCount: 1.
Upgrade Notes
NetBird 0.75.0 improves the combined server’s management, relay, and
self-hosting paths. It adds account settings for dashboard and agent-network
features, source and destination traffic filters, trusted-proxy handling for
relay client addresses, and a unified admin CLI. The redesigned desktop client
announced in this upstream release is distributed separately and is not part of
this server chart.
No chart value migration is required when upgrading from 0.74.7. Back up the
configured database and /var/lib/netbird, then apply the new chart defaults
while preserving your explicit overrides:
helm repo update helmforge
helm upgrade netbird helmforge/netbird \
--version 1.0.3 \
--namespace netbird \
--reset-then-reuse-values
Using --reuse-values alone retains the previous image tag and does not deploy
NetBird 0.75.0.
This v1 hardening release changes the default store from sqlite to PostgreSQL subchart mode. Existing sqlite installs that want to keep sqlite should set:
database:
mode: sqlite
postgresql:
enabled: false
To migrate production data from sqlite to PostgreSQL, follow the upstream
NetBird PostgreSQL migration guidance and back up /var/lib/netbird before
switching modes.
Dashboard replicas can scale independently when the backing server and ingress layer are ready for the traffic.