app and worker containers — no embedded database — and an ekso.json with placeholder connection strings for you to fill in.
Pick this if you have a managed Postgres on AWS RDS / Azure Database / Supabase / Neon, a SQL Server estate with spare capacity, or strict policy that data lives in your existing instance. For a clean-slate install with no external dependencies, see Docker - full stack instead.
Prerequisites
- Docker Engine 20+ on Linux, Docker Desktop on macOS or Windows
-
An empty database on Postgres 16+ or SQL Server 2025, plus credentials with
CREATErights so Ekso can apply its schema on first boot -
pgvector installed on Postgres (one-time per database):
- A free license — fetch one at ekso.app/get-started
SQL Server 2025 is the minimum because Ekso uses native vector search. Earlier versions don’t have the required types and DiskANN index support.
Install
-
Download the bundle (
ekso-docker-byod.zip) from your welcome email. -
Unzip somewhere persistent. The zip contains
docker-compose.yml,ekso.json, and aREADME.md. -
Edit
ekso.json— fill in the connection strings for your database. The full schema is documented in the configuration reference; the relevant fields are underDatabase. The same two fields (TransactConnection+MartConnection) take connection strings in the dialect implied byProvider: Postgres example:SQL Server example: -
Bring it up:
The API auto-applies the schema on first boot. Allow 30–60 seconds for that plus image pulls.
-
Open the install URL to land in the first-run wizard:
Transact vs Mart connections
Ekso splits database access into two connection strings:| Connection | Purpose | When to point them differently |
|---|---|---|
Transact | OLTP — every live request hits this | Default — the live-work database |
Mart | Reporting, analytics, the Insights module | Point at a read replica when reporting load is heavy enough to bother the OLTP path |
Connection-string gotchas
| Symptom | Likely cause |
|---|---|
connection refused from app container | Database hostname resolves correctly inside Docker? Use the host’s network address, not localhost. |
permission denied on first boot | The Ekso user doesn’t have CREATE rights — schema apply fails. Grant CREATE ON DATABASE. |
extension "vector" does not exist | pgvector wasn’t installed before first boot. Run CREATE EXTENSION IF NOT EXISTS vector; and restart app. |
| TLS handshake errors against managed Postgres | Cloud providers usually require Ssl Mode=Require;Trust Server Certificate=true in the connection string. |
What’s running
Three containers:| Service | Image | Role |
|---|---|---|
app | eksoapp/app | REST API + UI on port 6050 |
worker | eksoapp/worker | Background jobs |
backup | alpine:3.20 | Daily snapshots of uploaded attachments |
docker-compose.yml:
| Folder | What’s in it | Whose responsibility |
|---|---|---|
./data/storage/ | Uploaded attachments | The bundle |
./backups/storage/ | Daily snapshots, retained for 14 days | The bundle |
| Your external database | All other Ekso data | You — back up with your existing DB tooling |
docker compose down -v reassurance — see Data management.
Updating
./data/ and ./backups/ folders are untouched, and the bundle never touches your external DB. See Upgrading for release cadence, version pinning, and the rollback procedure.