Skip to content

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.74.4 for the management API, gRPC endpoint, signal, relay, metrics, health, and UDP STUN service
  • netbirdio/dashboard:v2.90.3 for the web dashboard
  • Secret-backed config.yaml, either generated from values or supplied through server.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 3478 Service 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. Keep 1 with 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 supplied config.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, or external.
  • database.external.engine: external postgres or mysql.
  • 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.auth.tokenSource, dashboard.auth.useAuth0: dashboard OIDC environment.
  • 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

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

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: server
    - host: dashboard.netbird.example.com
      paths:
        - path: /
          pathType: Prefix
          service: dashboard
  tls:
    - secretName: netbird-tls
      hosts:
        - netbird.example.com
        - dashboard.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

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.

Additional Resources