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-postgres volume (PostgreSQL data directory)
  • mantisbt-secrets volume (database password material)
  • mantisbt-webroot volume (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 cell
  • CELL_SUPERVISE_CMD=...postgres -D /var/postgresql/data: process to supervise
  • CELL_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 ownership
  • CELL_DEPENDS_ON="mantisbt-data-postgresql": hard ordering to DB
  • CELL_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 ownership
  • CELL_DEPENDS_ON="mantisbt-app-phpfpm": edge waits for app tier
  • CELL_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, mode 0700)
  • 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.conf and pg_hba.conf
    • generates and stores DB password in secrets volume
    • creates/updates mantisbt role and mantisbt database
  • 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).

  1. bootstrap host once (skip if already done)
cellmgr system bootstrap
  1. copy shipped example manifests
cp /usr/share/examples/cellmgr/mantisbt/* /etc/cellmgr/
  1. inspect desired state before first apply
cellmgr cell show mantisbt-data-postgresql --view desired
cellmgr cell show mantisbt-app-phpfpm --view desired
cellmgr cell show mantisbt-edge-nginx --view desired
cellmgr volume list --view desired
  1. run targeted dry-run
cellmgr apply --dry-run mantisbt-data-postgresql mantisbt-app-phpfpm mantisbt-edge-nginx
  1. run targeted apply
cellmgr apply mantisbt-data-postgresql mantisbt-app-phpfpm mantisbt-edge-nginx
  1. verify runtime status
cellmgr cell list --view merged
cellmgr volume list --view merged
cellctl list -T
cellctl stats -T
  1. retrieve generated database password
cellmgr cell shell mantisbt-data-postgresql
# inside cell shell
cat /var/db/mantisbt-secrets/db-password
exit
  1. 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
  1. persist your changes as code
  • keep /etc/cellmgr under 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