Overview
The repository ships a multi-stageDockerfile that compiles the standalone mirobody binary and produces a slim runtime image:
- builder — Ubuntu 24.04 with the full build toolchain and dev headers; compiles the
mirobodyexecutable from the system package set (vcpkg is Windows-only; Linux uses CMakefind_package). - runtime — Ubuntu 24.04 with only the shared libraries the binary actually links (extracted via
ldd), plus CA certificates for outbound TLS.
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
3
Prepare config.yml
config.yml and set at least one LLM key plus your database connection (see Database backend):config.yml
4
Run
The image sets The container listens on port 80; the example maps host port 80 to it. Open http://localhost.
HTTP_PORT=80 internally and runs as an unprivileged user. Mount your config over the baked template: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.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 setREDIS_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
Static assets and SQL live under /app
Static assets and SQL live under /app
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.Node is present for Tanka login
Node is present for Tanka login
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).No Docker HEALTHCHECK
No Docker HEALTHCHECK
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.Optional document formats are off
Optional document formats are off
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
Port conflict
Port conflict
Remap the host side:
docker run -p 8080:80 …, or change the internal port with -e HTTP_PORT=8080 and map to that.Container exits immediately
Container exits immediately
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.Can't reach a database on the host
Can't reach a database on the host
From the container, the host is
host.docker.internal (Docker Desktop) — set PG_HOST to that rather than localhost.