From 56f98dc5382ca87f2313a60e80b2d2f34e82d6a3 Mon Sep 17 00:00:00 2001
From: Jack Carter <128555021+SunsetDrifter@users.noreply.github.com>
Date: Wed, 6 May 2026 15:06:58 +0200
Subject: [PATCH] docs(peers): add bootstrap via config file guide
New page covering how to pre-populate default.json so NetBird peers
register with the right settings on first start in IaC, Docker, and
Kubernetes deployments. Documents file location across OSes, common
keys (with guidance to leave PrivateKey empty and treat PreSharedKey
as optional), runtime setup-key injection with worked Docker and
Kubernetes ConfigMap + Secret examples, backup hazards around the
embedded WireGuard private key, and how to verify registration via
netbird status --check startup, --json, and GET /api/peers.
Includes a callout that this workflow is for unattended workloads
only -- end-user devices should still enroll via the SSO flow so
Zero Trust can re-verify the user identity.
Linked from Manage NetBird -> Peers, right after Setup Keys.
---
src/components/NavigationDocs.jsx | 4 +
.../peers/bootstrap-via-config-file.mdx | 176 ++++++++++++++++++
2 files changed, 180 insertions(+)
create mode 100644 src/pages/manage/peers/bootstrap-via-config-file.mdx
diff --git a/src/components/NavigationDocs.jsx b/src/components/NavigationDocs.jsx
index 02c4ed1d..25680e74 100644
--- a/src/components/NavigationDocs.jsx
+++ b/src/components/NavigationDocs.jsx
@@ -96,6 +96,10 @@ export const docsNavigation = [
title: 'Setup Keys',
href: '/manage/peers/register-machines-using-setup-keys',
},
+ {
+ title: 'Bootstrap via Config File',
+ href: '/manage/peers/bootstrap-via-config-file',
+ },
{ title: 'Browser Client', href: '/manage/peers/browser-client' },
{ title: 'SSH', href: '/manage/peers/ssh' },
{ title: 'Lazy Connections', href: '/manage/peers/lazy-connection' },
diff --git a/src/pages/manage/peers/bootstrap-via-config-file.mdx b/src/pages/manage/peers/bootstrap-via-config-file.mdx
new file mode 100644
index 00000000..a8ad761a
--- /dev/null
+++ b/src/pages/manage/peers/bootstrap-via-config-file.mdx
@@ -0,0 +1,176 @@
+import {Note, Warning} from "@/components/mdx"
+
+export const description = 'Bootstrap NetBird peers via a pre-populated default.json config file: where it lives, what to set, how to inject the setup key at runtime, backup considerations, and how to verify registration.'
+
+# Bootstrap peers via config file
+
+When you deploy NetBird across golden images, infrastructure-as-code (Terraform, Ansible, cloud-init), Docker, or Kubernetes, you want each peer to come up with the right settings on first start, register against your account, and report success without anyone touching it.
+
+This page covers the three pieces of that workflow: pre-configuring the client with a `default.json` file, passing the setup key at runtime, and verifying that registration succeeded.
+
+For the credentials side — what setup keys are, one-off vs. reusable, ephemeral peers, auto-assign groups — see [Use setup keys to add machines to your network at scale](/manage/peers/register-machines-using-setup-keys).
+
+
+This workflow is for **unattended workloads** — servers, containers, autoscaled VMs, IaC-provisioned infrastructure. **Don't use setup keys to enroll end-user devices.** Zero Trust depends on continuously re-verifying the user behind a peer; a peer registered with a setup key has no associated user identity, so it can't be re-authenticated when a session expires or scoped by user-based policies. Enroll user laptops and phones via the SSO login flow instead — see [Install NetBird](/get-started/install).
+
+
+## Pre-configure with `default.json`
+
+The NetBird daemon stores its system default profile in a JSON file. If that file already exists when the daemon starts for the first time, it picks up the values you set instead of starting from a blank state. This lets you bake your management URL, interface settings, and feature toggles into a base image.
+
+### File location
+
+| Platform | Path |
+| --- | --- |
+| Linux / macOS (system default profile) | `/var/lib/netbird/default.json` |
+| Windows | `C:\ProgramData\Netbird\default.json` |
+| Docker (`netbirdio/netbird` image) | inside the `netbird-client` volume mounted at `/var/lib/netbird/` |
+
+### Common keys
+
+A representative `default.json`:
+
+```json
+{
+ "ManagementURL": "https://api.netbird.io:443",
+ "AdminURL": "https://app.netbird.io:443",
+ "WgIface": "wt0",
+ "IFaceBlackList": ["docker", "br-", "veth"],
+ "BlockInbound": false,
+ "BlockLANAccess": false,
+ "RosenpassEnabled": false,
+ "PrivateKey": "",
+ "PreSharedKey": ""
+}
+```
+
+Notable fields:
+
+- `ManagementURL` and `AdminURL` — only needed when you point at a self-hosted deployment. The cloud defaults are `https://api.netbird.io:443` and `https://app.netbird.io:443`.
+- `WgIface` — WireGuard interface name (defaults to `wt0`).
+- `IFaceBlackList` — interfaces the client should ignore when listening for connections.
+- `BlockInbound`, `BlockLANAccess`, `RosenpassEnabled` — feature toggles that mirror the [`netbird up` flags](/get-started/cli#up).
+- `PrivateKey` — **leave empty.** The daemon generates a unique WireGuard private key on first start. Each peer must end up with its own key, so never ship a populated `PrivateKey` in a base image.
+- `PreSharedKey` — **optional.** WireGuard pre-shared keys are not auto-generated. Only set this if your deployment requires PSK authentication; otherwise leave it empty or pass `--preshared-key` at runtime.
+
+
+The fastest way to derive a working template is to bootstrap one peer manually on the exact NetBird version you plan to deploy, copy its `default.json`, clear `PrivateKey`, and use that as your base. The schema can shift between versions, so re-derive the template after major version bumps rather than reusing an old one.
+
+
+Values from `default.json` sit at the bottom of the [configuration precedence](/get-started/cli#configuration-precedence): `NB_*` environment variables and CLI flags both override them.
+
+## Pass the setup key at runtime
+
+The setup key is **not** stored in `default.json`. Pass it per-launch so it can be sourced from a secret manager and rotated without rebuilding images:
+
+- `NB_SETUP_KEY=` environment variable, or
+- `--setup-key ` / `--setup-key-file ` flags on `netbird up` or `netbird login`.
+
+### Docker
+
+Mount a pre-baked `default.json` into the volume the daemon reads from, and inject the setup key from your shell or a secret store:
+
+```shell
+docker run -d --name netbird --cap-add=NET_ADMIN \
+ -v "$(pwd)/default.json:/var/lib/netbird/default.json:ro" \
+ -e NB_SETUP_KEY="$NB_SETUP_KEY" \
+ netbirdio/netbird:latest
+```
+
+### Kubernetes
+
+Bake the config into a `ConfigMap`, source the setup key from a `Secret`, and mount both into the pod. Pair this with the liveness, readiness, and startup probes from [Deploy routing peers to a Kubernetes cluster](/use-cases/cloud/routing-peers-and-kubernetes) for a complete deployment.
+
+```yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: netbird-config
+data:
+ default.json: |
+ {
+ "ManagementURL": "https://api.netbird.io:443",
+ "AdminURL": "https://app.netbird.io:443",
+ "WgIface": "wt0",
+ "BlockInbound": false,
+ "BlockLANAccess": false,
+ "RosenpassEnabled": false,
+ "PrivateKey": ""
+ }
+---
+apiVersion: v1
+kind: Secret
+metadata:
+ name: netbird-setup-key
+type: Opaque
+stringData:
+ NB_SETUP_KEY: "AAAA-BBB-CCC-DDDDDD"
+---
+# Pod spec excerpt
+spec:
+ containers:
+ - name: netbird
+ image: netbirdio/netbird:latest
+ env:
+ - name: NB_SETUP_KEY
+ valueFrom:
+ secretKeyRef:
+ name: netbird-setup-key
+ key: NB_SETUP_KEY
+ volumeMounts:
+ - name: config
+ mountPath: /var/lib/netbird/default.json
+ subPath: default.json
+ volumes:
+ - name: config
+ configMap:
+ name: netbird-config
+```
+
+## Backing up `default.json`
+
+
+`default.json` contains the peer's WireGuard private key. Restoring it onto a different machine clones the peer identity, and a cloned identity will fail to connect while the original peer is still connected — only one peer per identity can be online at a time. Don't treat this file as a portable backup.
+
+
+The clean pattern is to treat `default.json` as ephemeral local state: when you need to recreate a peer, re-register it with a setup key and let the daemon generate a fresh private key.
+
+For workloads where peers come and go — containers, autoscaling groups, short-lived VMs — create the setup key with **Ephemeral peers** enabled. The management server automatically removes peers that have been offline for more than 10 minutes, so you don't accumulate stale entries. See [Ephemeral peers](/manage/peers/register-machines-using-setup-keys#ephemeral-peers) for details.
+
+## Verify registration
+
+### Single-peer health check
+
+`netbird status --check startup` exits `0` once the daemon has connected to management, signal, and (if any are configured) at least one relay; it exits `1` otherwise. Companion checks:
+
+- `--check live` — the daemon process is responsive.
+- `--check ready` — the client is not waiting on user authentication.
+
+```shell
+netbird status --check startup && echo "registered" || echo "not registered yet"
+```
+
+The Kubernetes example in [Deploy routing peers to a Kubernetes cluster](/use-cases/cloud/routing-peers-and-kubernetes#step-4-deploy-the-netbird-agent) wires all three checks into liveness, readiness, and startup probes — a good template for any container-based deployment.
+
+### Parseable output
+
+`netbird status --json` returns the full status block as JSON, suitable for scripts, CI checks, or shipping to a monitoring backend:
+
+```shell
+netbird status --json | jq '.management.connected'
+```
+
+### Fleet-wide check via the REST API
+
+To verify many peers without logging into each one, query the management API. `GET /api/peers` returns every peer with its `connected` flag and `last_seen` timestamp:
+
+```shell
+curl -H "Authorization: Token $NETBIRD_PAT" \
+ https://api.netbird.io/api/peers | jq '.[] | {name, connected, last_seen}'
+```
+
+This needs a Personal Access Token; the recommended pattern is to issue one to a [service user](/manage/public-api) rather than a human user, so it survives staff changes. See:
+
+- [List all Peers](/api/resources/peers) — full endpoint reference and language samples.
+- [Public API](/manage/public-api) — service users, token creation, rate limits.
+- [Authentication](/api/guides/authentication) — how to send the `Authorization: Token` header.