MantisBT End-to-End Example
What this page gives you
This walkthrough is for admins who want one complete, realistic stack example from shipped manifests to running service.
You will learn:
- how a multi-cell stack is modeled in manifests
- how dependencies (
CELL_DEPENDS_ON) enforce rollout order - how volume mounts model data ownership and persistence boundaries
Shipped example location on NetBSD:
/usr/share/examples/cellmgr/mantisbt
Topology and dependency graph
The MantisBT example has three cells and three volumes:
mantisbt-data-postgresql(database)mantisbt-app-phpfpm(application runtime)mantisbt-edge-nginx(public HTTP edge)mantisbt-postgresvolume (PostgreSQL data directory)mantisbt-secretsvolume (database password material)mantisbt-webrootvolume (application webroot shared app/edge)
Dependency graph:
mantisbt-data-postgresql -> mantisbt-app-phpfpm -> mantisbt-edge-nginx
Operational meaning:
- DB comes up first
- app starts only after DB is present
- edge starts only after app runtime exists
Manifest deep dive: how the stack is modeled
mantisbt-data-postgresql.cell
Key modeling fields:
CELL_CREATE_RESERVED_PORTS="5432": reserves DB port ownership for this cellCELL_SUPERVISE_CMD=...postgres -D /var/postgresql/data: process to superviseCELL_DEPENDS_ON="": DB is the first layer (no upstream dependency)CELL_VOLUME_MOUNTS="mantisbt-secrets:/var/db/mantisbt-secrets:rw,mantisbt-postgres:/var/postgresql"
Important detail: this stack uses a dedicated data volume for PostgreSQL itself
(mantisbt-postgres), separate from secrets and webroot.
mantisbt-app-phpfpm.cell
Key modeling fields:
CELL_CREATE_RESERVED_PORTS="9000": PHP-FPM listener ownershipCELL_DEPENDS_ON="mantisbt-data-postgresql": hard ordering to DBCELL_VOLUME_MOUNTS="mantisbt-webroot:/var/www/mantisbt:rw": app writes code/config
This models app as a middle tier that can update webroot content.
mantisbt-edge-nginx.cell
Key modeling fields:
CELL_CREATE_RESERVED_PORTS="80": public HTTP port ownershipCELL_DEPENDS_ON="mantisbt-app-phpfpm": edge waits for app tierCELL_VOLUME_MOUNTS="mantisbt-webroot:/var/www/mantisbt:ro": edge reads only
Read-only mount on edge is intentional least-privilege design.
Volume manifests
Volume files are minimal by design:
mantisbt-postgres.volume(persistent DB data)mantisbt-secrets.volume(restricted secret storage, mode0700)mantisbt-webroot.volume(shared app content)
Even simple volume manifests create explicit persistence contracts.
Apply plans
mantisbt-data-postgresql.apply- installs PostgreSQL 16 server package
- initializes cluster on first run
- writes
postgresql.auto.confandpg_hba.conf - generates and stores DB password in secrets volume
- creates/updates
mantisbtrole andmantisbtdatabase
mantisbt-app-phpfpm.apply- installs PHP/FPM + required modules
- downloads MantisBT release and verifies SHA256
- extracts release into shared webroot
- writes
php-fpm-cellmgr.conf
mantisbt-edge-nginx.apply- installs nginx
- writes nginx config
- forwards PHP requests to
127.0.0.1:9000
End-to-end deployment steps
Run commands as root (or prefix with doas).
- bootstrap host once (skip if already done)
- copy shipped example manifests
- inspect desired state before first apply
- run targeted dry-run
- run targeted apply
- verify runtime status
- retrieve generated database password
- complete web installer
- open
http://<host-ip>/ - DB host:
127.0.0.1 - DB name:
mantisbt - DB user:
mantisbt - DB password: value from previous step
- persist your changes as code
- keep
/etc/cellmgrunder version control - continue all updates through manifests +
cellmgr apply
Operations notes after go-live
- back up DB data volume regularly:
cellmgr volume backup create mantisbt-postgres - back up webroot volume as needed:
cellmgr volume backup create mantisbt-webroot - use dry-run before every rollout:
cellmgr apply --dry-run --all