Database, Self-hosted
Running Postgres on the same VPS as the Olympus apps
Self-hosting Postgres alongside Olympus is straightforward, compose.prod.yml ships a Postgres container, and you can opt into it via a Daedalus wizard toggle.
Recommendation: prefer managed Postgres (Neon) unless one of the specific reasons below applies. The operational savings outweigh the cost.
Reasons to self-host
- Air-gapped deployment, no outbound from the VPS to a SaaS Postgres.
- Data residency, you need the database physically in the same jurisdiction as the app, with no possibility of provider routing through other regions.
- You're already operating Postgres at scale and have ops capacity to spare.
- Cost at large scale, once your database CPU consistently exceeds a few hundred dollars/month on managed, self-hosting starts to win.
What you take on
- Backups. Nightly
pg_dump, off-host storage, restore drills. - TLS certs. Generate, distribute, rotate (see Operate, Cert Rotation).
- Major version upgrades. Postgres 17 → 18 → 19 every 12-18 months.
- Monitoring. Disk fill alerts, replication lag (if you go HA), connection pool saturation.
- Tuning.
shared_buffers,effective_cache_size,max_connections, Olympus's defaults work but might not be optimal for your workload.
What Daedalus configures
When you select self-hosted in the Database step:
- The
postgresservice stays enabled incompose.prod.yml. - A volume is created for
/var/lib/postgresql/data. init-db.sqlruns on first start, creating the five Olympus databases and their per-database users.- The Postgres container generates a self-signed TLS cert via the Daedalus Secrets step; the apps trust the cert via the local CA bundle.
Sizing the host
For 1k MAU with self-hosted Postgres on the same VPS:
- VPS: at least 4GB RAM (2GB Postgres, 2GB Olympus apps)
- Disk: 20GB minimum; Olympus's data growth is modest (~10MB per 1000 identities)
For 10k MAU:
- VPS: 8GB RAM
- Disk: 50GB
Above 10k MAU, consider splitting Postgres onto a separate host or moving to managed.
Backup strategy
Minimum viable:
# /etc/cron.daily/olympus-pgbackup
podman exec olympus-postgres pg_dumpall -U postgres \
| gzip > /backups/$(date +%Y%m%d).sql.gz
# Off-host: rclone to S3, B2, or rsyncSee Operate, Backups (Postgres) for the full procedure including restore drill cadence.
TLS configuration
Production Olympus requires sslmode=verify-full. With self-hosted Postgres, you must:
- Generate a CA, server cert, and client certs (Daedalus does this).
- Configure
postgresql.conf:ssl = on ssl_cert_file = '/etc/postgresql/server.crt' ssl_key_file = '/etc/postgresql/server.key' ssl_ca_file = '/etc/postgresql/ca.crt' - Configure
pg_hba.confto requirehostsslfor app connections. - Distribute the CA cert to every app container so
verify-fullcan validate the chain.
See Deploy, Database SSL verify-full for the full setup.
Migrations
Olympus migrations run automatically, Kratos and Hydra each have their own migrate containers that run before the main service starts. For PostgreSQL major version upgrades, see Operate, Logs and observability for the recommended pg_upgrade procedure.