Skip to Content
Install & DeployDocker (all-in-one)

Docker (all-in-one)

The fastest way to get Classifyre running: one image carrying the whole stack — the API, the web UI, the Python scan workers, and PostgreSQL — with nothing to provision and nothing to connect.

docker run -d --name classifyre \  -p 3000:3000 \  --shm-size=1g \  -v classifyre-pgdata:/var/lib/postgresql/data \  -v classifyre-data:/var/lib/classifyre \  -v classifyre-uv-cache:/cache/uv \  classifyre/all-in-one:0.5.6

Then open localhost:3000. The first boot initialises the database and creates a workspace, which takes a few minutes on a laptop.

This is also a reasonable way to run Classifyre for a single investigator. For a team, or for anything that has to survive a machine dying, use the Helm chart instead — it runs the same images as separate, independently scalable workloads.

What is inside the image

ProcessPortWhat it is
Caddy3000the only published port; routes to the two servers below
Web UI3100 (internal)Next.js, and this documentation at /docs
API + worker8000 (internal)REST, WebSockets, job queues, embeddings, and the parent of every scan
PostgreSQL 18 + pgvector5432 (internal)all data

They are supervised by s6-overlay, which restarts anything that dies and makes docker stop and docker restart behave as expected. Only port 3000 is reachable — PostgreSQL binds to loopback inside the container’s own network namespace and is never exposed.

The scan workers are not a service: the API starts one process per scan and it exits with the scan, the same lifecycle Kubernetes gives them as Jobs.

The image ships a small embedding model (Xenova/all-MiniLM-L6-v2) already baked in, so semantic search and duplicate review work offline from the first scan.

Requirements

Memory4 GB minimum, 8 GB recommended. The container refuses to start below 4 GB rather than failing halfway through your first scan.
CPU2 cores minimum. Scans are CPU-bound.
Disk~10 GB for the image and database, plus room for what you scan.
Shared memory--shm-size=1g. Without it, large queries fail with could not resize shared memory segment.

On macOS and Windows, Docker Desktop caps what containers may use and often defaults to 2 GB — below the floor. Raise it under Settings → Resources → Memory and restart Docker.

Both linux/amd64 and linux/arm64 are published, so Apple Silicon runs natively with no emulation.

Run it

The command above. The first boot initialises the database, applies the migrations, and creates a workspace called default — a few minutes on a laptop. Follow it with docker logs -f classifyre.

Connect a source

Point it at something you already run — a database, an S3 bucket, a Confluence space, a Git repository, or a folder you mounted. Credentials are encrypted at rest. See configuring sources.

Switch on detectors

Enable the pre-built packs you care about. They work on the first scan with no model setup.

Run a scan, open a case

Findings land ranked by importance. Group them into inquiries and cases, or add an AI provider and let the autopilot work them between scans.

Scanning a folder on your machine

Bind-mount it, then point a source at the path inside the container:

docker run -d --name classifyre \
  -p 3000:3000 --shm-size=1g \
  -v classifyre-pgdata:/var/lib/postgresql/data \
  -v classifyre-data:/var/lib/classifyre \
  -v classifyre-uv-cache:/cache/uv \
  -v "$HOME/Documents/case-files:/data/case-files:ro" \
  classifyre/all-in-one:latest

In the UI: Sources → New → Mounted Folder, path /data/case-files. See Mounted Folder.

Mount read-only (:ro) unless you have a reason not to. Classifyre only ever reads from a folder source, and :ro makes that the filesystem’s guarantee rather than the application’s.

Where the data lives

Three volumes, and you want all three:

VolumeHoldsIf you drop it
/var/lib/postgresql/datathe databaseeverything is lost
/var/lib/classifyrescan logs, the credential encryption key, the model cachestored credentials become unreadable
/cache/uvoptional Python dependencies installed on first usethey are downloaded again after every upgrade

Configuration

Everything is an environment variable, and everything has a working default. Pass them with -e NAME=value, or with --env-file.

Core

VariableDefaultPurpose
PORT_HTTP3000Port inside the container. Usually easier to remap with -p 8080:3000.
CLASSIFYRE_BOOTSTRAP_NAMESPACEdefaultSlug of the workspace created on first boot. Set to "" to create your own.
CLASSIFYRE_MASKED_CONFIG_KEYgeneratedEncrypts stored source credentials and MCP tokens.
DEMO_MODEfalseRead-only mode; blocks every write.
TELEMETRY_DISABLED / DO_NOT_TRACKunsetSet either to 1 to disable telemetry.
CORS_ORIGINsame-originOnly needed if the UI is served from another host.

