Odly
← All guides

Self-hosted

Self-host Odly

The Self-hosted plan (€3,000/mo)runs Odly entirely on your own infrastructure — your servers, your keys, your data. Nothing leaves your network, and Managed AI works with your own platform key. This guide takes you from an empty box to a running instance: the infrastructure it needs, the environment it validates at boot, the self-hosted knobs, the one-time bootstrap, and how updates & rollbacks work. It is a sales-assisted plan — contact Odly to get a license key first.
Setup

1 · Prerequisites & infrastructure

Odly ships as a small set of containers. The reference docker-compose.prod.yml wires them together for you.

  • PostgreSQL 16 with pgvector — the reference image is pgvector/pgvector:pg16. If you bring your own Postgres, it must be v16+ and you must enable the extension once: CREATE EXTENSION vector;
  • Valkey 8 — a Redis-compatible store used for the BullMQ job queues (async work, scheduled checks).
  • Backend container — image ghcr.io/orqesto/odly-backend:main. Budget roughly 3.5 GB of memory for it.
  • nginx — sits in front and terminates TLS. The backend, database and Redis all bind to loopback; only nginx is exposed to the network.
You don't have to assemble this by hand — the provided docker-compose.prod.yml already defines Postgres, Valkey and the backend with the right bindings. Run nginx (or your own reverse proxy) in front on the host to terminate TLS.

2 · Environment

Odly validates its configuration at startup and refuses to boot if anything required is missing or invalid. Set these before the first run — the authoritative template is .env.client.example.

  • LICENSE_KEYrequired in production. On a missing, invalid or expired key the app calls exit(1) and stops.
  • DATABASE_URL — in the reference compose this is built for you from DB_USER / DB_PASSWORD / DB_NAME, so don't set DATABASE_URL directly there.
  • JWT_SECRETmin 32 characters. Generate with openssl rand -base64 32.
  • ENCRYPTION_KEYmin 32 characters. Encrypts integration credentials at rest, so treat it like a root secret and never rotate it casually.
  • FRONTEND_URL — comma-separated list of allowed origins.
  • REDIS_HOST / REDIS_PORT / REDIS_PASSWORD — how the app reaches Valkey.
  • BACKEND_URL — recommended, so email-verification and password-reset links point back to the right host.

A minimal .env to boot:

# --- required in production ---
LICENSE_KEY=xxxxxxxx-your-license-key
DEPLOYMENT_MODE=self_hosted
SUBSCRIPTION_ENFORCEMENT_ENABLED=false

# database — compose builds DATABASE_URL from these
DB_USER=odly
DB_PASSWORD=change-me
DB_NAME=odly

# secrets — min 32 chars each (openssl rand -base64 32)
JWT_SECRET=REPLACE_WITH_32+_CHARS
ENCRYPTION_KEY=REPLACE_WITH_32+_CHARS

# origins & links
FRONTEND_URL=https://help.acme.com
BACKEND_URL=https://api.acme.com

# valkey / redis
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=change-me

# first-run admin (see step 4)
BOOTSTRAP_ADMIN_EMAIL=admin@odly.ai
BOOTSTRAP_ADMIN_PASSWORD=change-me-on-first-login

Full, commented reference: .env.client.example.

3 · Self-hosted mode & knobs

Setting DEPLOYMENT_MODE=self_hosted flips Odly out of its SaaS defaults so it behaves like software you own.

With DEPLOYMENT_MODE=self_hosted set, new workspaces default to the unlimited admin plan and land active with no trial — there is no 14-day expiry — and the billing / plan-catalog UI is hidden. Managed AI works using your own platform key, with no per-org entitlement to manage. BILLING_PROVIDER defaults to none, so there is no paywall.

Optional knobs

  • BEDROCK_ALLOW_INSTANCE_PROFILE — use EC2 instance-profile credentials for Amazon Bedrock instead of static keys.
  • INTEGRATIONS_ALLOW_PRIVATE_ENDPOINT / STORAGE_ALLOW_PRIVATE_ENDPOINT — relax the SSRF guard so Odly can reach private / loopback services on your own network. Self-host only.
The *_ALLOW_PRIVATE_ENDPOINT flags deliberately loosen a security guard. Enable them only when you truly need to reach a private endpoint, and only on an instance you fully control.

4 · First-run bootstrap

Once the containers are up and the environment validates, seed the instance a single time.

  1. Run npm run init:prod (a.k.a. seed:prod:bootstrap). It creates the plan catalog, one admin organization, one admin user, and the default departments.
  2. It uses BOOTSTRAP_ADMIN_EMAIL (default admin@odly.ai) and BOOTSTRAP_ADMIN_PASSWORD (default password123) for that first admin.
  3. Sign in and change the admin password immediately. The command is idempotent, so it's safe to re-run.
The default password123 is insecure by design — it only exists to get you in on the first boot. Change it on first login, or set your own BOOTSTRAP_ADMIN_PASSWORD before you bootstrap.

5 · Storage

Attachments and uploads land on local disk unless you point Odly at object storage.

By default files are written to local disk at /app/uploads. For S3-compatible object storage, set STORAGE_DRIVER=s3 together with the S3_* variables.

The S3 storage path is currently being cut over — treat it as advanced / optional. Local disk is the reliable default for a first deployment.

6 · Updates, migrations & rollback

Database migrations are automatic and forward-only; the update script health-gates every new release and can roll the image back on its own.

  • Migrations run on container start — automatically and forward-only. For schema changes use db:migrate; never db:push.
  • Auto-update — the selfhosted-autoupdate.sh script (suggested as a cron job every ~15 min) checks GHCR for a newer image, pulls it, redeploys, and health-gates the new version for up to 180s. If the new version doesn't come up healthy, it auto-rolls-back the image to the previous one.
  • Health & versionGET /api/health/version reports the running version and the deployment mode.
Image rollback does not undo a migration the failed release already ran. If a release includes a breaking migration, take a database backup before updating — rolling the container image back will not roll the schema back with it.
Back to all guides. Self-hosting is part of the €3,000/mo Self-hosted plan and is sales-assisted — contact Odly to get your license key. Commands and variable names are verified against the reference deployment.