Services (managed addons)
Add managed services (Postgres, Redis, MongoDB, Mailpit, Meilisearch, MinIO)
to a project's environment from a built-in catalog. Each service runs as a
container on the paas-apps network with a persistent named volume; apps in
the same environment automatically receive its connection URL as
{SLUG}_URL in their runtime env vars.
Catalog
| Key | Service | Image | Default port | Volume? |
|---|---|---|---|---|
postgres-16 |
PostgreSQL 16 | postgres:16-alpine |
5432 | yes |
redis-7 |
Redis 7 | redis:7-alpine |
6379 | yes |
mongodb-7 |
MongoDB 7 | mongo:7 |
27017 | yes |
meilisearch-1.10 |
Meilisearch | getmeili/meilisearch:v1.10 |
7700 | yes |
minio |
MinIO (S3) | minio/minio:latest |
9000 | yes |
mailpit |
Mailpit (SMTP) | axllent/mailpit:latest |
1025 | yes |
To add more, edit src/Paas.Domain/Catalog/Catalog.cs and rebuild. The
catalog is searchable by name/description/category/tags via the dashboard
and the API: GET /api/service-templates?q=<query>.
Adding a service
Dashboard
Sidebar → Services → pick env tab → + Add service. Search the catalog
("redis", "search", "data" all work), pick a template, give it a slug
(db, cache, search...), click Provision.
The service moves through Provisioning → Ready (typically 5–15s). When
Ready, click Reveal DSN to see the connection string and the env-var
name it will be auto-injected as.
API
TOKEN=…
PROJ=https://paas.example.com/api/orgs/acme/projects/storefront
# Provision a Redis named "cache" in production
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"slug":"cache","templateKey":"redis-7"}' \
"$PROJ/envs/production/services/"
# List services in an env
curl -H "Authorization: Bearer $TOKEN" "$PROJ/envs/production/services/"
# Reveal connection string (admin only, audited)
curl -H "Authorization: Bearer $TOKEN" \
"$PROJ/envs/production/services/cache/dsn"
How apps connect
For every Ready service in (project, env), the Orchestrator injects an
env var into every app in the same env on the next deploy:
{SLUG_UPPERCASE}_URL = <rendered DSN>
Slug cache (Redis) → CACHE_URL=redis://...:6379. Slug db (Postgres) →
DB_URL=postgres://app:<password>@...:5432/db.
Hyphens in slugs become underscores: feature-flags → FEATURE_FLAGS_URL.
Apps should read these vars at startup. They're populated on the next deploy or redeploy of the app — adding a service does not auto-restart running apps. Either redeploy explicitly or push a new commit.
Per-env isolation
Services are scoped to a single (Project, Environment). Adding a Redis to Production does not create one in Staging. Each env runs its own instances with its own data volumes — staging cannot accidentally see prod data.
If you want the same template across multiple envs, provision it explicitly in each.
Lifecycle
| Action | Effect |
|---|---|
| Add | Container starts, named volume created, status → Ready. |
| Reveal DSN | Decrypts the stored config, renders DSN. Audit-logged. |
| Delete | Container stops + removed. Volume preserved by default so you can re-create the service and recover its data. |
| Auto-restart on host reboot | Containers use restart=unless-stopped so they come back up automatically. |
There is no auto-failover or HA in v1 — these are single-container instances ideal for self-hosted-side projects and staging environments. For prod-grade HA, use a managed cloud provider for stateful tier and let Paas keep managing your apps.
Storage paths
Each service has a named volume paas-svc-<id> mounted at the template's
VolumeMountPath. To back up Postgres for example:
docker exec paas-svc-<id> pg_dump -U app db | gzip > db-$(date +%F).sql.gz
To list all service volumes:
docker volume ls --filter name=paas-svc-
Custom services
Not yet — v1 only ships with the built-in catalog. The data model supports arbitrary templates (any image, any env spec, any DSN format), so a v1.x addition will let users define their own templates via JSON in the dashboard.