Deployment
Run PhlatPage with Docker Compose, keep per-deployment config in env.json, and ship releases with Deployer.
Layout
A deployment has two halves. phlat/, site/ and vendor/ are code, rebuilt from git on every release. data/ is state: pages/, users/, git/ (the History deploy key), storage/ (the registry, locks and rate limits), cache/ (compiled views and the like, which can be deleted at any time) and env.json. State is never baked into the image and survives redeploys, except cache/, which each release makes for itself.
Docker Compose
compose.yaml runs the app image with the project mounted at /app:
services:
app:
image: git.cohere.digital/phlat/frank:latest
restart: unless-stopped
user: 1000:1000
volumes:
- .:/app
- ./phlat/Caddyfile:/etc/frankenphp/Caddyfile
ports:
- 10000:80
The image is FrankenPHP with PHP 8.4, gd, imagick and git. Put a reverse proxy in front for TLS; Caddy trusts private-range proxies for forwarded headers.
compose.yaml also defines a PHP-FPM and Caddy pair on port 19000 (phlat/Caddyfile.fpm) as an alternative.
Config
Config merges in order, later wins: phlat/config.json, site/config.json, data/env.json. Put secrets and per-host overrides in data/env.json, which is gitignored. data/env.cli.json merges on top for CLI runs only.
Deployer
deploy.php ships the code to a host over SSH. Start from phlat/examples/deploy.example.php and set the repository, host and deploy_path. Host credentials go in the gitignored deploy.env.php.
vendor/bin/dep deploy domain.com
Each release is cloned from git and installed with composer install --no-dev. These paths are shared between releases and symlinked in:
data/env.jsonanddata/env.cli.jsondata/pages,data/users,data/git,data/storagesite/public
data/cache is not shared. Each release starts with its own, so a release never serves what an earlier one rendered.
The app container restarts after a deploy or rollback, so PHP's opcache and realpath cache pick up the new release at once.
Build CSS and JS locally first. The deploy does not run a build step.
Reusable image
phlat/Dockerfile.dist builds a runtime image with phlat/ and vendor/ baked in and no site/. A downstream project mounts its own site/ and data/ over it:
services:
app:
image: git.cohere.digital/phlat/page:vX.Y.Z
volumes:
- ./site:/app/site
- ./data:/app/data
Backups
data/ is the state to protect. One command backs up pages (collections included), users, git/ and the env files; restore with backup:restore. storage/ and cache/ are left out: restore rebuilds the registry from the pages and empties the cache.
docker compose exec app php phlat/addons/cli/phlat backup:create