Start and operate
Start
docker compose up -d --build
docker compose ps
In order: Caddy obtains the certificates; PostgreSQL, RabbitMQ and Redis become healthy;
migrations creates the schemas and exits 0; then the identity host, the API, the gateway
and the SPA become healthy. Open https://app.example.com, create the first account and
confirm it from the e-mail.
Seeding is off in Production: the database starts empty, except for the plan catalog.
The first administrator
BlouppyAdmin is the support role: an account that carries it passes every organization
role check of the API, to help an organization's people. Nobody has it in Production, and
there is no screen to grant it, on purpose. Give it to your own account once confirmed,
from the database — deploy/README.md has the two SQL statements. Sign out and in again:
the role is read at sign-in.
Migrations
The migrations service runs before the hosts on every docker compose up. In Production
the runner applies nothing unless Migrations__AllowInProduction=true; .env.example sets
it, so an upgrade migrates on its own.
To make schema changes a deliberate release step, set it to false and migrate by hand
before starting the new version:
docker compose run --rm -e Migrations__AllowInProduction=true migrations
A failed migration exits 1, and the hosts are not started against a schema in an unknown
state.
Upgrading
git pull # or copy the new version
./backup.sh # always before a schema change
docker compose up -d --build # rebuilds, migrates, then restarts the hosts
docker image prune -f
Sessions survive the restart: the keys that encrypt them are in the database. To build
images once elsewhere and only pull on the server, set BLOUPPY_IMAGE_PREFIX to your
registry and BLOUPPY_VERSION to the version.
Backups
| What | Where | Without it |
|---|---|---|
| The database | the postgres-data volume | everything |
| The Data Protection certificate | deploy/secrets/data-protection.pfx and its password | sessions, reset links, saved AI keys and webhook secrets unreadable |
| Files: data exports and avatars | the bucket, or the files volume | the files |
.env | deploy/.env | the configuration |
deploy/backup.sh writes a compressed pg_dump to deploy/backups/ and keeps 14 days.
Run it before every upgrade and nightly, and copy backups/ off the server every day.
Try a restore once, into a scratch database, before you need one — deploy/README.md
gives the commands.
Operating
- Health. Every host answers
GET /health(ready: its database, its broker) andGET /alive(the process). Point an uptime monitor athttps://app.example.com/health. - Logs.
docker compose logs -f gateway identity api, or setOTEL_EXPORTER_OTLP_ENDPOINTto send traces, metrics and logs to an OpenTelemetry collector. - Start-up warnings worth acting on: unencrypted Data Protection keys, no CAPTCHA keys,
an empty
ApiIntrospection:Secret, an API without its response cache, a Stripe test key in production. A healthy start logs nofailline. - Scaling out. The hosts are stateless: sessions, keys, scheduled jobs (clustered
Quartz.NET) and real-time fan-out (RabbitMQ) are shared.
docker compose up -d --scale api=2works for the API. More than one server needs a load balancer doing what Caddy does here, andFileStorage__Provider=S3. - Behind a CDN, list its address ranges in
trusted_proxiesindeploy/Caddyfile, or the audit log and the rate limits will see the CDN's address instead of the visitor's.
The static sites
The landing page and the documentation site have no dependency on the stack. Each has its
own nginx image (front/landing/Dockerfile, front/docs/Dockerfile), or you deploy its
build output to any static host:
cd front && npm ci
npm run build --workspace landing
npm run build --workspace docs
Their addresses are built in: set them before building (see Rename and rebrand).
Without Docker Compose
The images run anywhere containers run. What the compose file supplies, you then supply
yourself: the connection strings, the hosts' public addresses, the trusted proxy range, a
job running the migration image before the hosts roll out, and a TLS-terminating load
balancer. deploy/README.md lists each setting.