feat: add NetBox Cloudron package (Infrastructure) [#648]

Official-image wrapper of netboxcommunity/netbox v4.6.10
(netbox-docker 5.0.2, Granian), digest-pinned. OIDC via
python-social-auth wired to the platform provider; RQ worker
backgrounded behind a web-port gate; addon waits cover the 30s
upstream DB timeout. Full-stack verified: migrations, Granian,
worker, login page + SSO button. 16/~57.

Detail + verification: https://projects.knownelement.com/issues/648#note-4976
This commit is contained in:
2026-09-06 06:26:54 -05:00
parent ee5344f5a5
commit cead1523ad
11 changed files with 392 additions and 14 deletions
+94 -1
View File
@@ -4,7 +4,7 @@
**Project**: TSYSDevStack-SupportStack-Cloudron
**Goal**: Package ~57 applications for Cloudron PaaS platform
**Start Date**: 2025-01-24
**Current Status**: 15/~57 packages completed (~26%)
**Current Status**: 16/~57 packages completed (~28%)
## Completed Packages
@@ -1211,6 +1211,99 @@ IdP if the directory path disappoints.
---
### 16. NetBox (Infrastructure) ✅
**Date**: 2026-09-06
**Application**: NetBox — open-source IPAM/DCIM (IP addresses, prefixes,
VLANs, sites, racks, devices, circuits, virtualization, REST + GraphQL
APIs). Upstream: https://github.com/netbox-community/netbox
(Apache-2.0), v4.6.10. First package in the workspace verified with a
**full-stack local test** (ephemeral PG16 + Redis 7 → migrations →
Granian bind → RQ worker → login page 200 + OIDC button).
**Ticket**: [#648](https://projects.knownelement.com/issues/648)
**Pattern**: official-image wrapper. NetBox itself has no Docker
tooling — images come from the separate netbox-docker repo; v4.6.10 is
built from netbox-docker **5.0.2** (beware stale docs claiming 3.x:
3.4.2 was the last nginx-unit release; 4.0+ serves via **Granian** on
:8080). The image's configuration is env-driven
(`DB_*`, `REDIS[_CACHE]_*`, `SECRET_KEY`, `ALLOWED_HOSTS`,
`CSRF_TRUSTED_ORIGINS`, `REMOTE_AUTH_BACKEND`, `SOCIAL_AUTH_OIDC_*`),
so no config-file generation is needed — start.sh only maps Cloudron
env onto it.
**Auth gate verdict**: ✅ OIDC preferred. NetBox 4.6 uses
python-social-auth directly; there is NO `SOCIAL_AUTH_TYPE` (legacy
netbox-docker 1.x/2.x mechanism). Minimum viable OIDC:
`REMOTE_AUTH_BACKEND='social_core.backends.open_id_connect.OpenIdConnectAuth'`
+ `SOCIAL_AUTH_OIDC_{OIDC_ENDPOINT,KEY,SECRET}` — wired from
`CLOUDRON_OIDC_*`, with the issuer normalized to a trailing slash
(social-core discovery requirement). Local Django login stays available
for admin bootstrap (`manage.py createsuperuser` via the Cloudron
terminal); SSO users register WITHOUT privileges.
**Key decisions**:
- **One-container problem**: upstream compose runs the RQ worker as a
separate service; Cloudron is one container per app. start.sh
backgrounds `manage.py rqworker` behind a gate that waits for
127.0.0.1:8080 to answer — Granian binding is the signal that
docker-entrypoint.sh finished migrating, so the worker never races
the schema. When Granian exits, the container dies and takes the
worker with it.
- **Addon waits BEFORE the entrypoint**: netbox-docker's own DB wait is
only `DB_WAIT_TIMEOUT=30s` — too tight against a cold Cloudron
postgres addon. start.sh does the repo-standard bash `/dev/tcp` wait
for PostgreSQL AND Redis first (same pattern as ChirpStack/eLabFTW).
- **Persistence via build-time symlinks**: the container runs as
unprivileged `netbox` (uid 999, gid 0), so `/opt/netbox/netbox/
{media,reports,scripts}` are replaced by symlinks into `/app/data`
at BUILD time (root), not in start.sh.
- **One Redis instance, two logical DBs**: tasks=0, caching=1
(upstream convention; Cloudron's single redis addon suffices).
- **SKIP_SUPERUSER=true**: no baked-in admin password; README covers
`createsuperuser` via the terminal (mirrors the ChirpStack bootstrap
story). `SECRET_KEY` generated as 64 hex chars (NetBox enforces
>= 50), persisted under /app/data.
- **PG floor**: 4.6 requires PostgreSQL 14+ (15+ from 4.7) — the
Cloudron postgresql addon satisfies it.
**Verification** (the deepest in the workspace so far):
- `docker build --cgroup-parent ukrrs-batch.slice` green (image
pulled by digest, ~1GB).
- No-addons smoke: secret generated, entrypoint reached its DB wait —
i.e. Django configuration parsed cleanly.
- Full-stack test on a scratch docker network: ephemeral postgres:16
+ redis:7 (requirepass), mapped through the same `CLOUDRON_*` env
the platform injects. Results: all ~230 migrations applied; config
banner confirmed every `/etc/netbox/config/*.py` loaded; Granian
`[INFO] Listening at: http://:::8080`; worker gate fired ("web port
is up" → RQ `Listening on high, default, low`); `GET /login/` = 200
with the SSO button linking `/oauth/login/oidc/` — the OIDC backend
is registered. (A `Host: 127.0.0.1` curl returns 400 — ALLOWED_HOSTS
working as designed; the Cloudron proxy sends the real domain.)
- First boot took ~24 min under a load-19 contended dev box (migrate
~15 min + reindex); minutes on an idle host — noted in the README.
**Files Created**:
- Dockerfile (official-image wrapper, tag+amd64-manifest-digest
pinned, build-time persistence symlinks, tini ENTRYPOINT preserved)
- CloudronManifest.json (manifestVersion 2, port 8080, healthCheckPath
/login/, localstorage + postgresql + redis, memoryLimit 2048)
- start.sh (secret persistence, env mapping, OIDC wiring, addon waits,
gated RQ worker, entrypoint handoff) — committed executable
- README.md (auth story, admin bootstrap, runtime layout, knobs)
- CHANGELOG.md
- .env.example (TIME_ZONE / GRANIAN_WORKERS / METRICS_ENABLED)
- .dockerignore (excludes the cloned repo/ from the build context)
- logo.png (from upstream netbox/project-static/img/netbox_touch-icon-180.png)
**Commit**: `feat: add NetBox Cloudron package (Infrastructure) [#648]`
---
## Packaging Pattern: Download Pre-Compiled Binaries
### When to Use