orchkaDocs

Deployment

Orchka needs four things running: the web service, the worker, a Postgres database, and a Redis instance. The worker is not optional — it is where every workflow actually executes.

Deploy the worker as an always-on background process with no port and no HTTP health check. It polls Redis and never serves HTTP, so a platform that sleeps idle services, or one that requires an HTTP check, will stop it working.

Docker

Two images, built from the repo root:

docker build -f Dockerfile.web    -t orchka-web .
docker build -f Dockerfile.worker -t orchka-worker .

Or run the whole stack, including Redis:

docker compose --profile app up -d

The app services sit behind an app profile, so docker compose up -d redis still starts infrastructure only for local development.

Both images carry Bun and Node: Bun runs the workspace, but next and prisma ship Node shebangs. They also install OpenSSL, which Prisma's query engine links against.

Migrations

Run them once, as a release or pre-deploy step, before the new version takes traffic:

cd packages/db && bunx prisma migrate deploy

Do not run migrations at build time. On most platforms the build step cannot reach the managed database — private networking is runtime-only. (prisma generate at build is fine; it needs DATABASE_URL to be set, not reachable.)

The Prisma client is generated during the image build, not committed, so a fresh clone needs bun run prisma:generate before it will build locally.

Render

A blueprint is committed at render.yaml. Dashboard → New → Blueprint, point it at the repo, and it proposes all four components.

CREDENTIAL_ENCRYPTION_KEY is declared in a shared environment group, so you enter it once and both services receive the same value — a mismatch between them is silent and makes credentials undecryptable. BETTER_AUTH_SECRET is generated for you.

After the first deploy, set BETTER_AUTH_URL to the assigned URL and register that callback in your GitHub and Google OAuth apps.

DigitalOcean App Platform

An app spec is committed at .do/app.yaml:

doctl apps create --spec .do/app.yaml

Set the secret values in the dashboard afterwards. CREDENTIAL_ENCRYPTION_KEY must be pasted identically into both the web and worker components — App Platform has no shared-group equivalent.

BETTER_AUTH_URL is wired to ${APP_URL}, so OAuth callbacks are the only URL you set by hand.

Check the Valkey eviction policy is noeviction after creation. BullMQ keeps in-flight job state there; on an evicting policy, jobs are discarded under memory pressure and workflows vanish mid-run with nothing in the logs.

Anywhere else

The Docker images run on Fly.io, ECS, Kubernetes, or a single VPS with docker compose. Four things carry over regardless of host:

  1. The worker gets no port and no HTTP health check.
  2. Redis must persist and must not evict. See Operations.
  3. Migrations run pre-deploy, not at build time.
  4. CREDENTIAL_ENCRYPTION_KEY must be byte-identical across both processes, and backed up somewhere you will still have it after a disaster.

Platforms that cannot run a long-lived background process — most "serverless" hosting — can serve the web half but not the worker.

Before real users

  • Set RESEND_API_KEY. Without it, password reset links are written to the server log rather than emailed, so nobody but you can recover an account.
  • Decide on email verification. See Security for the address-squatting window it closes.
  • Set ORCHKA_ADMIN_EMAILS, or /settings/engine is inaccessible to everyone.
  • Arrange Postgres backups and store the encryption key somewhere separate.

On this page