# How to Deploy Headroom in Docker Using Docker-Compose: Complete Setup Guide

> Deploy Headroom in Docker with docker-compose. Clone the repo and run a single command to set up the Headroom proxy service with Qdrant and Neo4j databases.

- Repository: [Tejas Chopra/headroom](https://github.com/chopratejas/headroom)
- Tags: how-to-guide
- Published: 2026-06-04

---

**Deploy Headroom by cloning the chopratejas/headroom repository and running `docker compose up --build -d`, which builds a multi-stage image and orchestrates the Headroom proxy service with Qdrant and Neo4j databases.**

Headroom is an open-source knowledge management system that packages its Rust-based core and Python proxy into a production-ready container. To **deploy headroom in docker using docker-compose**, you leverage a multi-stage build process that isolates compilation dependencies from the runtime environment, resulting in a minimal, secure image. This guide walks through the architecture, configuration files, and deployment commands using the actual source implementation from the repository.

## Understanding the Multi-Stage Dockerfile

The `Dockerfile` at the repository root implements a multi-stage build strategy that separates the heavy build environment from the lightweight runtime. This approach minimizes the final image size and attack surface while ensuring the Rust extensions compile correctly.

### The Builder Stage

The `builder` stage (lines 6-53) uses `python-slim` as its base image and handles all compilation tasks:

- Installs system dependencies including `build-essential`, `g++`, `curl`, and `patchelf`
- Utilizes the `uv` package manager to install Python dependencies and build the `headroom[proxy,code]` wheel in a single step
- Compiles the Rust-based `_core` extension from source
- Executes a smoke test to verify the compiled extension before proceeding to the runtime stage

### The Runtime Stage

The final stage defaults to `runtime-slim-base` (lines 63-99) and creates the production-ready image:

- Copies only the compiled site-packages from the builder stage, discarding the Rust toolchain and build tools
- Creates a non-root user for security isolation
- Exposes port **8787** and configures a health check endpoint at `http://127.0.0.1:8787/readyz`
- Sets the entrypoint to execute `headroom proxy`

## Docker-Compose Architecture

The [`docker-compose.yml`](https://github.com/chopratejas/headroom/blob/main/docker-compose.yml) file orchestrates three interconnected services that form the complete Headroom stack according to the source definitions (lines 1-50).

### Core Services

- **headroom-proxy**: Built from the repository `Dockerfile`, this service exposes the Headroom API on port 8787 and depends on both databases
- **qdrant**: Vector database container providing semantic search capabilities through persistent storage
- **neo4j**: Graph database container handling knowledge graph storage and relationship queries

### Networking and Persistence

Docker Compose automatically creates a dedicated bridge network allowing services to communicate via internal hostnames (`qdrant` and `neo4j`). Both database services mount persistent Docker volumes—`qdrant_data` and `neo4j_data`—ensuring data survives container restarts.

## Step-by-Step Deployment

Follow these commands to deploy the complete stack from source:

1. Clone the repository and change to the project directory:

```bash
git clone https://github.com/chopratejas/headroom.git
cd headroom

```

2. Build the images and start all services in detached mode:

```bash
docker compose up --build -d

```

3. Verify the Headroom service is running by streaming logs:

```bash
docker compose logs -f headroom-proxy

```

4. Confirm the installation by checking the version inside the container:

```bash
docker compose exec headroom-proxy headroom version

```

## Managing the Deployment

Use these commands for common operational tasks:

- **Stop services**: `docker compose down`
- **Stop and remove data volumes**: `docker compose down -v`
- **View service status**: `docker compose ps`
- **Restart single service**: `docker compose restart headroom-proxy`

## Customization Options

### Custom LLM Endpoints

To point Headroom to a custom OpenAI-compatible API instead of the default, uncomment and configure the `OPENAI_TARGET_API_URL` environment variable in the `headroom-proxy` service definition within [`docker-compose.yml`](https://github.com/chopratejas/headroom/blob/main/docker-compose.yml).

### Runtime User Configuration

By default, the container runs as a non-root user for security. To override this during the build process, pass the build argument:

```bash
docker compose build --build-arg RUNTIME_USER=root headroom-proxy

```

### Distroless Base Image

For minimal security-focused deployments, modify the final stage in the `Dockerfile` to use `runtime-slim` (distroless base) instead of `runtime-slim-base`, then rebuild with `docker compose build`.

## Summary

- Headroom uses a multi-stage `Dockerfile` that compiles Rust extensions in an isolated builder stage before copying artifacts to a minimal runtime image exposing port 8787
- The [`docker-compose.yml`](https://github.com/chopratejas/headroom/blob/main/docker-compose.yml) orchestrates three services—`headroom-proxy`, `qdrant`, and `neo4j`—with persistent volumes and internal networking on dedicated Docker networks
- Deploy the entire stack by running `docker compose up --build -d` inside the cloned chopratejas/headroom repository
- The default configuration runs as a non-root user with health checks configured at `/readyz` and supports customization through build arguments and environment variables

## Frequently Asked Questions

### What ports need to be open for Headroom to function?

Headroom exposes port **8787** for the proxy API service. The Qdrant and Neo4j services communicate internally within the Docker network via container hostnames and do not require external port exposure for standard operation.

### How do I persist data when restarting containers?

The [`docker-compose.yml`](https://github.com/chopratejas/headroom/blob/main/docker-compose.yml) defines named volumes `qdrant_data` and `neo4j_data` mounted to the respective database containers. Data persists across container restarts unless you explicitly run `docker compose down -v`, which removes these volumes along with the containers.

### Why does the build process use the `uv` package manager instead of pip?

The builder stage uses `uv` to rapidly install Python dependencies and build the `headroom[proxy,code]` wheel in a single step. This approach significantly reduces build time compared to traditional `pip install` methods while correctly compiling the required Rust extensions and handling binary wheels efficiently.

### Can I run Headroom as root inside the container?

While the default configuration runs as a non-root user for security, you can build the image to run as root by setting the `RUNTIME_USER=root` build argument. Pass this during build: `docker compose build --build-arg RUNTIME_USER=root headroom-proxy`, though this is not recommended for production deployments.