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.