PHP API End-to-End Example
What this page gives you
This deep dive shows a compact two-tier service and is a good first example for understanding dependency and shared-volume modeling.
Shipped example location on NetBSD:
/usr/share/examples/cellmgr/php-api
Topology and dependency graph
The stack has two cells and one volume:
php-api-app-phpfpm(PHP-FPM backend on9000)php-api-edge-nginx(public edge on80)php-api-webroot(shared app files)
Dependency graph:
php-api-app-phpfpm -> php-api-edge-nginx
Operational meaning:
- backend runtime is converged first
- edge proxy converges second and forwards traffic to backend
Manifest deep dive
php-api-app-phpfpm.cell
Key fields:
CELL_CREATE_RESERVED_PORTS="9000"CELL_SUPERVISE_CMD="...php-fpm83 ... /usr/pkg/etc/php-fpm-cellmgr.conf"CELL_DEPENDS_ON=""(backend is first layer)CELL_VOLUME_MOUNTS="php-api-webroot:/var/www/php-api:rw"
Why this matters:
- app layer owns write access to webroot content
- runtime service command is explicit and supervised
php-api-edge-nginx.cell
Key fields:
CELL_CREATE_RESERVED_PORTS="80"CELL_DEPENDS_ON="php-api-app-phpfpm"CELL_VOLUME_MOUNTS="php-api-webroot:/var/www/php-api:ro"
The same volume is mounted read-only in edge. This models least privilege and prevents accidental content mutation from the proxy tier.
php-api-webroot.volume
Defines persistent/shared webroot storage used by both tiers.
Apply plans
php-api-app-phpfpm.apply- installs
php83andphp83-fpm - writes minimal JSON API endpoint at
/var/www/php-api/index.php - writes
/usr/pkg/etc/php-fpm-cellmgr.conf
- installs
php-api-edge-nginx.apply- installs
nginx - writes nginx config routing
/api/to PHP-FPM onlocalhost:9000
- installs
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
- run targeted dry-run
- apply stack
- verify runtime
- validate endpoint behavior
- open
http://<host-ip>/api/ - expected response: JSON payload with
service=php-api-app-phpfpmandstatus=ok
Modeling takeaways
CELL_DEPENDS_ONmodels startup order explicitly- one shared volume with
rw/romount mode split models write authority cleanly - apply plans keep package/config provisioning idempotent and reviewable