Migrate the netbird stack (server/dashboard/proxy) off ~500 lines of per-app Rust to 3 declarative manifests, adding 4 reusable primitives: - SecretGenKind::Base64 (netbird relay authSecret + sqlite store encryptionKey) - GeneratedCert schema + ensure_manifest_certs (self-signed TLS so the dashboard gets a secure context for OIDC PKCE — issue #15; https proxy on 8087 preserved) - templated GeneratedFile render: {{HOST_IP}}/{{HOST_MDNS}}/{{NETWORK_GATEWAY}} (aardvark resolver for the #15 stale-IP fix) /{{secret:NAME}} (never logged) - legacy create_container now honours port.protocol (3478/udp STUN) install_netbird_stack routes via the orchestrator first (legacy kept as fallback, mirroring indeedhub); launch URL derives https://{host_ip}:8087 from host facts. Legacy Rust deletion deferred to post-live-verify. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
123 lines
4.3 KiB
YAML
123 lines
4.3 KiB
YAML
app:
|
|
id: netbird-server
|
|
name: NetBird Server
|
|
version: "0.71.2"
|
|
description: NetBird combined management / signal / relay server with an embedded identity provider and STUN. Backend for the self-hosted NetBird mesh VPN.
|
|
category: networking
|
|
|
|
# Hyphen name matches the runtime references (crash_recovery / dependencies /
|
|
# config startup order) + the live container, so on an existing node the
|
|
# orchestrator ADOPTS the running server rather than recreating it (data +
|
|
# the sqlite store under /var/lib/netbird preserved). Alias `netbird-server`
|
|
# is the short hostname the proxy's nginx proxies/grpc-passes to.
|
|
container_name: netbird-server
|
|
|
|
container:
|
|
image: docker.io/netbirdio/netbird-server:0.71.2
|
|
pull_policy: if-not-present
|
|
network: netbird-net
|
|
network_aliases: [netbird-server]
|
|
# The relay authSecret and the sqlite store encryptionKey are base64 keys
|
|
# (the server base64-decodes them to recover raw bytes — hex would decode to
|
|
# the wrong value). Generated once and reused: ensure_generated_secrets
|
|
# no-ops when the file already exists, so a re-render of config.yaml on an
|
|
# adopted node keeps the same keys (regenerating would orphan the store).
|
|
generated_secrets:
|
|
- name: netbird-relay-auth-secret
|
|
kind: base64
|
|
- name: netbird-store-encryption-key
|
|
kind: base64
|
|
# Pass the rendered config explicitly, mirroring the legacy `--config` arg.
|
|
custom_args: ["--config", "/etc/netbird/config.yaml"]
|
|
|
|
dependencies:
|
|
- storage: 1Gi
|
|
|
|
resources:
|
|
memory_limit: 1Gi
|
|
|
|
security:
|
|
# cap-drop=ALL is applied by the orchestrator. The server binds :80
|
|
# (management/signal/relay HTTP + gRPC) inside the container — a privileged
|
|
# port — so it needs NET_BIND_SERVICE. STUN is 3478/udp (unprivileged).
|
|
capabilities: [NET_BIND_SERVICE]
|
|
readonly_root: false
|
|
network_policy: isolated
|
|
|
|
ports:
|
|
- host: 8086
|
|
container: 80
|
|
protocol: tcp # management API + embedded OIDC issuer (/oauth2)
|
|
- host: 3478
|
|
container: 3478
|
|
protocol: udp # STUN — must be UDP; tcp here breaks relay discovery
|
|
|
|
volumes:
|
|
- type: bind
|
|
source: /var/lib/archipelago/netbird/data
|
|
target: /var/lib/netbird
|
|
options: [rw]
|
|
# The rendered config.yaml, read-only. Re-rendered on every reconcile from
|
|
# host facts + the base64 secrets; idempotent (stable bytes → no restart).
|
|
- type: bind
|
|
source: /var/lib/archipelago/netbird/config.yaml
|
|
target: /etc/netbird/config.yaml
|
|
options: [ro]
|
|
|
|
environment: []
|
|
|
|
# The server's config. {{HOST_IP}} is the node's primary host IP (the proxy's
|
|
# public origin is https on 8087 — the dashboard needs a secure context for
|
|
# OIDC PKCE, issue #15). {{secret:...}} are read 0600 from the secrets dir.
|
|
files:
|
|
- path: /var/lib/archipelago/netbird/config.yaml
|
|
overwrite: true
|
|
content: |
|
|
server:
|
|
listenAddress: ":80"
|
|
exposedAddress: "https://{{HOST_IP}}:8087"
|
|
stunPorts:
|
|
- 3478
|
|
metricsPort: 9090
|
|
healthcheckAddress: ":9000"
|
|
logLevel: "info"
|
|
logFile: "console"
|
|
authSecret: "{{secret:netbird-relay-auth-secret}}"
|
|
dataDir: "/var/lib/netbird"
|
|
auth:
|
|
issuer: "https://{{HOST_IP}}:8087/oauth2"
|
|
localAuthDisabled: false
|
|
signKeyRefreshEnabled: false
|
|
dashboardRedirectURIs:
|
|
- "https://{{HOST_IP}}:8087/nb-auth"
|
|
- "https://{{HOST_IP}}:8087/nb-silent-auth"
|
|
dashboardPostLogoutRedirectURIs:
|
|
- "https://{{HOST_IP}}:8087/"
|
|
cliRedirectURIs:
|
|
- "http://localhost:53000/"
|
|
store:
|
|
engine: "sqlite"
|
|
encryptionKey: "{{secret:netbird-store-encryption-key}}"
|
|
|
|
# TCP liveness on the management port. Binds at startup, stays green; an http
|
|
# check of /oauth2 would false-fail while the issuer warms up.
|
|
health_check:
|
|
type: tcp
|
|
endpoint: localhost:80
|
|
interval: 30s
|
|
timeout: 5s
|
|
retries: 10
|
|
start_period: 30s
|
|
|
|
metadata:
|
|
author: NetBird
|
|
icon: /assets/img/app-icons/netbird.svg
|
|
website: https://netbird.io
|
|
repo: https://github.com/netbirdio/netbird
|
|
license: BSD-3-Clause
|
|
tags:
|
|
- networking
|
|
- vpn
|
|
- wireguard
|
|
- mesh
|