Docker Deployment Guide
July 20, 2026 ยท View on GitHub
This guide covers the supported Docker path for Grimoire: one local-only container that serves both the React frontend and the daemon API on port 3210.
Grimoire has scoped bearer-token authentication for local integration surfaces such as MCP, but the first-party browser app and general REST API still rely on the loopback trust boundary. Do not publish the daemon on a public interface unless you put it behind authentication, a VPN, or another trusted access control layer.
Prerequisites
- Docker Engine 20.10+
- Docker Compose v2 (
docker compose) - At least 2 GB RAM available
- 1 GB disk space for the image and local data
Quick Start
git clone https://github.com/goniszewski/grimoire.git
cd grimoire
docker compose up -d
Open http://127.0.0.1:3210.
The default Compose file publishes 127.0.0.1:3210:3210, so the container is
reachable from the host machine only. Inside the container, the daemon still
uses HOST=0.0.0.0 so Docker can forward the loopback-bound host port into the
container.
Docker Directly
docker build -t grimoire .
docker run -d \
-p 127.0.0.1:3210:3210 \
-v grimoire-data:/data \
--name grimoire \
grimoire
Open http://127.0.0.1:3210.
Configuration
The Docker image sets these runtime defaults:
| Variable | Default | Description |
|---|---|---|
HOST | 0.0.0.0 | Container-internal bind address. Keep host port publishing loopback-only. |
PORT | 3210 | HTTP port inside the container. |
DATA_DIR | /data | SQLite database, backups, and runtime data. |
XDG_CONFIG_HOME | /data/config | Persisted settings directory inside the data volume. |
HOME | /data | Writable home directory for the non-root container user. |
NODE_ENV | production | Production error responses and logging defaults. |
LOG_FORMAT | json | Structured container logs. |
AI and embedding execution uses persisted Settings UI/API values first. Environment variables are only first-start or unattended defaults.
| Variable | Description |
|---|---|
LLM_API_KEY | Seeds OpenAI LLM execution and makes the default AI provider openai. |
LLM_BASE_URL | Optional OpenAI-compatible LLM endpoint override. |
LLM_MODEL | Default OpenAI LLM model. |
EMBEDDING_API_KEY | Optional embedding API key override. Falls back to LLM_API_KEY. |
EMBEDDING_BASE_URL | Optional OpenAI-compatible embedding endpoint override. |
EMBEDDING_MODEL | Default embedding model. |
Additional LLM providers are configured through persisted Settings after startup: Anthropic, OpenRouter, custom OpenAI-compatible chat endpoints, and DeepSeek international each have separate API key, base URL, and model fields. Custom OpenAI-compatible embeddings use their own provider, API key, base URL, and model instead of sharing the selected LLM provider.
Example OpenAI override:
services:
grimoire:
environment:
- LLM_API_KEY=${OPENAI_API_KEY}
- LLM_MODEL=gpt-4o-mini
- EMBEDDING_API_KEY=${OPENAI_API_KEY}
- EMBEDDING_MODEL=text-embedding-3-small
Local Ollama
If you enable the optional Ollama service in docker-compose.yml, configure
Grimoire through Settings or the API after startup:
curl -X PUT http://127.0.0.1:3210/settings \
-H "Content-Type: application/json" \
-d '{
"ai": {
"provider": "ollama",
"ollama": {
"base_url": "http://ollama:11434",
"model": "llama3"
},
"embeddings": {
"provider": "ollama",
"model": "nomic-embed-text"
}
}
}'
The commented Ollama port mapping is loopback-only
(127.0.0.1:11434:11434) so local tools can still reach Ollama without
exposing it to the network.
Data and Backups
The grimoire-data volume contains the SQLite database, backups, and runtime
data. Prefer the in-app backup/restore flow for portable snapshots.
For emergency volume-level backup:
docker run --rm \
-v grimoire-data:/data \
-v "$PWD":/backup \
alpine tar czf /backup/grimoire-data.tar.gz /data
For emergency volume-level restore, stop Grimoire first:
docker compose down
docker run --rm \
-v grimoire-data:/data \
-v "$PWD":/backup \
alpine tar xzf /backup/grimoire-data.tar.gz -C /
docker compose up -d
Health and Logs
docker compose ps
docker exec grimoire curl -f http://localhost:3210/health
docker logs -f grimoire
The container health check calls http://localhost:3210/health from inside the
container. From the host, use http://127.0.0.1:3210/health.
Changing the Local Port
Keep the host address bound to 127.0.0.1 when changing ports:
services:
grimoire:
ports:
- "127.0.0.1:3211:3210"
Then open http://127.0.0.1:3211.
Remote Access
Grimoire is designed for local-first, single-user use. Integration token auth does not turn the daemon into a public server because most first-party REST routes remain loopback-trusted. Public reverse proxy examples are intentionally omitted. If you need remote access, put the service behind an authenticated tunnel, VPN, or reverse proxy that enforces authentication before traffic reaches Grimoire.
Do not use these unsafe port mappings:
ports:
- "3210:3210"
- "0.0.0.0:3210:3210"
Cleanup
docker compose down
# Deletes all Grimoire Docker data.
docker compose down -v
docker rmi grimoire