# NetBox NetBox for homelab documentation and visualization. Two runtimes are available: | Runtime | Manifest | Purpose | | ------- | -------------- | -------------------------------------------------------------- | | Docker | `compose.yaml` | Local stand on `127.0.0.1:8000` (no public exposure) | | k8s | `k8s/` | Homelab service on `netbox.forust.xyz` (and the internal name) | Both use the same image (`netboxcommunity/netbox:v4.7-5.1.1`) and Valkey for tasks plus a second logical database for caching. The Docker stand keeps its own PostgreSQL container, while the k8s deployment uses the shared `database` cluster (`postgres.database.svc.cluster.local:5432`, role/database `netbox`); only Valkey stays a per-service StatefulSet. ## Docker Compose ```bash cp .env.example .env # replace CHANGE_ME docker compose up -d ``` The UI is available at . The port is bound to `127.0.0.1` intentionally, so this stand is not exposed on the LAN or public interfaces. The `netbox` service is also attached to the external `proxy` network and carries Traefik labels for `netbox.forust.xyz` and `netbox.workstation.internal`. Those labels only take effect while the Docker Traefik stack is running; it is currently stopped, and the live ingress path in this homelab is the k8s Traefik. Inspect startup and health with: ```bash docker compose ps docker compose logs -f netbox ``` Stop it with `docker compose down`; data is kept in the named volumes `netbox-postgres`, `netbox-media-files`, `netbox-reports-files`, `netbox-scripts-files` and `netbox-redis-data`. ## Kubernetes `k8s/` is deployed in the homelab cluster and serves `netbox.forust.xyz` publicly plus `netbox.workstation.internal` / `netbox.gigaforust.internal` internally. To rebuild it from scratch: ```bash # 1. shared PostgreSQL: the password lives in the shared secret, NetBox keeps a copy kubectl -n database patch secret postgres-shared-secrets \ --type merge -p '{"stringData":{"NETBOX_DB_PASSWORD":""}}' kubectl -n database exec postgres17-0 -- psql -U postgres -d postgres \ -c 'CREATE ROLE netbox LOGIN PASSWORD ...' -c 'CREATE DATABASE netbox OWNER netbox' # 2. secrets first: the deploy workflow never applies *secret*.yaml cp k8s/secrets.yaml.example k8s/secrets.yaml # replace CHANGE_ME kubectl apply -f k8s/secrets.yaml # 3. manifests kubectl apply -f k8s/ ``` The shared cluster is reached at `postgres.database.svc.cluster.local:5432`. Its NetworkPolicy (`postgres/k8s/network-policy.yaml`) must list the `netbox` namespace or connections are dropped, and `postgres/initdb/01-create-databases.sh` already creates the role and database on a fresh data directory. NetBox has no PostgreSQL StatefulSet of its own — only `netbox-valkey`. `netbox.forust.xyz` resolves to this host (`78.98.72.122`) through the `DOMAINS` list in the `default/cfddns` secret. cert-manager issues `netbox-prod-tls` with the `letsencrypt-prod` issuer, the internal route uses `internal-wildcard-tls`. Resources are permanent again now that the first-boot migrations are complete: the web container reserves `100m`/`512Mi` and is capped at `2` CPU/`2Gi`, the worker reserves `50m`/`256Mi` and is capped at `1` CPU/`1Gi`, and Valkey reserves `25m`/`64Mi` and is capped at `250m`/`256Mi`. The deliberately generous CPU caps leave enough headroom for future schema migrations without letting one process consume the whole node. The first start applies ~810 migrations, each in its own transaction with DDL and a commit; every later start is a no-op. The startup probe allows 15 minutes and `progressDeadlineSeconds` is 1800 for the same reason. Probes run inside the pod and explicitly set `Host: netbox.forust.xyz`; a kubelet `httpGet.host` field would replace the probe destination with that public hostname and bypass the pod. ## Secrets - `netbox/.env` (compose) and `netbox/k8s/secrets.yaml` (k8s) are gitignored. Only `.env.example` and `k8s/secrets.yaml.example` are committed. - `netbox/configuration/configuration.py` is env-driven: hosts, database, Redis and the Django keys all come from the environment, so the same settings file works in both runtimes. The k8s copy lives in the `netbox-settings` ConfigMap (`k8s/settings.yaml`) and must be kept in sync with the file. - Rotating `SECRET_KEY` invalidates all sessions; rotating `API_TOKEN_PEPPER_1` invalidates every API token.