Skip to content

Latest commit

 

History

History
529 lines (424 loc) · 24.7 KB

File metadata and controls

529 lines (424 loc) · 24.7 KB

import {Note, Warning} from "@/components/mdx"; import {Properties, Property} from "@/components/mdx";

Self-Hosted Deployment Configuration Files Reference

This page provides a comprehensive reference for all configuration files used when self-hosting NetBird with the getting-started.sh deployment method. Understanding these files helps you customize your deployment, troubleshoot issues, and integrate with existing infrastructure.

Configuration files are **generated automatically** by the `getting-started.sh` script. Modifying files directly is only necessary for advanced customization after initial setup.

Overview

A standard NetBird self-hosted deployment uses the following configuration files:

File Purpose
docker-compose.yml Defines all services (dashboard, netbird-server, optionally traefik), their Docker images, port mappings, volumes, and startup order. Structure varies depending on the reverse proxy option chosen during setup.
config.yaml Unified server configuration for the combined NetBird server: listen addresses, STUN, relay authentication, embedded IdP, and database settings. Replaces the old management.json and relay.env files.
dashboard.env Configures the web dashboard including API endpoints, OAuth2/OIDC settings, and optional SSL settings for standalone deployments without a reverse proxy.

File Locations

After running the installation script, configuration files are located in the directory where you ran the script (typically ~/netbird/ or the current working directory):

./
├── docker-compose.yml
├── config.yaml
├── dashboard.env
└── nginx-netbird.conf      # Only when using Nginx reverse proxy
    npm-advanced-config.txt  # Only when using Nginx Proxy Manager
    caddyfile-netbird.txt    # Only when using Caddy reverse proxy

docker-compose.yml

The Docker Compose file defines all NetBird services, their dependencies, networking, and volumes.

Services Overview

Service Image Internal Port External (Exposed) Description
traefik traefik:v3.6 80, 443 80:80, 443:443 Handles TLS termination via Let's Encrypt and routes incoming HTTPS requests to the appropriate NetBird services. Only included when using the built-in Traefik option (option 0).
dashboard netbirdio/dashboard 80 8080:80 The web-based management console where administrators configure networks, manage peers, create access policies, and view activity logs. Includes an embedded nginx server for serving the UI.
netbird-server netbirdio/netbird-server 80, 3478/udp 8081:80, 3478:3478/udp Combined server that includes management, signal, relay, and embedded STUN in a single container. Configured via config.yaml.
**Internal vs External ports**: Internal ports are what services listen on inside their containers. External (Exposed) ports show the host-to-container mapping used when running without the built-in Traefik (e.g., with Nginx or other reverse proxies). When using the default Traefik deployment, only Traefik exposes ports externally. The `netbird-server` container combines what were previously separate management, signal, relay, and STUN containers into a single service. This simplifies the deployment architecture while maintaining the same functionality.

Traefik Service

The Traefik service is only present when using the built-in reverse proxy option (option 0 during setup). It handles automatic TLS certificate provisioning via Let's Encrypt and routes requests to the correct backend services.

traefik:
  image: traefik:v3.6
  container_name: netbird-traefik
  restart: unless-stopped
  networks: [netbird]
  command:
    - "--providers.docker=true"
    - "--providers.docker.exposedbydefault=false"
    - "--providers.docker.network=netbird"
    - "--entrypoints.web.address=:80"
    - "--entrypoints.websecure.address=:443"
    - "--entrypoints.websecure.transport.respondingTimeouts.readTimeout=0"
    - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
    - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
    - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
    - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
  ports:
    - '443:443'
    - '80:80'
  volumes:
    - /var/run/docker.sock:/var/run/docker.sock:ro
    - netbird_traefik_letsencrypt:/letsencrypt
  logging:
    driver: "json-file"
    options:
      max-size: "500m"
      max-file: "2"
The `readTimeout=0` setting on the websecure entrypoint disables read timeouts, which is required for long-lived gRPC and WebSocket connections used by the signal and relay services.

Dashboard Service

With built-in Traefik (default):

