Skip to Content

Docker

This image is not for production. It runs every service in a single container with an embedded database and no replication, high availability, or automated backups. Use the Kubernetes deployment for production workloads.

The Classifyre all-in-one Docker image bundles everything into a single container — PostgreSQL, the NestJS API, the Next.js web UI, and a Caddy reverse proxy. One command and the full application is running on port 3000.

Good for

  • Local development and feature exploration
  • Sales demos and proof-of-concept trials
  • Offline or air-gapped environments
  • CI integration tests against a real running instance

Quick start

Pull the image

docker pull classifyre/all-in-one:0.4.50

The image is available for linux/amd64 and linux/arm64. Pin to a release version for reproducible demos.

Run without persistence

docker run --rm \
-p 3000:3000 \
classifyre/all-in-one:0.4.50

Open http://localhost:3000 in your browser.

The API health endpoint is at http://localhost:3000/api/ping.

Without a volume, everything — sources, findings, settings, and credentials — is lost when the container stops.

Add a data volume

docker run --rm \
-p 3000:3000 \
-v classifyre-data:/var/lib/postgresql/data \
classifyre/all-in-one:0.4.50

With the volume mounted, the database and all application state survive container restarts and image upgrades.



What runs inside

All services start automatically via s6-overlay, a lightweight process supervisor that manages boot order and handles graceful shutdown.

Container  →  port 3000

└── s6-overlay (PID 1)
    ├── PostgreSQL 16    — database for all application data
    ├── NestJS API       — REST + WebSocket backend  (internal :8000)
    ├── Next.js Web      — dashboard UI              (internal :3100)
    └── Caddy            — reverse proxy, single public endpoint
                           /         → web UI
                           /api/*    → API
                           /socket.io/* → WebSocket

Prisma migrations run automatically every time the container starts. You never need to run them manually.


Volumes

The container persists PostgreSQL data at /var/lib/postgresql/data, declared as a Docker volume. All logs go to stdout/stderr and are managed by s6-overlay — use docker logs to access them.

Docker volume /var/lib/postgresql/data
├── PG_VERSION
├── .classifyre_masked_config_key    (encryption key, auto-generated)
└── base/  global/  pg_wal/  ...     (PostgreSQL data files)

To persist data across restarts, mount a named volume at /var/lib/postgresql/data:

docker run --rm \
-p 3000:3000 \
-v classifyre-data:/var/lib/postgresql/data \
classifyre/all-in-one:0.4.50

The container also uses /cache/uv as a package cache for on-demand Python dependency installs. It is declared as a separate volume.

docker run --rm \
-p 3000:3000 \
-v classifyre-data:/var/lib/postgresql/data \
-v classifyre-uv-cache:/cache/uv \
classifyre/all-in-one:0.4.50

What you lose without a volume

DataImpact if lost
PostgreSQL databaseAll sources, findings, custom detectors, and job history gone
Encryption keyStored connector credentials become permanently unreadable
uv package cacheDependencies re-downloaded on next Python install

Why the encryption key matters

Classifyre encrypts connector credentials (API tokens, passwords) at rest using CLASSIFYRE_MASKED_CONFIG_KEY. When no volume is mounted, a new random key is generated on every container start. Any credentials you saved in the previous session become unreadable because the key that encrypted them no longer exists.

Always mount a volume for any session where you configure real connectors.

Storage

The all-in-one Docker image has no embedded object storage. To enable S3 persistence, pass the relevant environment variables at runtime:

docker run \
  -e S3_ENDPOINT=https://s3.us-east-1.amazonaws.com \
  -e S3_BUCKET=my-classifyre-logs \
  -e S3_SANDBOX_BUCKET=my-classifyre-sandbox \
  -e S3_REGION=us-east-1 \
  -e S3_FORCE_PATH_STYLE=false \
  -e S3_ACCESS_KEY_ID=AKIA... \
  -e S3_SECRET_ACCESS_KEY=... \
  classifyre/all-in-one:latest

When these variables are not set, the image runs without object storage and logs stream in-memory only.


Environment variables

VariableDefaultDescription
CLASSIFYRE_MASKED_CONFIG_KEYauto-generated32-character key for encrypting connector credentials. Set explicitly if you need the same key across sessions without a persistent volume.
LOG_LEVELinfoLog verbosity: debug, info, warn, error.
MAX_CONCURRENT_RUNNERS1Max simultaneous CLI scan jobs running inside the container.
POSTGRES_PASSWORD(empty)Password for the postgres user (auth is trust-based by default).
POSTGRES_DBclassifyreName of the default database created on first start.
TEMP_DIR/tmpTemporary directory for scan artifacts.
CLASSIFYRE_CLI_AUTO_INSTALL_OPTIONAL_DEPS1Auto-installs optional detector dependencies (e.g. OCR, ML models) via uv at runtime. Set to 0 to disable.
docker run \
-p 3000:3000 \
-v classifyre-data:/var/lib/postgresql/data \
-e LOG_LEVEL=debug \
classifyre/all-in-one:0.4.50

System requirements

MinimumRecommended
CPU1 core2 cores
RAM1 GB2 GB
Disk2 GB5 GB

Playwright (browser-based crawling) is bundled in the image. Connectors that use it consume an additional ~500 MB RAM per browser instance during active scans.


Upgrading

Pull the new image, stop the existing container, start again pointing at the same volume. Migrations run automatically.

docker pull classifyre/all-in-one:0.4.50

docker compose down
docker compose up -d

The data volume is untouched by image upgrades.


Backup and restore

Even for demos, you may want to preserve a working state.

Backup:

For a consistent backup, use pg_dump against the running container:

docker exec <container-id> pg_dump -h 127.0.0.1 -U postgres classifyre > classifyre-$(date +%Y%m%d).sql

To back up the full data directory (container must be stopped):

docker run --rm \
  -v classifyre-data:/var/lib/postgresql/data \
  -v "$(pwd)/backups:/backup" \
  alpine \
  tar czf /backup/classifyre-$(date +%Y%m%d).tar.gz -C /var/lib/postgresql/data .

Restore:

docker run --rm \
  -v classifyre-data:/var/lib/postgresql/data \
  -v "$(pwd)/backups:/backup" \
  alpine \
  tar xzf /backup/classifyre-20240101.tar.gz -C /var/lib/postgresql/data

Troubleshooting

Container exits immediately

docker logs <container-id>

Common causes: port 3000 already in use (lsof -i :3000), insufficient disk space (docker system df).

Web UI loads but API returns errors

# Check s6 service status
docker exec <container-id> s6-rc -a list
 
# Tail the API log (via Docker, s6 captures stdout)
docker logs <container-id>

Verify health

curl -i http://localhost:3000/api/ping
# → 200 {"status":"ok"}

Architecture reference

Moving to production

When you outgrow the single-container setup, deploy Classifyre on Kubernetes with proper separation of concerns, a managed database, and horizontal scaling.

Kubernetes Deployment

Last updated on