What you'll build
A minimal Celenite application called helloceleneite that:
- Listens on HTTPS port 9090 using a self-signed certificate
- Serves a
GET /api/v1/statusendpoint from the C++ daemon (no PHP) - Serves a
GET /HTML dashboard rendered by PHP-FPM via FastCGI - Runs as a systemd service with the standard hardening flags
- Builds into a sub-50MB Docker image via a multi-stage build
Step plan
Step 1 — Lay out the project
Standard Celenite project layout: src/, php/, etc/, scripts/, build/, Makefile, helloceleneite.service. Why this layout, what each directory owns.
Step 2 — Write the C++17 HTTPS daemon skeleton
Bring up an OpenSSL-backed HTTPS listener with a small request router. Two endpoints: /api/v1/status handled by the daemon, everything else passed through to PHP-FPM via FastCGI.
Step 3 — Wire the FastCGI bridge to PHP-FPM
Open the FPM Unix socket, build the FCGI_PARAMS, stream the request body, read the response, write it back to the TLS connection. The actual handful of lines of C++ that make the whole pattern work.
Step 4 — Configure a dedicated PHP-FPM pool
Why each app gets its own pool. pool.d/helloceleneite.conf with the right user, listen socket, and process manager settings. How to size pm.max_children against your expected concurrency.
Step 5 — Write the dashboard in PHP
A simple index.php that fetches the JSON status from the daemon's local API endpoint and renders it as HTML. Two-file frontend: header.php for chrome, index.php for content.
Step 6 — Self-signed TLS for development
Generate a dev cert with openssl req. Where the daemon loads it. How to swap to Let's Encrypt or a commercial wildcard for production.
Step 7 — Write the systemd unit
Hardened service file: NoNewPrivileges=yes, ProtectSystem=strict, PrivateTmp=yes, raised LimitNOFILE, restart on failure, journal logging. The pattern used by every production Celenite daemon.
Step 8 — Multi-stage Docker build
Build stage with full compiler toolchain → runtime stage with just the binary, PHP-FPM, and a minimal Debian base. Target sub-100MB image. Mount the config and webroot at runtime instead of baking them in.
Step 9 — Smoke test
curl -sk https://localhost:9090/api/v1/status, then curl -sk https://localhost:9090/. Verify the daemon serves the API and that the dashboard renders.
Step 10 — From here to production
What to add next: rate limiting, audit log, credential vault, metrics endpoint, RBAC. Each one is a small standalone module — none of them require a new sidecar.
Until the full walkthrough lands
The fastest way to get the pattern is to read one of the existing daemons end-to-end. Mcaster1StreamProxy (Go variant) is the most compact production example and a good starting point: github.com/davestj/Mcaster1StreamProxy.