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:

VariableDefaultDescription
HOST0.0.0.0Container-internal bind address. Keep host port publishing loopback-only.
PORT3210HTTP port inside the container.
DATA_DIR/dataSQLite database, backups, and runtime data.
XDG_CONFIG_HOME/data/configPersisted settings directory inside the data volume.
HOME/dataWritable home directory for the non-root container user.
NODE_ENVproductionProduction error responses and logging defaults.
LOG_FORMATjsonStructured container logs.

AI and embedding execution uses persisted Settings UI/API values first. Environment variables are only first-start or unattended defaults.

VariableDescription
LLM_API_KEYSeeds OpenAI LLM execution and makes the default AI provider openai.
LLM_BASE_URLOptional OpenAI-compatible LLM endpoint override.
LLM_MODELDefault OpenAI LLM model.
EMBEDDING_API_KEYOptional embedding API key override. Falls back to LLM_API_KEY.
EMBEDDING_BASE_URLOptional OpenAI-compatible embedding endpoint override.
EMBEDDING_MODELDefault 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