Database

Leave unset to use the PostgreSQL inside the image.

VariableDefaultPurpose
DATABASE_URLbundledSet it and the bundled server never starts.
POSTGRES_DBclassifyreDatabase name (bundled server only).
PGDATA/var/lib/postgresql/dataData directory (bundled server only).
CLASSIFYRE_AUTO_MIGRATEtruefalse skips migrations at startup.

An external server must have pgvector available, and the user must be able to CREATE SCHEMA and CREATE EXTENSION — each workspace gets its own schema, created on demand. See PostgreSQL.

-e DATABASE_URL="postgresql://user:[email protected]:5432/classifyre?sslmode=require"

Object storage

Scan logs are written to disk by default. Point them at S3-compatible storage to keep them when the container is disposable. See S3 object storage.

VariableDefaultPurpose
S3_BUCKETunsetSetting this switches scan logs from disk to S3.
S3_ENDPOINTAWSRequired for MinIO, R2, Backblaze, and anything non-AWS.
S3_REGIONus-east-1
S3_ACCESS_KEY_ID / S3_SECRET_ACCESS_KEYunsetOmit both to use the ambient credential chain.
S3_FORCE_PATH_STYLEtrueRequired by MinIO and most self-hosted providers.
S3_LOG_PREFIXrunner-logs/Key prefix.

Embeddings

VariableDefaultPurpose
EMBEDDING_PROVIDERtransformers-jsopenai-compatible to use a remote service.
EMBEDDING_BASE_URL / EMBEDDING_API_KEYunsetThe remote endpoint, when using openai-compatible.
EMBEDDING_MODELXenova/all-MiniLM-L6-v2Changing it re-embeds everything.
EMBEDDING_ALLOW_REMOTE_MODELSfalsetrue allows downloading a different local model.

See embeddings for what changing the model costs.

AI providers for LLM detectors and the autopilot are not environment variables. They are per-workspace settings configured in the UI under Settings → AI providers, with their keys encrypted at rest.

Resources

The container measures the memory and CPU it was given and sizes itself at startup. Override only with reason.

VariablePurpose
CLASSIFYRE_NODE_HEAP_MBNode heap ceiling. Bigger is usually worse — a larger ceiling means more garbage accrues before a major GC.
PG_SHARED_BUFFERS, PG_WORK_MEM, PG_EFFECTIVE_CACHE_SIZEPostgreSQL memory.
MAX_CONCURRENT_RUNNERSScans running at once.
CLASSIFYRE_MAX_POOL_WORKERSDetector worker processes per scan.
CLASSIFYRE_MIN_MEMORY_MBThe 4 GB startup floor.

The startup log prints what it chose:

[classifyre] memory=8192MB cpus=4 shm=1024MB
[classifyre] node heap=2048MB rss guard=4928MB
[classifyre] postgres shared_buffers=512MB work_mem=16MB effective_cache_size=4096MB
[classifyre] scans: 1 concurrent, 4 worker(s) each

Upgrades

docker pull classifyre/all-in-one:latest
docker rm -f classifyre
# …then the same `docker run`, with the same volumes

Data lives in the volumes, so it carries over, and migrations run automatically on the first boot of the new version. Pin a version tag to control when that happens. Downgrades are not supported — migrations only go forwards. See upgrade & versioning.

Backup

Two things, and you need both:

docker exec classifyre pg_dump -U postgres classifyre > classifyre.sql
docker exec classifyre cat /var/lib/classifyre/masked-config.key

Without the key, a restored dump still holds every stored source credential — encrypted, and permanently unreadable. Keep it where you would keep a password, and restore it with -e CLASSIFYRE_MASKED_CONFIG_KEY=….

Troubleshooting

The container exits saying there is not enough memory: Docker is capping it below 4 GB. Raise Settings → Resources → Memory in Docker Desktop and restart Docker, or check for a --memory flag.

Moving to Kubernetes

Nothing here is a dead end. Export a workspace from this container and import it into a cluster install — sources, findings, cases and lineage all move. The Helm chart runs the same images this one is composed from.

Last updated on