Installation
OtoDock is self-hosted: you run it on your own Linux server. This guide gets a working instance up and serving its dashboard. When you're done, head to First run to create your account and chat with your first agent.
Prefer to watch first? Here's the whole install, uncut, with an honest clock — under three minutes from empty directory to the dashboard:
Two ways to install
| Method | What it is | Best for |
|---|---|---|
| Docker Compose (recommended) | The official OtoDock images from GHCR, brought up with one compose file and one command. No repository checkout needed. | Everyone. The fastest, most reproducible path. |
| From source | Clone the repository and either build the same container stack locally, or run the server natively on the host. | Developers and contributors. |
Both run the same software.
Docker Compose (recommended)
Prerequisites
- A Linux server — Debian 12 or Ubuntu 22.04 LTS (or newer). 4 GB RAM is a comfortable minimum — see How much RAM? below for what fits.
- Docker and the Docker Compose plugin.
That's all — the OtoDock image ships with everything else baked in (the AI CLIs, the sandbox runtime, the toolchain agents use).
Step 1 — Get the compose file
Pick a directory for your install and download the compose file into it:
mkdir -p /opt/otodock && cd /opt/otodock
curl -fsSLO https://raw.githubusercontent.com/OtoDock/oto-dock/main/docker-compose.yml
Step 2 — Create your .env
Create a .env file next to the compose file. This one file is OtoDock's configuration:
Compose reads it automatically (no --env-file flag needed), and the server keeps its own
generated secrets in it too.
cat > .env <<EOF
# Required — the bundled PostgreSQL initialises with this password on first run.
POSTGRES_PASSWORD=$(openssl rand -hex 24)
# The URL your users will browse to. Drives login cookies, OAuth redirects,
# document preview, and links in notifications. Leave as-is for a same-host trial.
DASHBOARD_PUBLIC_URL=http://localhost:8400
# Container timezone — scheduled tasks and notification times use this.
TZ=Europe/Athens
EOF
chmod 600 .env
That is genuinely all most installs need. On first boot OtoDock generates its remaining secrets (API key, signing keys, push-notification keys) and appends them to this same file, so they survive restarts and upgrades. Every other knob is optional and documented in the Configuration reference.
If your team signs in through an identity provider (Authentik, Keycloak, Entra ID, …), add
the OIDC_* settings to the same .env — see
Users & Access. You can also do this later; local
accounts work out of the box.
Step 3 — Start it
docker compose up -d
The first run pulls the pinned release images and starts the full stack: the OtoDock server (dashboard included), PostgreSQL, document preview, and the supporting services. Your data lives in named Docker volumes (database, agent files, sessions), so stopping and restarting the stack keeps everything intact.
docker compose logs -f otodock-proxy # follow the server logs
docker compose down # stop the stack
The compose file pins the OtoDock release it shipped with, so installs are reproducible. To
run a different release, set OTODOCK_VERSION in .env — and see
Upgrading & backups for the update flow. Release notes live on
the GitHub Releases page.
How much RAM?
OtoDock admits agent sessions based on live free memory, so a full box politely asks you to retry instead of crashing — but the ceiling is set by your RAM. Rough guide for concurrent Claude Code / Codex CLI sessions (each grows to roughly 1 GB with a full context; the same numbers apply to Docker Compose and source installs):
| Server RAM | Concurrent sessions | …alongside a heavy Docker MCP (e.g. the browser) |
|---|---|---|
| 4 GB | ~3 | ~2 |
| 8 GB | ~5–6 | ~4–5 |
| 16 GB | ~10–12 | ~9–11 |
| 32 GB | 20+ | 19+ |
The estimates behind these numbers are tunable in .env (see the comments in
config.env.example).
Verify it's running
OtoDock serves both its API and dashboard on port 8400 by default.
curl http://localhost:8400/health # → ok
Then open http://<your-server>:8400 in a browser. A fresh install greets you with the
setup wizard — continue to First run.
Put it behind HTTPS
For anything beyond a local trial, front port 8400 with a reverse proxy (Caddy, nginx,
Traefik) or a tunnel that terminates TLS, and set DASHBOARD_PUBLIC_URL to the public
https:// address. Forward the standard headers on every hop — at minimum Host, plus
X-Forwarded-Proto from the hop that terminates TLS — so OtoDock knows how the browser
reached it. (With DASHBOARD_PUBLIC_URL set, in-chat artifacts and mini-apps stay correctly
sandboxed on that address even if a hop drops X-Forwarded-Proto.)
If you put OtoDock behind a gateway that forces a login on every request (Authentik, Authelia, oauth2-proxy, Cloudflare Access), a few paths must skip that login — the clients calling them authenticate themselves and can't complete a browser login:
^/ui-kit/— the styling and chart libraries that in-chat artifacts and mini-apps load. These render in a hard security sandbox that deliberately sends no cookies, so a forced-login gateway silently blocks them and agent-built dashboards come out unstyled. The files are public static assets (fonts, CSS, chart libraries) — safe to exempt.^/v1/webhooks/— every incoming trigger fire and every integration event (the vendor webhook receivers). OtoDock authenticates these itself with keys and signed requests./ws/— the live dashboard connection. Make sure your proxy forwards WebSocket upgrades; with strict forced-login gateways, exempt this path from the login redirect too (a WebSocket handshake can't follow one) — OtoDock authenticates the socket itself with your logged-in session.^/v1/images/temp/— only if you use reverse image search: the search vendor fetches the photo through a short-lived, random tokenized URL and has no browser session./favicon.png— the browser fetches the icon before the login redirect completes; a public static icon, safe to exempt.
Everything else — the dashboard and all management endpoints — stays behind your gateway. The full recipe, including a couple of niche paths some MCPs use, is in API & Webhooks.
OtoDock pins its own internal Docker subnets, so no host Docker daemon changes are needed. If
the defaults (10.200.0.0/24 and 10.201.0.0/16) overlap your LAN or VPN, override
OTODOCK_NETWORK_SUBNET / OTODOCK_MCP_ADDRESS_POOL in .env.
From source (developers & contributors)
Everything above runs the published images. If you're developing OtoDock — or just prefer to build what you run — clone the repository and use the source flow.
Containerised, built from source
Needs only Git and Docker — everything builds inside the containers:
git clone https://github.com/OtoDock/oto-dock.git
cd oto-dock
printf 'POSTGRES_PASSWORD=%s\n' "$(openssl rand -hex 24)" > config.env
scripts/compose.sh up -d --build
scripts/compose.sh stacks the build overlay (docker-compose.build.yml) on the same base
compose file, with the base images pinned from VERSIONS.md. It builds exactly what your
working tree contains — so updating is just git pull and re-running the same command.
The source flow keeps its settings in config.env at the repository root (same contents and
behaviour as .env above).
Native (bare-metal development)
The server can also run directly on the host — this is how OtoDock itself is developed. One
idempotent bootstrap script stands up the whole environment: the pinned toolchain from
VERSIONS.md (Python, Node, uv, pnpm), the sandbox runtime, Docker, the server's virtualenv
and config.env, PostgreSQL in a container (loopback-only), and a dashboard build:
git clone https://github.com/OtoDock/oto-dock.git
cd oto-dock
scripts/dev-setup.sh
Then run it — foreground while you're hacking on the code, so logs and restarts are right in your terminal:
cd proxy && venv/bin/python app.py # the server (serves the built dashboard too)
cd dashboard && npm run dev # optional second terminal: hot-reload dashboard
If the box doubles as a long-running instance, register it as a systemd service instead — the bootstrap generates the unit for your checkout path and user, enables it, and starts it:
scripts/dev-setup.sh --service
Updating is git pull, re-running scripts/dev-setup.sh (it reconciles the toolchain and
dependencies, never overwrites your secrets), and restarting the server.
Per-agent storage quotas enforce limits as warnings on any setup, but hard enforcement (blocking writes past a cap) needs a native install on an XFS volume with project quotas. A Docker Compose deployment always uses the warning-only tier. See Usage & limits.
Next steps
- First run → — create your administrator account and meet your pre-installed assistant.
- Connecting your AI → — plug in the Claude, ChatGPT, or other models your agents will run on.
- Upgrading & backups → — keep your instance current and your data safe.