Deploy with Docker¶
Bring up the whole self-hosted stack on one machine with a single command: the ingestlib app (its MCP server), the registry Postgres, a vector store, and an S3-compatible artifact store — pre-wired on one network.
The same code runs whether you pip install ingestlib into a single process,
bring up this Docker stack, or scale it out on Kubernetes — only the packaging
changes. This guide covers the Docker stack.
What comes up¶
docker compose -f infra/docker-compose.stack.yml --profile stack up starts:
| Service | Role | Port |
|---|---|---|
app |
the ingestlib MCP server (agents connect here) | 8000 |
registry |
ingestlib's metadata database (Postgres) | 5433 |
qdrant |
the vector store | 6333 |
minio |
the artifact store (document bytes), S3-compatible | 9000 · console 9001 |
The LLM and embeddings are a cloud API by key (OpenAI by default), so nothing heavy runs locally except — optionally — the OCR model (below).
1. Prerequisites¶
- Docker with Compose v2.
OPENAI_API_KEY(chat + embeddings),JINA_API_KEY(reranking), andMCP_TOKEN(any strong random string the MCP server requires for its bearer auth).- For parse only: an NVIDIA GPU (see OCR).
The app image is linux/amd64 (the layout model, paddlepaddle, ships no arm64 wheel); on an Apple Silicon host Docker builds and runs it under emulation.
2. Start it¶
export OPENAI_API_KEY=sk-...
export JINA_API_KEY=jina_...
export MCP_TOKEN=$(openssl rand -hex 32)
docker compose -f infra/docker-compose.stack.yml --profile stack up -d
The app entrypoint runs ingestlib registry init (the schema migrations) on
first boot, then serves the MCP server. Check health:
Connect any MCP client to http://localhost:8000 with the header
Authorization: Bearer $MCP_TOKEN. Or run the CLI inside the container:
docker exec -it ingestlib_app ingestlib doctor
docker exec -it ingestlib_app ingestlib ingest /path/in/container
Browse stored artifacts at the MinIO console: http://localhost:9001
(minioadmin / minioadmin).
OCR — the one GPU piece¶
Parse runs PaddleOCR-VL, a vision model that needs a GPU. On an NVIDIA host
with the nvidia-container-toolkit,
add the gpu profile to also run the OCR server:
The first run downloads ~1.8 GB of weights into a named volume (once). The app
reaches it at http://ocr:8111 — already wired in infra/deploy/config.yaml.
No NVIDIA GPU? The honest matrix:
| Host | parse | everything else |
|---|---|---|
| Linux + NVIDIA GPU | ✅ in-container | ✅ |
| macOS (Apple Silicon) | run OCR host-side (mlx-vlm), point paddle_vl.server_url at it |
✅ |
| CPU-only | ❌ unavailable | ✅ classify · split · extract · retrieve · SQL · MCP |
ingestlib doctor reports whether the OCR server is reachable; the rest of the
pipeline works regardless.
Configure it¶
Providers, stores, and rules live in infra/deploy/config.yaml (mounted at
/config). It defaults to OpenAI + qdrant + MinIO + Jina reranking. To change a
provider or store, edit that file — add any new key to the app's environment in
the compose — and recreate the app service.
Publishing / pulling the image¶
Release tags build and push the app image to GitHub Container Registry
(.github/workflows/docker-image.yml). To deploy a published image instead of
building locally, replace the app service's build: with
image: ghcr.io/<owner>/ingestlib-app:<version>.