ci / lint-yaml (push) Successful in 2s
ci / lint-dockerfiles (push) Successful in 1s
ci / validate (push) Successful in 2s
ci / build (push) Skipped
deploy / validate (push) Skipped
renovate-ci / validate-renovate (push) Skipped
ci / lint-prettier (push) Successful in 3s
ci / lint-ruff (push) Successful in 1s
ci / lint-prettier (pull_request) Successful in 3s
ci / lint-ruff (pull_request) Successful in 1s
ci / lint-yaml (pull_request) Successful in 5s
ci / lint-dockerfiles (pull_request) Successful in 1s
ci / validate (pull_request) Successful in 1s
ci / build (pull_request) Skipped
renovate-ci / validate-renovate (pull_request) Successful in 10s
124 lines
5.4 KiB
Markdown
124 lines
5.4 KiB
Markdown
# NetBird
|
|
|
|
Self-hosted NetBird with the combined management, signal, relay, and STUN server. The dashboard and server run behind the repository's existing external Traefik instance on the Docker `proxy` network. Only STUN UDP `3478` is published directly.
|
|
|
|
The deployment uses SQLite for a single-instance homelab server. The persistent `netbird_data` volume and the datastore encryption key are both required to recover the installation.
|
|
|
|
## Files
|
|
|
|
- `compose.yaml`: dashboard and combined server; selected by the marker-driven deploy workflow through `active`.
|
|
- `config.template.yaml`: non-secret server configuration rendered at startup.
|
|
- `entrypoint.sh`: injects Docker secrets into an in-memory runtime configuration.
|
|
- `client.compose.yaml`: optional host-network peer using a dashboard-generated setup key.
|
|
- `.env`: ignored local hostnames, the detected Traefik Docker-network subnet, and optional client setup key.
|
|
- `secrets/`: ignored relay secret and datastore encryption key.
|
|
|
|
## First deployment
|
|
|
|
Run these commands on the Docker host before merging the activating branch. The deploy preflight resets tracked files but preserves ignored local state.
|
|
|
|
```bash
|
|
cd /srv/homelab/netbird
|
|
./setup.sh
|
|
$EDITOR .env
|
|
docker compose config --quiet
|
|
docker compose up -d
|
|
```
|
|
|
|
Review the values in `.env` before starting. The example public hostname is `netbird.forust.xyz`; change it if a different public domain was selected. `setup.sh` replaces `NETBIRD_PROXY_SUBNET=auto` with the first IPv4 subnet of the external Docker `proxy` network. Keep that value synchronized with the network; set an explicit CIDR instead if the network is managed elsewhere.
|
|
|
|
`setup.sh` is idempotent and never replaces existing secrets. Do not delete or regenerate `secrets/datastore-encryption-key` after the first successful start unless all encrypted setup keys and API tokens are intentionally being invalidated.
|
|
|
|
## Network prerequisites
|
|
|
|
- Point the public hostname directly to the Docker host. Do not proxy UDP `3478` through Cloudflare or another CDN.
|
|
- Allow inbound TCP `80`, TCP `443`, and UDP `3478` through the host firewall and upstream router.
|
|
- Ensure the external `proxy` Docker network exists and Traefik uses its `websecure` entrypoint and `letsencrypt` resolver. `NETBIRD_PROXY_SUBNET` must describe that network; it is used to trust only forwarded client addresses from Traefik.
|
|
- Ensure the internal names in `.env` resolve where the local and development aliases are needed.
|
|
- Keep Traefik's `websecure` read timeout disabled for long-lived gRPC and WebSocket sessions. This repository configures `--entrypoints.websecure.transport.respondingTimeouts.readTimeout=0` in `traefik/compose.yaml`.
|
|
|
|
After startup, verify OIDC discovery through the public TLS endpoint:
|
|
|
|
```bash
|
|
curl -fsS "https://${NETBIRD_DOMAIN}/oauth2/.well-known/openid-configuration"
|
|
```
|
|
|
|
Open `https://${NETBIRD_DOMAIN}` immediately and complete the initial owner setup. Treat the initial setup flow as public until the owner exists.
|
|
|
|
## Optional host client
|
|
|
|
The client intentionally lives in a separate Compose project. Normal server deploys use `--remove-orphans`, so keeping the client in the server project would cause it to be removed.
|
|
|
|
1. Create a reusable or ephemeral setup key in the NetBird dashboard.
|
|
2. Put `NB_SETUP_KEY=<key>` in the ignored `netbird/.env` file.
|
|
3. Set `NETBIRD_CLIENT_HOSTNAME` to this machine's desired peer name.
|
|
4. Start and inspect the client:
|
|
|
|
```bash
|
|
cd /srv/homelab/netbird
|
|
docker compose -f client.compose.yaml config --quiet
|
|
docker compose -f client.compose.yaml up -d
|
|
docker compose -f client.compose.yaml exec netbird-client netbird status
|
|
```
|
|
|
|
The client uses host networking and requires `NET_ADMIN`, `SYS_ADMIN`, `SYS_RESOURCE`, and `/dev/net/tun`. Remove it without affecting the server stack:
|
|
|
|
```bash
|
|
docker compose -f client.compose.yaml down
|
|
```
|
|
|
|
## Operations
|
|
|
|
Inspect status and logs:
|
|
|
|
```bash
|
|
docker compose ps
|
|
docker compose logs --tail=200 netbird-server dashboard
|
|
```
|
|
|
|
Stop or remove containers without deleting data:
|
|
|
|
```bash
|
|
docker compose down
|
|
```
|
|
|
|
Do not add `-v` to `docker compose down`; it would delete the NetBird datastore.
|
|
|
|
## Backup and restore
|
|
|
|
Back up both the persistent volume and the ignored secret files. For a consistent SQLite backup, briefly stop the server first and store the resulting archive and `datastore-encryption-key` in an encrypted backup:
|
|
|
|
```bash
|
|
cd /srv/homelab/netbird
|
|
mkdir -p backups
|
|
docker compose stop netbird-server
|
|
docker run --rm \
|
|
-v netbird_data:/data:ro \
|
|
-v "$PWD/backups:/backup" \
|
|
busybox:1.37.0 \
|
|
tar -C /data -czf "/backup/netbird-data-$(date -u +%Y%m%dT%H%M%SZ).tar.gz" .
|
|
docker compose start netbird-server
|
|
```
|
|
|
|
Also securely back up:
|
|
|
|
- `secrets/datastore-encryption-key` — required to decrypt stored secrets.
|
|
- `secrets/relay-auth-secret` — keeps issued relay credentials valid across restoration.
|
|
- `netbird/.env` — optional, but it records the public and internal hostnames.
|
|
|
|
Test a restore in an isolated Docker host before relying on a backup.
|
|
|
|
## Upgrade
|
|
|
|
1. Take and verify a backup.
|
|
2. Review NetBird release notes for server, client, and dashboard compatibility.
|
|
3. Update the pinned tags in `compose.yaml`; update `client.compose.yaml` separately when deploying the client.
|
|
4. Pull and recreate the selected services:
|
|
|
|
```bash
|
|
docker compose pull
|
|
docker compose up -d
|
|
```
|
|
|
|
The image tags are intentionally pinned instead of using `latest`, matching this repository's pull-on-deploy policy.
|