import {Note, Warning} from "@/components/mdx"; import {Properties, Property} from "@/components/mdx";
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.
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. |
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
The Docker Compose file defines all NetBird services, their dependencies, networking, and volumes.
| 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. |
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"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 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"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.
| 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. |
The unified configuration file controls the combined NetBird server. It replaces the separate management.json and relay.env files from older deployments.
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"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
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.Environment configuration for the dashboard service.
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| 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. |
| 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. |
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. |
To use PostgreSQL instead of SQLite:
- 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)/netbirdSee Management Postgres Store for detailed setup.
Update server.logLevel in config.yaml:
server:
logLevel: "debug"Options: debug, info, warn, error. Use debug for troubleshooting connection issues.
To use multiple STUN ports, update config.yaml:
server:
stunPorts:
- 3478
- 3479Make sure to expose all ports in docker-compose.yml:
netbird-server:
ports:
- '3478:3478/udp'
- '3479:3479/udp'When running behind your own reverse proxy (Nginx, Caddy, Nginx Proxy Manager, etc.) instead of the built-in Traefik:
- Set
LETSENCRYPT_DOMAIN=noneindashboard.env - Use the exposed-ports variant of
docker-compose.yml(the setup script generates this automatically for options 1-4) - 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)
- Dashboard:
See Reverse Proxy Configuration for detailed templates for Nginx, Caddy, and other proxies.
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.
- Self-hosting Quickstart Guide - Get started quickly with default settings
- Reverse Proxy Configuration - Nginx, Caddy, NPM, HAProxy setup
- Management SQLite Store - SQLite database details
- Management Postgres Store - PostgreSQL setup