Build and run the current checkout:
cd docker
docker compose up --buildTo run the configured image without rebuilding, use docker compose up --no-build.
Plain docker compose up may reuse or pull an image rather than rebuild local changes.
Then open http://localhost:18793. The local Compose default signs that browser in automatically so Settings > Models is immediately available.
One container, two processes:
| process | what it does |
|---|---|
nginx (:80) |
serves the built page from /app/ui-web/dist, proxies /rpc, /auth*, /health, /file, /files/, /oauth/callback to the engine |
| the Raven engine | the RPC gateway on 127.0.0.1:18793 inside the container |
They share a container because the engine binds loopback only
(web.TCPSite(runner, "127.0.0.1", port)), so a proxy in a second container
would have nothing to dial. The image builds the page in a Node stage and the
Python environment with uv sync --frozen, so both halves come from the same
commit.
The engine mints a session credential per boot and the page needs a cookie for
it. Compose defaults RAVEN_AUTO_LOGIN=1, so nginx gives a browser loading the
page that credential automatically. This is intended for a locally published
port.
For a remotely exposed deployment, put RAVEN_AUTO_LOGIN=0 in .env.local.
The entrypoint prints a one-time link on startup:
raven-docker: sign in once with this one-time link (replace localhost if you are remote):
http://localhost:18793/auth#<nonce>
The cookie it sets lasts 30 days, and survives a restart -- the engine reloads
the same cookie from /data rather than minting a new one.
The page's raven web advice is for a host install. In a container, mint
another one-time link with:
docker compose exec raven docker-entrypoint.sh signinThe engine starts with nothing configured. It says so on the way up:
! no provider is configured yet -- run `raven onboard` for guided setup
Starting anyway. Add a provider in Settings > Models on the page.
Add one in the page's Settings > Models and the next turn uses it -- the provider reads its credentials per call, so nothing needs restarting.
To have a deployment come up already configured, declare one in .env.local
instead:
RAVEN_PROVIDER=anthropic
RAVEN_API_KEY=sk-ant-...The entrypoint writes that into config on every boot, so where it is set it is the source of truth.
Local providers can be seeded by address without an API key:
RAVEN_PROVIDER=ollama-chat
RAVEN_API_KEY=
RAVEN_API_BASE=http://host.docker.internal:11434The container always runs raven gateway, including the page, RPC, IM
channels, cron, and the proactivity stack. Its resolving provider re-reads
credentials on every call, which is what makes a provider added in Settings
work on the next turn.
.env is committed and holds defaults. The service loads the optional,
git-ignored .env.local second for container runtime variables such as provider
credentials and RAVEN_AUTO_LOGIN. Put every credential in .env.local.
Compose interpolation is separate: RAVEN_IMAGE, RAVEN_WEB_PORT,
RAVEN_EXTRAS, RAVEN_PLUGINS, and RAVEN_OFFICE are resolved before the
container starts. Setting them only in the service's .env.local does not
override the image, published port, or build arguments. From this directory,
use shell variables, for example:
RAVEN_IMAGE=raven:local RAVEN_WEB_PORT=18893 docker compose up --buildOr, after creating .env.local, load it explicitly for interpolation too:
docker compose --env-file .env --env-file .env.local up --buildThe later file wins; shell environment values override both files.
Everything durable is under /data on the raven-data volume: config.json,
the workspace, sessions, logs and the memory store. Removing the container
keeps it; docker compose down -v does not.
Any argument that is not run or signin is handed to the raven CLI:
docker compose exec raven docker-entrypoint.sh provider test anthropic
docker compose run --rm raven status-
Exposure. The default Compose page automatically grants a Raven browser session to anyone who can reach its port, so the published port binds
127.0.0.1only. A remote deployment must choose its own bind or proxy and setRAVEN_AUTO_LOGIN=0. nginx also rewrites theOriginheader so the engine accepts a browser that reached it through a published port. That drops a defence-in-depth layer; the session cookie isSameSite=Strict, so an unauthenticated socket is still refused. Publish this port only where you would have published the engine's own. -
HTTPS. Not configured here. Terminate TLS in front of this container; the page picks
wss://fromlocation.protocolon its own. -
The TUI is not in this image.
raven tuineeds the Node bundle fromui-tui/, which the image does not build. -
sandbox. The extra is off by default: inside a container the container is the boundary. Turn it on withRAVEN_EXTRASif you want boxlite as well. -
LibreOffice is in the image. The gateway uses it to convert
.docx,.xlsx, and.pptxfiles to PDF for browser previews. LibreOffice and the CJK fonts add roughly 500 MB to the image. Build with--build-arg RAVEN_OFFICE=0, orRAVEN_OFFICE=0in the environment Compose reads, for a deployment that will never preview one. -
The tokenizer dictionary and the deepdoc models are in the image, about 160 MB. They are fetched at build time rather than at first use so the container needs no egress to read a PDF or to segment Chinese -- a deployment without it would otherwise fail the first time somebody uploaded one, long after the build that could have said so. Build with
--build-arg RAVEN_RESOURCES=0, orRAVEN_RESOURCES=0in the environment Compose reads, for a smaller image that does neither; both features report their own absence rather than failing obscurely.Before you push this image anywhere, read the "deepdoc models" section of
NOTICES.md. One of the four,layout.onnx, stampsAGPL-3.0into its own metadata underauthor: Ultralytics, and its metadata contradicts itself about that. Building the image here is your own fetch happening inside a container; pushing it to a registry, or shipping an appliance built from it, is redistribution, and that is where the question becomes yours to answer.RAVEN_RESOURCES=0is the build that carries none of them.