Skip to main content

Overview

The repository ships a multi-stage Dockerfile that compiles the standalone mirobody binary and produces a slim runtime image:
  1. builder — Ubuntu 24.04 with the full build toolchain and dev headers; compiles the mirobody executable from the system package set (vcpkg is Windows-only; Linux uses CMake find_package).
  2. runtime — Ubuntu 24.04 with only the shared libraries the binary actually links (extracted via ldd), plus CA certificates for outbound TLS.
The image bakes config.example.yml as the lowest-precedence defaults layer. Real settings come from environment variables or a config.yml you mount at /app/config.yml.
Mirobody ships as a single image you run against your own database (and, optionally, Redis) — there’s no bundled docker compose stack to stand up.

Build and run

1

Clone

2

Build the image

The image links the PostgreSQL backend by default. Choose a different SQL backend with a build arg:
3

Prepare config.yml

Edit config.yml and set at least one LLM key plus your database connection (see Database backend):
config.yml
4

Run

The image sets HTTP_PORT=80 internally and runs as an unprivileged user. Mount your config over the baked template:
The container listens on port 80; the example maps host port 80 to it. Open http://localhost.
5

Verify

Precedence inside the container is: environment variables → mounted config.yml → remote config → baked config.example.yml. You can therefore configure entirely via -e env vars instead of a file, e.g. -e GOOGLE_API_KEY=... -e PG_HOST=....

Database backend

The SQL backend is compiled into the binary, so it is fixed at image-build time.
The shipped Dockerfile installs libpq-dev for the PostgreSQL backends. To build MySQL / DuckDB images, add the matching -dev package to the apt-get install line in the Dockerfile first.

Cache (optional)

The server uses an in-process in-memory cache by default — no Redis needed for a single instance. To share cache state across replicas, run a Redis and set REDIS_HOST (and REDIS_PORT / REDIS_PASSWORD) in your config or via env vars.

Configuration via environment variables

Any config key can be overridden by an env var of the same name (highest precedence). Handy for secrets:

Management

Notes on the runtime image

The binary resolves res/htdoc (HTTP_ROOT) and res/sql relative to its working directory, so res/ and config.yml sit next to the binary under /app. The web client is served at the container’s port.
The runtime image installs nodejs so the server can auto-discover the Tanka QR-login signer at boot. If you don’t use Tanka, it’s dead weight — set TANKA_LOGIN_ENABLED=false (or TANKA_WASM_AUTODISCOVER=false).
The runtime image is libraries-only (no curl/wget), so there’s no built-in HEALTHCHECK. Under Kubernetes, use an httpGet liveness/readiness probe against /api/health.
The server image keeps PDF/OCR/.xls off to stay lean (.xlsx via xlnt is built in). To enable PDF/OCR, add the deps and CMake flags to the Dockerfile — see the comments in it and File Processing.

Troubleshooting

Remap the host side: docker run -p 8080:80 …, or change the internal port with -e HTTP_PORT=8080 and map to that.
Check docker logs <container> — the most common cause is a database it can’t reach (PG_HOST) or a missing/invalid PG_ENCRYPTION_KEY. Bad connection settings fail startup by design.
From the container, the host is host.docker.internal (Docker Desktop) — set PG_HOST to that rather than localhost.
For production hardening, see Production Deployment.