Olympus Docs
DeployProduction readiness

Dev vs prod

Field-by-field differences between compose.dev.yml and compose.prod.yml

Olympus has two Compose stack variants. This page lists every meaningful difference between them.

ConcernDev (compose.dev.yml)Prod (compose.prod.yml)
App sourcevolume: mount from sibling repos (../athena, ../hera, ../site) for live reloadPulled from ghcr.io/olympusoss/<app>@sha256:... pinned by digest
Image source for Kratos/Hydraoryd/kratos:v1.x, oryd/hydra:v2.xSame upstream Ory images, pinned by digest
TLSSelf-signed by Caddy, valid for localhost.olympus.appReal cert from Let's Encrypt, ACME-HTTP-01
Captcha (Turnstile)Disabled (TURNSTILE_DISABLED=true)Enabled if TURNSTILE_SITE_KEY is configured
EmailCaptured by MailSlurper at localhost:5434Routed to the configured provider (Resend, Postmark, Brevo, SMTP2GO, custom SMTP)
PostgresSingle self-hosted Postgres containerManaged (Neon recommended) or self-hosted, with sslmode=verify-full
Postgres SSL modedisableverify-full, see Database SSL verify-full
Email verificationOptional (configurable, often left off for dev convenience)Mandatory, enforced by verify-email-enforcement.yml CI gate
Seeded adminadmin@demo.user / admin123!Operator-supplied via Daedalus Accounts wizard step
pgAdminlocalhost:5433Same path, but behind Caddy and OAuth SSO
MailSlurperlocalhost:5434Not present
Kratos serve.public URLhttp://localhost:3100, http://localhost:4100https://ciam.<domain>/.ory/kratos, https://iam.<domain>/.ory/kratos
Hydra urls.self.issuerhttp://localhost:3102, http://localhost:4102https://ciam.<domain>, https://iam.<domain>
Kratos leak_sensitive_valuestrue (dev: helpful errors)false, required by verify-prod-config.yml
Hera CIAM host portBound via Caddy on :3000 (only Caddy gets a port mapping)Not bound at all, internal-only, accessed via Caddy's reverse_proxy
Hera IAM host portBound via Caddy on :4000 (only Caddy gets a port mapping)Not bound at all
LogsContainer stdout (visible via podman logs)Container stdout, plus shipped to your logging provider
Container restartalways for dev convenienceunless-stopped plus systemd unit for VPS-level resilience
Image rebuildoctl deploy triggers a build if local source changedImage is built in GitHub Actions and pushed to GHCR; deploy pulls
Compose networkintranet (bridge)Same; ports policy enforced
ENCRYPTION_KEYGenerated locally by octl deploy, written to .env.devGenerated by Daedalus Secrets wizard step, stored in GitHub Secrets
SESSION_SIGNING_KEYGenerated locallyGenerated by Daedalus, stored in GitHub Secrets
CIAM_RELOAD_API_KEYGenerated locallyGenerated by Daedalus, rotated quarterly per Operate, Reload API Key Rotation
TURNSTILE_SECRET_KEYNot set (captcha disabled)Set per the Turnstile provider account
Outbound to internetAllowed but unused (MailSlurper catches mail)Required for Let's Encrypt ACME, email provider API, GHCR pulls

What's the same

  • The Kratos and Hydra container images are identical between dev and prod (only the config differs).
  • The Athena and Hera app code is identical between dev and prod (only the runtime config differs, env vars, image source).
  • The database schemas, identity schemas, and migrations are identical.
  • The Caddyfile structure is similar (dev uses self-signed; prod uses Let's Encrypt; the route blocks are otherwise the same shape).

Where these differences are configured

DifferenceConfigured in
App image sourceCompose image: vs build:
TLS sourceCaddyfile tls internal vs tls operator@your-domain
CaptchaTURNSTILE_DISABLED env var
EmailKratos courier.smtp.connection_uri
Postgres URLDATABASE_URL env var, including ?sslmode=verify-full
Seeded admindev/iam-seed-dev.sh runs in dev only
Per-domain URLsKratos/Hydra config files (platform/{dev,prod}/{ciam,iam}-kratos/kratos.yml)

Validation

The platform repo's CI runs three workflows that enforce prod-only invariants:

Where next

On this page