Skip to main content

Running O2ID with Docker

O2ID publishes an official Docker image built from the same static binary the installer ships — every tagged release publishes a matching multi-arch (linux/amd64, linux/arm64) image to GitHub Container Registry:

docker pull ghcr.io/o2stack/o2id:latest
note

There is deliberately no o2idctl in this image. o2idctl is a client tool that talks over HTTP to whatever O2ID instance you point it at — it isn't a component of the running service, so it isn't bundled here. Install it separately via the installer wherever you run management commands from.

Required: the master key

O2ID's application-level encryption for connection secrets (see Managing Connections) requires O2ID_MASTER_KEY to be set — the server refuses to start without it, regardless of whether you use the Connections feature yet. Generate one and keep it somewhere durable (losing it makes any stored connection secrets unrecoverable):

openssl rand -hex 32

Running the container

docker run -d \
--name o2id \
-p 8080:8080 \
-e O2ID_MASTER_KEY=<your-generated-key> \
-v o2id-data:/var/lib/o2id \
ghcr.io/o2stack/o2id:latest
  • -v o2id-data:/var/lib/o2id persists the default SQLite database file across container restarts/recreations — omit it only for a throwaway instance. If you bind-mount a host directory instead of a named volume, make sure Docker is actually allowed to share that path (Docker Desktop and Rancher Desktop don't share /tmp by default on macOS — use a path under your home directory, or a named volume, to avoid data silently not persisting).
  • To use PostgreSQL or MySQL instead, mount your own o2id.toml over /etc/o2id/o2id.toml (see Storage) rather than the SQLite default baked into the image.

First run: setting up the platform admin

The first time O2ID starts against an empty database, it prompts on stdin for the platform admin's email and password (see Setting up the platform admin). In a container this means the first run needs stdin attached:

docker run -i --rm \
-p 8080:8080 \
-e O2ID_MASTER_KEY=<your-generated-key> \
-v o2id-data:/var/lib/o2id \
ghcr.io/o2stack/o2id:latest

Type the email and password when prompted (or pipe them, for scripted setup — the prompt falls back to plain-text stdin when it isn't attached to a real terminal):

printf '%s\n%s\n' admin@example.com 'a-strong-password' | \
docker run -i --rm \
-p 8080:8080 \
-e O2ID_MASTER_KEY=<your-generated-key> \
-v o2id-data:/var/lib/o2id \
ghcr.io/o2stack/o2id:latest

Once the platform admin exists (persisted in the mounted volume), every subsequent run can start normally detached (-d, no -i needed) — the prompt only appears when the user table is empty.

Verify it's running

curl http://localhost:8080/health

Building the image yourself

The Dockerfile at the repository root builds the same binary make service does, just inside a container:

docker build --build-arg VERSION=$(git describe --tags --always) -t o2id:local .

Configuration reference

SettingHow
Listen addressBaked in as --addr :8080; publish a different host port with -p <host>:8080 rather than changing this.
Config file (storage driver, external portal)Bind-mount your own file over /etc/o2id/o2id.toml — see Storage and Login Portal.
Master keyO2ID_MASTER_KEY environment variable — required, no default.
Data directory/var/lib/o2id (also the container's working directory, so a relative dsn in o2id.toml resolves here).