Installation
OtoDock is self-hosted: you run it on your own Linux server. This guide gets a working instance up and serving its dashboard with one short install script. When you're done, head to First run to create your account and chat with your first agent. (Developing OtoDock, or prefer to build what you run? See From source at the end.)
Prerequisites
- A Linux server — Debian 12 or Ubuntu 22.04 LTS (or newer). 4 GB RAM is the minimum; more is recommended for multi-user installs and parallel agent sessions — especially if your agents use the heavier Docker MCP sidecars (the Camoufox browser, file tools). See How much RAM? below for what fits.
- Docker and the Docker Compose plugin — if the server doesn't have them yet,
install Docker Engine first (Debian/Ubuntu
shortcut:
curl -fsSL https://get.docker.com | sh, thensudo usermod -aG docker $USERand log back in). The install script checks for it and stops with the same instructions if it's missing.
That's all — the OtoDock image ships with everything else baked in (the AI CLIs, the sandbox runtime, the toolchain agents use).
Install
Create a folder for the install, then run the script in it:
mkdir otodock && cd otodock
curl -fsSLO https://raw.githubusercontent.com/OtoDock/oto-dock/main/scripts/install.sh
bash install.sh
The installer is a short, commented script built to be read. It checks Docker, writes a
.env with a generated database password, handles the Ubuntu 24.04+ host step
automatically when the host needs it (the one step that may ask for sudo), downloads the
release-pinned docker-compose.yml, and starts the stack. Everything lands in the folder
you run it from, and it performs fresh installs only — it stops rather than touch an
existing install.
That one .env file is the whole configuration: on first boot OtoDock generates its
remaining secrets and appends them there, your data lives in named Docker volumes, and the
compose file pins the release it shipped with — upgrading later is a one-line version bump
(see Upgrading & backups). Every optional knob is documented
in the Configuration reference.
When it finishes, skip ahead to Verify it's running. If your users
will browse to the server by name or IP rather than localhost, set the public URL in the
generated .env (its comments show where):
# .env
DASHBOARD_PUBLIC_URL=http://your-server:8400 # the address your users browse to
TZ=Europe/Athens # optional — scheduled tasks and
# notification times use this
…then apply it:
docker compose up -d
If your team signs in through an identity provider (Authentik, Keycloak, Entra ID, …), add
the OIDC_* settings to the same .env —
Users & Access shows the exact
lines. You can also do this later; local accounts work out of the box.
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.
Day-to-day, two commands cover operations (run them next to the compose file):
docker compose logs -f otodock-proxy # follow the server logs
docker compose down # stop the stack (your data stays in its volumes)
Reverse proxy & HTTPS
For anything beyond a local trial, front port 8400 with a reverse proxy (Caddy, nginx,
Traefik) or a tunnel that terminates TLS. 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. Then tell OtoDock about the proxy in .env:
# .env — both required when OtoDock sits behind a reverse proxy
DASHBOARD_PUBLIC_URL=https://otodock.example.com # the public address
TRUSTED_PROXY=10.0.0.5 # your reverse proxy's IP
DASHBOARD_PUBLIC_URL drives login cookies, OAuth redirects, and links in notifications —
and with it set, in-chat artifacts and mini-apps stay correctly sandboxed on that address
even if a hop drops X-Forwarded-Proto. TRUSTED_PROXY (plain IPs or CIDRs,
comma-separate several) lets OtoDock see each visitor's real address through the proxy —
the login protections (rate limits, the local-network-only sign-in restriction) depend
on it.
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.