Docker
Requirements
One container, one process tree. Measured on ghcr.io/ahmadrosid/nakama:latest
(v0.4.20) with no LLM provider and no channel workers:
| Image on disk | 734 MB |
| Memory, idle | ~200 MB |
| Memory, serving chat | ~240 MB |
| Memory, automation worker also running | ~247 MB |
Boot to /health | 3 to 5 seconds |
| Data directory on first boot | 1.2 MB |
It starts and serves on 1 vCPU and 1 GB. It also starts under a 512 MB cap, using 221 MB, but that leaves nothing for the rest of the box.
Three things raise the figure and are not in the table:
- Channel workers. Telegram, WhatsApp, and Discord each run as their own process next to the server. WhatsApp carries Baileys and libsignal and is the heaviest of the three. Size for them separately if you enable them.
- A configured provider. The numbers above come from offline mode, so no model traffic passed through the container.
- The MicroSandbox bash backend, which needs a working hypervisor at
/dev/kvm. Most small VPS plans do not expose it. See MicroSandbox bash backend.
Quick run
Pull the prebuilt image and start Nakama:
docker pull ghcr.io/ahmadrosid/nakama:latest
docker run -d -p 4310:4310 -v nakama-data:/nakama/data --name nakama ghcr.io/ahmadrosid/nakama:latestOpen http://localhost:4310. The container serves the API, web dashboard, and platform workers together.
Data is stored at /nakama/data inside the container. The -v nakama-data:/nakama/data volume persists orgs, profiles, sessions, provider settings, and the local SQLite database across restarts.
Build from source
From the repository root:
./scripts/docker-build-run.shThe script uses docker buildx (default linux/amd64), then starts the container.
The build helper reads these optional environment variables:
NAKAMA_CONTAINER_NAMEsets the container name. The default isnakama.NAKAMA_IMAGE_NAMEsets the local image name. The default isnakama.NAKAMA_HOST_PORTsets the published host port. The default is4310.NAKAMA_DATA_VOLUMEsets the Docker volume name. The default isnakama-data.
For example, this builds and starts an isolated local install on port 4311:
NAKAMA_CONTAINER_NAME=nakama-dev \
NAKAMA_IMAGE_NAME=nakama-dev \
NAKAMA_HOST_PORT=4311 \
NAKAMA_DATA_VOLUME=nakama-dev-data \
./scripts/docker-build-run.shConfiguration
The data root follows NAKAMA_CONFIG_DIR when set. If you set it, use an
absolute path. Nakama rejects relative paths because they depend on the process
working directory and can break profile isolation. The default inside the
container is /nakama/data, which maps to the nakama-data volume. The build
helper always mounts its data volume at /nakama/data.
On first run, complete the setup wizard in the browser and add your LLM provider. See Providers and First-time setup.
Logs and monitoring
Use readiness checks to keep traffic away from an unavailable database, and request IDs to connect an HTTP response with its logs.
- Set
NAKAMA_LOG_FORMAT=jsonfor JSON lines on standard output.NAKAMA_LOG_LEVELacceptsdebug,info(default),warn,error, orsilent. These settings cover HTTP request logging and the initial worker lifecycle events; other existing logs remain unchanged. - HTTP responses include
X-Request-Id. Nakama honors incoming IDs up to 255 characters or generates one. Response logs include this ID, method, status, and duration;debugalso logs request start. URLs, request bodies, and credentials are not included in these HTTP logs. Streaming durations measure response setup, not the whole stream. - Use
/healthzfor liveness and/readyzfor readiness on port 4310. Readiness returns 200 when the active connection can read the migrated database, or 503 when unavailable. It does not track restore progress and can remain ready while the old connection is still usable. Neither probe needs login or checks external providers or worker connectivity. The existing/healthbehavior is unchanged. - Set
NAKAMA_METRICS=trueto enable/metrics; otherwise it returns 404. It serves Prometheus-format HTTP response and server-error counters, which reset on process restart. Nakama sends nothing to an external collector. The endpoint needs no login and uses the same listener as the dashboard: restrict access through your network or reverse proxy before enabling it.
HTTPS and session cookies
On HTTPS, the session and CSRF cookies are issued as __Host-nakama_session and __Host-nakama_csrf. Browsers bind those to the exact host, so a sibling host under the same parent domain cannot plant or overwrite a session.
- A proxy that terminates TLS must send
X-Forwarded-Proto: https, otherwise Nakama treats the request as plain HTTP, issues the unprefixednakama_sessionandnakama_csrfcookies, and loses the host binding. - Unprefixed cookies are ignored on HTTPS, so the first sign-in after upgrading happens once more. Signing in again reissues the host-bound pair and clears the old cookies.
- Plain HTTP deployments keep the unprefixed cookies, because browsers discard
Securecookies onhttp://origins.
First-boot seed (optional)
To skip the setup wizard on a fresh data volume, set all three admin seed variables before the first boot. Nakama creates the admin account and a Personal org (override with NAKAMA_SEED_ORG_NAME). No provider is created: after the first login, open /setup to add one. Self-hosted installs without these variables behave as today.
| Variable | Required | Purpose |
|---|---|---|
NAKAMA_SEED_ADMIN_EMAIL | Yes (with the other two) | Platform admin email |
NAKAMA_SEED_ADMIN_NAME | Yes (with the other two) | Platform admin display name |
NAKAMA_SEED_ADMIN_PASSWORD | Yes (with the other two) | Platform admin password (min 8 characters) |
NAKAMA_SEED_ORG_NAME | No | Organization name (default Personal) |
Partial seed config fails boot with a clear error. Restarting a seeded instance is a no-op (idempotent).
docker run -d -p 4310:4310 -v nakama-data:/nakama/data \
-e NAKAMA_SEED_ADMIN_EMAIL=admin@example.com \
-e NAKAMA_SEED_ADMIN_NAME=Admin \
-e NAKAMA_SEED_ADMIN_PASSWORD=seedpass123 \
--name nakama ghcr.io/ahmadrosid/nakama:latestReset a local Docker install
To remove the default local resources and start fresh:
./scripts/docker-destroy.sh
./scripts/docker-build-run.shThe reset script removes the container named nakama, every container that
publishes port 4310 (including unrelated containers), the nakama-data and
nakama-config volumes, and the local image named nakama. Stop any unrelated
containers before running it if you still need them.
The script does not remove the cached
ghcr.io/ahmadrosid/nakama:latest image. It also uses the default names, so
custom names set through the build helper can remain unless you remove them
yourself.
Optional: CloakBrowser with agent-browser
The image does not include CloakBrowser. Stock Chrome from agent-browser install still works inside the container when you use the dashboard Install path.
To use Cloak as the Chromium behind agent-browser, bind-mount the Cloak binary and pass the same host env Nakama's bash tool already inherits:
docker run -d -p 4310:4310 -v nakama-data:/nakama/data \
-v /path/to/cloak-chromium:/cloak/chromium:ro \
-e AGENT_BROWSER_EXECUTABLE_PATH=/cloak/chromium \
-e AGENT_BROWSER_ARGS="<copy from Cloak's agent-browser example>" \
--name nakama ghcr.io/ahmadrosid/nakama:latestSee Agent browser.
Optional: MicroSandbox bash backend
Stock docker run / ./scripts/docker-build-run.sh does not pass /dev/kvm (or nested virtualization). Keep NAKAMA_BASH_BACKEND=host (the default) inside Docker unless you deliberately add hypervisor access.
In Docker, host Bash runs inside the Nakama container with the server process's OS permissions. It can access mounted data outside the active profile workspace, including other profiles' files when permissions allow. The shared container does not isolate profiles from each other. Assign host Bash only to trusted profiles.
If you set NAKAMA_BASH_BACKEND=microsandbox without a working MicroSandbox runtime / KVM device, every bash tool call fails closed — there is no silent host fallback. Coding-agent harness runs require host for now. See Choose a MicroSandbox image for custom image setup.
Next steps
- Deployment hardening — keep port 4310 private and protect the data root
- Outbound connections — plan egress for enabled providers, channels, and tools
- Quickstart — first-run flow from zero
- Backup and restore — export and restore your data root
- Providers — LLM API keys and models