Skip to content

Securing your deployment

A hardening checklist for whoever runs a self-hosted FlowRunner: strong secrets, a locked-down database, HTTPS, an authenticated scheduler, and the protections the platform already runs for you.

FlowRunner keeps almost nothing outside MongoDB, so most of your security work is protecting two things well: the environment secrets the app boots with, and the database those secrets unlock.

Trust boundaries you control

1. Generate strong secrets and keep them out of git

Generate every secret with openssl — never reuse a value or paste one from an example.

VariableGenerateWhat it protects
AUTH_SECRETopenssl rand -base64 32Signs Auth.js session JWTs. Required — the app refuses to start without it.
SECRETS_KEYopenssl rand -base64 32Encrypts the per-workspace secrets vault (AES-256-GCM). Must decode to exactly 32 bytes.
CRON_SECRETopenssl rand -hex 32Authenticates the scheduler tick.

WARNING

Never commit these to git. Set them in your host's environment (Vercel project settings, container secrets, a secrets manager) and add .env* to .gitignore. A leaked AUTH_SECRET lets anyone forge sessions; a leaked SECRETS_KEY decrypts every stored secret.

assertEnv() hard-fails at boot only on AUTH_SECRET and MONGODB_URI. The optional keys log a warning and switch their feature off when absent — a missing SECRETS_KEY silently disables the vault rather than crashing. See Environment variables.

2. Lock down the database

The connection string is the keys to everything. Two operator-side controls that FlowRunner cannot enforce for you:

  • Use a least-privilege database user. Create a Mongo user with readWrite scoped to only the app's database — not root, dbAdmin, or a cluster-wide role. The app never needs admin rights, so a scoped readWrite user is best practice and limits the blast radius of a leaked MONGODB_URI.
  • Restrict network access. On Atlas, use Network Access → IP Access List to allow only your app hosts' egress IPs. On a self-hosted Mongo, bind it to a private network and firewall the port. Never leave the database open to 0.0.0.0/0.

3. Always serve over HTTPS

Terminate TLS at your proxy or platform edge and serve the app only over https://.

bash
AUTH_URL=https://app.example.com   # your public base URL
AUTH_TRUST_HOST=true               # required behind a proxy / hosted platform

AUTH_TRUST_HOST=true tells Auth.js to trust the forwarded host header from your proxy — without it, sign-in redirects and cookies misbehave. Plain HTTP would expose session cookies in transit.

4. Authenticate the scheduler

The scheduler tick (POST /api/cron/tick) is fail-closed: with no CRON_SECRET set it returns 401 and no schedule ever fires. When set, callers must send Authorization: Bearer $CRON_SECRET, and the app compares it with a constant-time check.

bash
curl -sS -X POST -H "Authorization: Bearer $CRON_SECRET" https://app.example.com/api/cron/tick

5. Back up the database and the key separately

A single mongodump (or Atlas continuous backup) captures everything — but the secrets collection holds only ciphertext, decryptable solely with the same SECRETS_KEY. Store that key in a separate secrets manager, versioned apart from the snapshot. Lose or rotate it and every stored secret is stranded. Full routine in Backup & restore.

6. Keep the components catalog on an origin you control

The editor loads node and component config UIs from a catalog origin (NEXT_PUBLIC_FORM_CATALOG_URL). Point it only at a host you operate.

NOTE

Today every built-in node and component is first-party, so production serves all of them from one trusted origin (components.flowrunner.io). That is safe because they are first-party. FlowRunner's design anticipates per-plugin origin isolation for third-party components, but that model assumes per-origin (wildcard-subdomain) hosting, which is not the current deploy — and executing untrusted third-party node logic server-side is not sandboxed yet (only first-party built-in nodes run in the engine). Until both land, do not point the catalog at an untrusted host. See The execution sandbox.

What the platform already enforces

You don't wire these up — they run automatically — but know they exist:

  • Rate limiting. A fixed-window limiter backed by the ratelimits collection guards login, form submissions, uploads, invites, and flow runs. Its TTL index reaps old counters.
  • Audit log. Security and administrative events (secret changes, membership changes, ownership transfers) are appended per workspace to the audit collection, best-effort so they never block the operation they record.

Hardening checklist

  • [ ] AUTH_SECRET, SECRETS_KEY, CRON_SECRET generated with openssl, never in git
  • [ ] Mongo user is readWrite on the app database only — not admin
  • [ ] Database network access restricted to your app hosts
  • [ ] AUTH_URL set and served over HTTPS with AUTH_TRUST_HOST=true
  • [ ] CRON_SECRET set so the scheduler is authenticated (fail-closed without it)
  • [ ] SECRETS_KEY backed up separately from the database
  • [ ] Components catalog points only at an origin you control

See also

FlowRunner — the no-code platform for small businesses.