dashboard:
  image: netbirdio/dashboard:latest
  container_name: netbird-dashboard
  restart: unless-stopped
  networks: [netbird]
  env_file:
    - ./dashboard.env
  labels:
    - traefik.enable=true
    - traefik.http.routers.netbird-dashboard.rule=Host(`netbird.example.com`)
    - traefik.http.routers.netbird-dashboard.entrypoints=websecure
    - traefik.http.routers.netbird-dashboard.tls=true
    - traefik.http.routers.netbird-dashboard.tls.certresolver=letsencrypt
    - traefik.http.routers.netbird-dashboard.priority=1
    - traefik.http.services.netbird-dashboard.loadbalancer.server.port=80
  logging:
    driver: "json-file"
    options:
      max-size: "500m"
      max-file: "2"
The dashboard service is configured via the `dashboard.env` file. See the [dashboard.env section](#dashboardenv) for the full list of environment variables. When using the built-in Traefik, no ports are exposed directly from the dashboard container; Traefik routes traffic to it internally via Docker labels.

NetBird Server Service

The combined server runs management, signal, relay, and STUN in a single container, configured by config.yaml.

With built-in Traefik (default):

netbird-server:
  image: netbirdio/netbird-server:latest
  container_name: netbird-server
  restart: unless-stopped
  networks: [netbird]
  ports:
    - '3478:3478/udp'
  volumes:
    - netbird_data:/var/lib/netbird
    - ./config.yaml:/etc/netbird/config.yaml
  command: ["--config", "/etc/netbird/config.yaml"]
  labels:
    - traefik.enable=true
    # gRPC router (needs h2c backend for HTTP/2 cleartext)
    # The /management.ProxyService/ path is only required if the reverse proxy
    # container (netbirdio/reverse-proxy) connects through Traefik — i.e., it
    # runs on a separate host or a different Docker network. If the proxy is on
    # the same Docker network as netbird-server, it connects directly and this
    # path prefix can be omitted.
    - traefik.http.routers.netbird-grpc.rule=Host(`netbird.example.com`) && (PathPrefix(`/signalexchange.SignalExchange/`) || PathPrefix(`/management.ManagementService/`) || PathPrefix(`/management.ProxyService/`))
    - traefik.http.routers.netbird-grpc.entrypoints=websecure
    - traefik.http.routers.netbird-grpc.tls=true
    - traefik.http.routers.netbird-grpc.tls.certresolver=letsencrypt
    - traefik.http.routers.netbird-grpc.service=netbird-server-h2c
    # Backend router (relay, WebSocket, API, OAuth2)
    - traefik.http.routers.netbird-backend.rule=Host(`netbird.example.com`) && (PathPrefix(`/relay`) || PathPrefix(`/ws-proxy/`) || PathPrefix(`/api`) || PathPrefix(`/oauth2`))
    - traefik.http.routers.netbird-backend.entrypoints=websecure
    - traefik.http.routers.netbird-backend.tls=true
    - traefik.http.routers.netbird-backend.tls.certresolver=letsencrypt
    - traefik.http.routers.netbird-backend.service=netbird-server
    # Services
    - traefik.http.services.netbird-server.loadbalancer.server.port=80
    - traefik.http.services.netbird-server-h2c.loadbalancer.server.port=80
    - traefik.http.services.netbird-server-h2c.loadbalancer.server.scheme=h2c
  logging:
    driver: "json-file"
    options:
      max-size: "500m"
      max-file: "2"

With external reverse proxy (exposed ports):

netbird-server:
  image: netbirdio/netbird-server:latest
  container_name: netbird-server
  restart: unless-stopped
  networks: [netbird]
  ports:
    - '127.0.0.1:8081:80'
    - '3478:3478/udp'
  volumes:
    - netbird_data:/var/lib/netbird
    - ./config.yaml:/etc/netbird/config.yaml
  command: ["--config", "/etc/netbird/config.yaml"]
  logging:
    driver: "json-file"
    options:
      max-size: "500m"
      max-file: "2"

Traefik Routing Labels

When using the built-in Traefik, the netbird-server service uses two routers to handle different traffic types:

Router Path Prefixes Backend Service Purpose
netbird-grpc /signalexchange.SignalExchange/, /management.ManagementService/, /management.ProxyService/ netbird-server-h2c (h2c scheme) gRPC traffic for signal exchange, management API, and the Reverse Proxy feature. Uses HTTP/2 cleartext (h2c) backend because gRPC requires HTTP/2. The /management.ProxyService/ path is only needed if the reverse proxy container connects through Traefik (see comment in the snippet above).
netbird-backend /relay, /ws-proxy/, /api, /oauth2 netbird-server (http scheme) HTTP traffic for relay connections, WebSocket proxying, REST API, and OAuth2/OIDC endpoints.

The dashboard router has priority=1 (lowest), so it acts as a catch-all for requests that don't match the more specific server routes.

The STUN port (3478/udp) must always be exposed publicly, regardless of reverse proxy configuration. STUN uses UDP for NAT detection and cannot be proxied through HTTP reverse proxies. The STUN server is embedded in the combined `netbird-server` container and configured via the `server.stunPorts` field in `config.yaml`.

Volume Configuration

Volume Mount Point Purpose
netbird_data /var/lib/netbird Stores the management database (SQLite by default), encryption keys, and persistent state. Back up this volume regularly to preserve your accounts, peers, policies, and setup keys.
netbird_traefik_letsencrypt /letsencrypt Stores Traefik's Let's Encrypt TLS certificates. Only used when deploying with the built-in Traefik reverse proxy (option 0). Preserve this volume to maintain TLS certificates across restarts.

config.yaml

The unified configuration file controls the combined NetBird server. It replaces the separate management.json and relay.env files from older deployments.

Complete Structure

server:
  listenAddress: ":80"
  exposedAddress: "https://netbird.example.com:443"
  stunPorts:
    - 3478
  metricsPort: 9090
  healthcheckAddress: ":9000"
  logLevel: "info"
  logFile: "console"

  authSecret: "your-relay-auth-secret"
  dataDir: "/var/lib/netbird"

  auth:
    issuer: "https://netbird.example.com/oauth2"
    signKeyRefreshEnabled: true
    dashboardRedirectURIs:
      - "https://netbird.example.com/nb-auth"
      - "https://netbird.example.com/nb-silent-auth"
    cliRedirectURIs:
      - "http://localhost:53000/"

  store:
    engine: "sqlite"  # sqlite, postgres, or mysql
    dsn: ""  # Connection string for postgres or mysql
    encryptionKey: "your-encryption-key"

Server Settings

The address and port the combined server listens on inside the container. Default: `:80`. TLS is handled by the reverse proxy. The public-facing URL where peers connect to the server. Format: `https://hostname:port`. This address is distributed to peers and must be reachable from all clients. List of UDP ports for the embedded STUN server. Default: `[3478]`. These ports must be exposed in `docker-compose.yml` and reachable through firewalls. Port to expose Prometheus metrics endpoint. Default: `9090`. Metrics are available at `/metrics` for monitoring. Address for health check endpoint. Default: `:9000`. Exposes `/health` for container orchestration and load balancer health probes. Controls log verbosity. Options: `debug`, `info`, `warn`, `error`. Default: `info`. Use `debug` for troubleshooting connection issues. Where to write log output. Use `console` for Docker logging (recommended) or specify a file path. Default: `console`. Shared secret for relay authentication. Auto-generated by the setup script. This secret is used internally by the combined server for relay credential validation. Data directory path where the server stores its database and state files. Default: `/var/lib/netbird`. Maps to the `netbird_data` Docker volume.

Authentication Settings

Configures the built-in identity provider (embedded IdP) that handles user authentication and management.

The issuer URL for OAuth2/OIDC tokens. Format: `https://your-domain/oauth2`. This URL is used to validate JWT tokens and must be accessible to clients. Enables automatic refresh of IdP signing keys. Recommended: `true`. Ensures tokens remain valid by periodically rotating signing keys. Allowed redirect URIs for OAuth2 authorization flow. Must include the dashboard authentication callbacks, typically `/nb-auth` and `/nb-silent-auth` on your domain. Redirect URIs for CLI-based authentication. Default: `["http://localhost:53000/"]`. Used when authenticating via the `netbird` CLI tool.

When the embedded IdP is active, the server automatically hosts these OIDC endpoints:

  • Discovery: https://your-domain/oauth2/.well-known/openid-configuration
  • JWKS (signing keys): https://your-domain/oauth2/keys
  • Token issuance: https://your-domain/oauth2/token
  • Device authorization: https://your-domain/oauth2/device/authorize
NetBird also supports integration with external OIDC-compatible identity providers for Single Sign-On (SSO), Multi-Factor Authentication (MFA), and centralized user management. See the [Authentication & IdPs page](/selfhosted/identity-providers) for configuration details.

Store Settings

Configures the database backend for storing all NetBird management data including accounts, peers, groups, access policies, routes, DNS configuration, setup keys, and activity logs.

Database engine. Options: `sqlite`, `postgres`, `mysql`. Default: `sqlite`. Connection string for postgres or mysql engines. For postgres: `host=localhost user=netbird password=secret dbname=netbird port=5432`. Alternatively, use the `NETBIRD_STORE_ENGINE_POSTGRES_DSN` or `NETBIRD_STORE_ENGINE_MYSQL_DSN` environment variables. 32-byte (256-bit) encryption key for sensitive data at rest. Used to encrypt setup keys, API tokens, and other secrets stored in the database. Auto-generated by the setup script.

What data is stored?

  • Accounts and users - User accounts, roles, and permissions
  • Peers - Registered devices, their WireGuard keys, IP assignments, and metadata
  • Groups - Peer groupings used for access control
  • Access policies - Network access rules
  • Routes - Network routes for external subnets
  • DNS configuration - Custom DNS settings
  • Setup keys - Keys for automated peer enrollment
  • Activity logs - Audit trail
Engine Storage Notes
SQLite (default) /var/lib/netbird/ volume File-based database stored in the netbird_data Docker volume. Zero configuration required, but does not support concurrent writes or running multiple management instances. Best for testing or small deployments.
PostgreSQL External database server Recommended for production deployments. Supports concurrent access, enabling multiple management instances for high availability.
MySQL External database server Alternative to PostgreSQL for organizations that have standardized on MySQL/MariaDB. Provides similar benefits including concurrent access.

For PostgreSQL or MySQL, set the connection string via the server.store.dsn field in config.yaml or environment variables on the netbird-server container. See Using an External Database below.

See Management Postgres Store for detailed PostgreSQL setup.

Keep `server.store.encryptionKey` secure and backed up. This key encrypts sensitive data in your database, including setup keys and API tokens. Losing this key means losing access to encrypted data, and you will need to regenerate all setup keys and API tokens.

dashboard.env

Environment configuration for the dashboard service.

Dashboard Architecture

The NetBird dashboard container includes an embedded nginx server that serves the dashboard web pages. This nginx instance is built into the container image and handles serving the static web UI files.

# Endpoints
NETBIRD_MGMT_API_ENDPOINT=https://netbird.example.com
NETBIRD_MGMT_GRPC_API_ENDPOINT=https://netbird.example.com

# OIDC - using embedded IdP
AUTH_AUDIENCE=netbird-dashboard
AUTH_CLIENT_ID=netbird-dashboard
AUTH_CLIENT_SECRET=
AUTH_AUTHORITY=https://netbird.example.com/oauth2
USE_AUTH0=false
AUTH_SUPPORTED_SCOPES=openid profile email groups
AUTH_REDIRECT_URI=/nb-auth
AUTH_SILENT_REDIRECT_URI=/nb-silent-auth

# SSL - disabled when behind reverse proxy (Traefik handles TLS)
NGINX_SSL_PORT=443
LETSENCRYPT_DOMAIN=none
When using the built-in Traefik or an external reverse proxy, set `LETSENCRYPT_DOMAIN=none` because the reverse proxy handles TLS termination. Only set a domain here if running the dashboard standalone without a reverse proxy.

Endpoint Configuration

Variable Description
NETBIRD_MGMT_API_ENDPOINT The URL where the dashboard makes REST API calls to the management server (e.g., https://netbird.example.com). Must be accessible from users' browsers since API calls are made client-side.
NETBIRD_MGMT_GRPC_API_ENDPOINT The URL for gRPC communication with the management server. Usually the same as the REST endpoint. Used for in-browser SSH and RDP clients, as well as surfacing management links for client config instructions.

Authentication Configuration

Variable Description
AUTH_AUDIENCE The expected audience claim in OAuth2 tokens. Must match the audience configured in your IdP. For embedded IdP, use netbird-dashboard.
AUTH_CLIENT_ID The OAuth2 client identifier for the dashboard application. For embedded IdP deployments, this is netbird-dashboard. Must match the client ID registered with your identity provider.
AUTH_CLIENT_SECRET OAuth2 client secret for confidential clients. Leave empty for public clients (the default for browser-based apps like the dashboard).
AUTH_AUTHORITY The OAuth2/OIDC issuer URL (e.g., https://netbird.example.com/oauth2 for embedded IdP). The dashboard fetches OIDC discovery metadata from {AUTH_AUTHORITY}/.well-known/openid-configuration.
USE_AUTH0 Set to true only when using Auth0 as your identity provider. Leave as false for embedded IdP or other OIDC providers.
AUTH_SUPPORTED_SCOPES Space-separated list of OAuth2 scopes to request during login. Standard value is openid profile email groups.
AUTH_REDIRECT_URI The path where the IdP redirects after authentication (e.g., /nb-auth). Must match a redirect URI registered with your identity provider.
AUTH_SILENT_REDIRECT_URI The path for silent token refresh (e.g., /nb-silent-auth). Used by the dashboard to refresh tokens in the background without user interaction.

Embedded Nginx Configuration

The dashboard container's embedded nginx server can be configured using these environment variables. These settings control how the dashboard serves its web UI.

Variable Default Description
NGINX_SSL_PORT 443 The HTTPS port for the dashboard's embedded nginx server. Only relevant in standalone mode without an external reverse proxy.
LETSENCRYPT_DOMAIN - The domain name for automatic Let's Encrypt certificate provisioning. Set to none when using an external reverse proxy that handles TLS.
LETSENCRYPT_EMAIL - Email address for Let's Encrypt account registration and certificate expiry notifications. Required when LETSENCRYPT_DOMAIN is set to an actual domain.
The `NGINX_SSL_PORT` and Let's Encrypt variables are **only necessary when running the dashboard standalone** without an external reverse proxy. For most installations using the built-in Traefik or an external reverse proxy, set `LETSENCRYPT_DOMAIN=none` and the embedded nginx will serve on HTTP (port 80) internally while your reverse proxy handles HTTPS.

Common Configuration Scenarios

Using an External Database

To use PostgreSQL instead of SQLite:

  1. Update config.yaml:
server:
  store:
    engine: "postgres"
    dsn: "host=db-server user=netbird password=secret dbname=netbird port=5432"

Alternatively, you can use an environment variable instead of putting the DSN in the config file:

netbird-server:
  environment:
    - NETBIRD_STORE_ENGINE_POSTGRES_DSN=host=db-server user=netbird password=secret dbname=netbird port=5432
    # Or for MySQL:
    # - NETBIRD_STORE_ENGINE_MYSQL_DSN=user:password@tcp(host:3306)/netbird

See Management Postgres Store for detailed setup.

Changing Log Level

Update server.logLevel in config.yaml:

server:
  logLevel: "debug"

Options: debug, info, warn, error. Use debug for troubleshooting connection issues.

Custom STUN Ports

To use multiple STUN ports, update config.yaml:

server:
  stunPorts:
    - 3478
    - 3479

Make sure to expose all ports in docker-compose.yml:

netbird-server:
  ports:
    - '3478:3478/udp'
    - '3479:3479/udp'

Behind a Reverse Proxy

When running behind your own reverse proxy (Nginx, Caddy, Nginx Proxy Manager, etc.) instead of the built-in Traefik:

  1. Set LETSENCRYPT_DOMAIN=none in dashboard.env
  2. Use the exposed-ports variant of docker-compose.yml (the setup script generates this automatically for options 1-4)
  3. Configure your reverse proxy to route traffic to the correct containers and ports:
    • Dashboard: 127.0.0.1:8080 (HTTP)
    • NetBird Server: 127.0.0.1:8081 (HTTP), with gRPC paths using h2c (HTTP/2 cleartext)

See Reverse Proxy Configuration for detailed templates for Nginx, Caddy, and other proxies.

Using External Services (Advanced)

The default NetBird deployment includes embedded relay, signal, and STUN services. External services are only needed for advanced use cases.

To use external STUN, relay, or signal servers, add overrides to config.yaml:

server:
  # ... basic settings ...

  # Optional: Use external STUN servers
  stuns:
    - uri: "stun:stun.example.com:3478"
      proto: "udp"

  # Optional: Use external relay servers
  relays:
    addresses:
      - "rels://relay.example.com:443"
    secret: "relay-auth-secret"
    credentialsTTL: "24h"

  # Optional: Use external signal server
  signalUri: "https://signal.example.com:443"

See the Scaling Your Self-Hosted Deployment guide for more details on configuring external services.


See Also