Skip to content
Back to home

§ DOCUMENTATION

Self-hosted deployment

Run the full Execlave governance platform on your own infrastructure using the published Docker images and a license key. Your data never leaves your network — the only thing that crosses the boundary is a license heartbeat (a fingerprint and a timestamp, no customer data).

§ 01

Data privacy: no external AI API calls by default

The default self-hosted deployment sends zero prompts, traces, or model inputs to any external AI provider. Semantic classification and policy generation run against a local LLM (Ollama or any OpenAI-compatible endpoint) configured via LOCAL_LLM_URL. If that endpoint is unreachable, those features gracefully degrade to deterministic heuristics — enforcement keeps working, you just lose the advisory classifications.

What this means for procurement reviews

  • Prompts and traces never leave your VPC.
  • No API keys for Anthropic, OpenAI, Google, or any other external LLM provider are required — or accepted — in the default configuration.
  • If you want to plug in an external provider for a specific workflow (e.g. using a hosted LLM for the policy-generation UI), you are responsible for the data-transfer compliance implications.
  • Optional product telemetry (PostHog, Accoil) is off by default. Leave the corresponding env vars blank to keep all analytics on-prem.
§ 02

Prerequisites

  • Linux host (any cloud or bare metal) with 4 CPU, 8 GB RAM minimum
  • Docker 24+ and Docker Compose v2
  • A PostgreSQL 15 instance — included in the compose file, or bring your own
  • A Redis 7 instance — included in the compose file, or bring your own
  • A license key (request one at /get-license)
  • Outbound HTTPS to license.execlave.com for heartbeat (air-gapped mode available — see §08)
§ 03

Quickstart

curl -O https://get.execlave.com/docker-compose.ymlexport LICENSE_KEY=exe_lic_<your-key>docker compose up -dopen http://localhost:3000

Four commands. The stack comes up in ~45 seconds on a modern host. Log in with the admin credentials printed in the startup output, or configure Logto.

§ 04

Get a license key

Free and paid self-hosted licenses are issued manually at this stage. Request one at /get-license.

  • Free plan: license arrives within 1 business hour
  • Paid plans: we reach out to set up payment first
  • Enterprise: we book a 30-min call

The license key is a JWT signed by our license server. The same key can be used on multiple instances up to the plan's instance limit (each distinct host fingerprint counts as one instance).

§ 05

Architecture

Everything runs inside your network. The only outbound traffic is the license heartbeat.

+-------------------------------------------------+|                Your infrastructure              ||                                                 ||   +---------+   +---------+   +-----------+    ||   | Next.js |-->| Express |-->| Postgres  |    ||   | (3000)  |   |  (4000) |   |  (5432)   |    ||   +---------+   +---------+   +-----------+    ||                      |                          ||                      v                          ||                 +---------+   +-----------+    ||                 | Worker  |-->|   Redis   |    ||                 | (BullMQ)|   |  (6379)   |    ||                 +---------+   +-----------+    ||                                                 ||   +-------------------+                         ||   |  Processing       |                         ||   |  (Python/FastAPI) |                         ||   +-------------------+                         |+-------------------------------------------------+         |         | outbound HTTPS only (heartbeat)         v+-----------------------------+| license.execlave.com        || (fingerprint + timestamp)   |+-----------------------------+
§ 06

Configuration

Required environment variables

VariableDescription
LICENSE_KEYThe JWT license key we email you
DEPLOYMENT_MODESet to self-hosted (controls license-client activation)
DATABASE_URLPostgreSQL connection string
REDIS_URLRedis connection string
LOGTO_ENDPOINTLogto endpoint (backend)
LOGTO_APP_IDLogto dashboard client app ID (backend)
LOGTO_APP_SECRETLogto dashboard client app secret (backend)
NEXT_PUBLIC_LOGTO_ENDPOINTLogto endpoint (frontend)
NEXT_PUBLIC_LOGTO_APP_IDLogto dashboard client app ID (frontend)

Optional environment variables

VariableDefaultDescription
LICENSE_SERVER_URLhttps://license.execlave.com/apiOverride for air-gapped proxies
LICENSE_CACHE_PATH~/.execlave/Where the license client caches the validated license
LICENSE_HEARTBEAT_INTERVAL_MS86400000How often to check in with the license server (default 24h)
LOCAL_LLM_URLunsetURL for local LLM service for semantic classification + policy generation
STRIPE_SECRET_KEYunsetNot used in self-hosted mode
SENTRY_DSNunsetOptional error tracking
§ 07

License keys: how they work

The license key is a signed JWT. When your instance starts:

  1. Startup validation — the license client verifies the JWT signature against our public key (bundled in the image) and checks the plan, expiry, and instance limits.
  2. Instance registration — your instance's host fingerprint (hash of hostname + MAC + Docker-Compose project name) is registered with the license server.
  3. Cached offline mode — the validated license is cached locally so the instance can boot even if the license server is unreachable.
  4. Heartbeat — every 24 hours, the instance sends a heartbeat containing its fingerprint and a timestamp. No customer data is included.
  5. Grace period — if the license server is unreachable for 14 consecutive days, the instance enters grace mode and logs a warning. After 21 days, enforcement is paused pending reconnection.
What we see: {fingerprint, timestamp, license_id, version}
What we don't see: prompts, traces, agents, policies, users, or any customer data whatsoever.
§ 08

Updating, backups, and air-gapped mode

Updating

Pull the latest images and restart:

docker compose pulldocker compose up -d

Database migrations run automatically on startup. Always take a backup first.

Backups

Back up the Postgres volume and the license cache:

docker compose exec postgres pg_dump -U execlave execlave > backup.sqldocker cp $(docker compose ps -q backend):/root/.execlave/ ./license-cache

Restoring from a backup regenerates the host fingerprint on first boot and re-registers with the license server.

Air-gapped mode

If your environment cannot reach license.execlave.com:

  1. Contact us to request an offline license bundle — a JWT with a longer offline grace window (typically 1 year).
  2. Set LICENSE_SERVER_URL to an internal proxy that queues heartbeats and replays them during a periodic sync window, OR
  3. Drop heartbeat altogether with LICENSE_HEARTBEAT_INTERVAL_MS=0 if you have an offline license.

Offline bundles are gated on a signed support agreement; email support@execlave.com for details.

§ 09

Troubleshooting

Backend won't start: "License validation failed"
  • Confirm LICENSE_KEY is set correctly in the environment
  • Check the JWT hasn't expired: echo $LICENSE_KEY | cut -d. -f2 | base64 -d
  • Verify outbound HTTPS to license.execlave.com is allowed
"Instance limit exceeded"
  • Your license plan caps the number of concurrent host fingerprints
  • Delete stale instances via the license server or upgrade your plan
Heartbeat failing but instance still running
  • This is expected during the 14-day grace period — a warning is logged
  • Check docker compose logs backend | grep -i license for the exact error
Migration errors on first start
  • The stack runs all pending migrations on boot. If a migration fails, restore from your backup and contact support.
§ 10

Support