ekso.json is the single source of truth for install-time configuration. The bundle ships with a complete ekso.json pre-configured for the install path you picked — most customers never edit it. This page documents every field, what it does, and when you’d touch it.
ekso.json is intentionally minimal: just the cryptographic keys the app needs to boot before the database exists, plus the database connection string. Everything else — mail provider, storage backend, S3 credentials, SMTP password, AI keys, license activation — lives in the database and is configured via the Settings UI after first-run, with sensitive values encrypted at rest using the Secrets.EncryptionKey field below.
File layout
ekso.json lives next to docker-compose.yml in the bundle. Compose mounts it into both the app and worker containers. Edit, then docker compose restart to pick up changes.
The bundle ships two sibling folders alongside ekso.json: ./data/ (database files and attachments) and ./backups/ (automatic daily snapshots). Those are not configured here — they’re properties of the docker-compose.yml. See Data management for layout, retention, and restore details.
Sections
That’s it. There are no
Misc, Smtp, or Storage sections in ekso.json — those settings now live in the admin Settings UI. See Configure storage and email for the post-install walkthrough.
Secrets
| Field | Description |
|---|---|
Secrets.JwtKey | Symmetric secret used to sign user session JWTs. Pre-baked unique-per-download. Minimum 32 bytes of entropy. |
Secrets.EncryptionKey | AES-GCM key for encrypting admin-managed settings (S3 credentials, SMTP password, Resend API key, mailbox/ticketing creds). Pre-baked unique-per-download. Either a 32-character ASCII string OR base64-encoded 32 bytes (44 chars with = padding). |
The session-JWT issuer and audience are install-wide constants (both
"Ekso"). They are not configurable.Generating new keys
You don’t normally generate these yourself — every download from ekso.app ships anekso.json with both fields pre-populated, and the Render Blueprint mints them via generateValue: true. The recipes below are for the rare cases that genuinely need a fresh key: a planned rotation, an ekso.local.json for dev, or a custom orchestrator that bypasses the standard install flows.
Secrets.JwtKey — any string with at least 32 bytes of entropy. The Dotcom seeder uses 48 random bytes encoded as base64url:
Secrets.EncryptionKey — 32 random bytes, base64-encoded. The cipher accepts either form (32-char ASCII or base64-of-32-bytes); the base64 form is canonical and avoids the “did you mean 32 chars or 32 bytes” trap:
EksoCipher constructor refuses to boot on a missing or wrong-length EncryptionKey with a clear error — your Backend logs will tell you immediately if you’ve pasted the wrong value.
Database
| Field | Description |
|---|---|
Database.Provider | "Postgres" (recommended) or "SqlServer". Determines which dialect, driver, and Dapper type-handlers Ekso wires up against the connection strings below. |
Database.TransactConnection | OLTP connection string — the live-work database. pgvector required for AI features when using Postgres; SQL Server 2025 required for vector search when using SQL Server. |
Database.MartConnection | Reporting/analytics connection. Can point to the same instance as Transact for small installs; separate it onto a read replica for heavy reporting. |
Connection strings use the dialect implied by
Provider. Use Postgres key=value syntax (Host=...;Port=...;Database=...) when Provider = "Postgres"; use SQL Server syntax (Server=...;Database=...;User Id=...) when Provider = "SqlServer".Query timeout (300s), max pool size (100), and Postgres auto-prepare (off, PgBouncer-safe) are hardcoded. They were never customised per install, so they’re no longer config knobs.Override mechanisms
Outside Docker (Backend dev, custom orchestrators), .NET configuration binding accepts these alternatives, in increasing precedence:ekso.json— committed defaultekso.local.json— same directory, gitignored, for developer overrides- Environment variables — section separator is
__, e.g.Secrets__JwtKey,Database__TransactConnection
ekso.local.json for persistent dev overrides; ekso.json for the canonical install config. The Render Blueprint sets every field via env vars (Secrets via generateValue: true, Database via fromDatabase) — there’s no ekso.json on Render at all.
Settings not in ekso.json
Everything operational lives in the database and is configured via the Settings UI after first run, with sensitive values encrypted at rest usingSecrets.EncryptionKey:
- Outbound mail — Resend or SMTP credentials. See Configure storage and email for the walkthrough.
- Storage backend — Local filesystem or S3-compatible bucket (AWS S3, Cloudflare R2, Backblaze B2, MinIO). Same guide.
- AI providers and keys — OpenAI, Azure OpenAI, Anthropic. Per-tenant. See Settings → AI.
- License activation — pasted from your welcome email during the first-run wizard; rotates with the licence.
- Authentication providers (Entra SSO, password policies, 2FA) — see Authentication.
- Mailbox / ticketing config, rule webhooks, integrations — see the per-feature pages under Core concepts.