Skip to content

Docker Compose

Docker Compose runs Long Tail with everything it talks to: Postgres, S3-compatible storage (MinIO) and, in the boilerplate, a NATS event bus. At the end of this page you have the dashboard, the REST API and /mcp running on your machine against the same services a cloud deployment uses.

There are two stacks:

Stack Who it is for Dashboard
long-tail-boilerplate App teams building workflows on the published package http://localhost:3030
long-tail Contributors changing Long Tail itself http://localhost:3000
  • Docker with Docker Compose
  • Node 22 or later (for npm install and the test scripts)
  • Git
  1. Clone the boilerplate and create your .env:

    Terminal window
    git clone https://github.com/hotmeshio/long-tail-boilerplate.git
    cd long-tail-boilerplate
    cp .env.example .env
    npm install
  2. Set the superadmin password for the first boot. The seed creates the superadmin account only when SEED_ADMIN_PASSWORD is set and no such user exists yet:

    .env
    SEED_ADMIN_PASSWORD=your-password
  3. Start the stack:

    Terminal window
    docker compose up -d --build
  4. Open http://localhost:3030 and sign in as superadmin with the password you set.

Service Image Host ports Purpose
app Dockerfile, dev stage 3030 Dashboard, REST API, /mcp and workers in one process
postgres postgres:16 5416 Workflow state, escalations, users, config
nats nats:2-alpine 4222 (client), 9222 (WebSocket) Event bus for live dashboard updates
minio cgr.dev/chainguard/minio 9002 (API), 9003 (console) S3-compatible file storage

The app container mounts src/, scripts/ and tests/. ts-node-dev restarts the process when a file changes.

URL What it serves
http://localhost:3030 Dashboard
http://localhost:3030/api REST API
http://localhost:3030/mcp MCP endpoint
http://localhost:3030/health Health check
http://localhost:9003 MinIO console (minioadmin / minioadmin)

Compose reads .env and then sets the in-network values on top:

Variable Compose value Purpose
POSTGRES_HOST postgres Database host inside the network
POSTGRES_PORT 5432 Database port inside the network
LT_S3_ENDPOINT http://minio:9000 Storage endpoint the server calls
LT_S3_PUBLIC_ENDPOINT http://localhost:9002 Storage endpoint the browser receives
NATS_URL nats://nats:4222 Server-to-NATS connection
NATS_TOKEN dev_api_secret NATS auth token
NATS_WS_TARGET ws://nats:9222 NATS WebSocket the server proxies for the dashboard
LT_OAUTH_ISSUER http://localhost:3030 Turns on OAuth sign-in for MCP clients at /mcp
SEED_ADMIN_PASSWORD from .env First-boot superadmin password
NODE_OPTIONS --max-old-space-size=3072 --max-semi-space-size=64 Node heap sizing

The rest of .env holds PORT, JWT_SECRET, the POSTGRES_* credentials, the LT_S3_* storage settings and optional LLM and OAuth keys. .env.example lists every variable with its local default.

Host ports move with PORT, PG_PORT, NATS_PORT, NATS_WS_PORT, MINIO_PORT and MINIO_CONSOLE_PORT.

Field Value
Host localhost
Port 5416
User postgres
Password password
Database myapp
SSL Off

docker-compose.multi.yml replaces the single app with one API container and two worker containers, the same split the AWS deployment runs:

Terminal window
docker compose -f docker-compose.yml -f docker-compose.multi.yml up -d --build

Each container sets APP_ROLE (api or worker). See Run modes for what each role starts.

Terminal window
npm test # Unit tests
npm run test:integration # Integration tests against the running stack

The long-tail repo runs the package from source, with the example workflows and seed data loaded.

  1. Clone and start:

    Terminal window
    git clone https://github.com/hotmeshio/long-tail.git
    cd long-tail
    docker compose up -d --build
  2. Open http://localhost:3000. The example workflows seed the dashboard. Sign in as superadmin with the password declared under seed.admin in index.ts.

On first boot the dev entrypoint installs the dashboard’s dependencies and builds it when dashboard/dist is missing.

Service Host ports Purpose
long-tail 3000 (API and dashboard), 9230 (Node debugger) Server and workers, run with ts-node-dev
postgres 5415 Database, tuned for write-heavy workloads
minio 9000 (API), 9001 (console) S3-compatible file storage
mock-oauth 9080 Test OAuth provider for the sign-in flows

Change a host port with LT_PORT, LT_DEBUG_PORT, LT_PG_PORT, LT_MINIO_PORT, LT_MINIO_CONSOLE_PORT or LT_MOCK_OAUTH_PORT.

The long-tail service sets LT_SEED_SERVICE_KEYS=true, which prints the seeded mcp-service account’s API keys to the container log on first start. JWT_SECRET, LT_OAUTH_ISSUER, the LLM keys and the Honeycomb keys pass through from your shell or .env.

Layer an override file to add a service:

File Adds Command
docker-compose.nats.yml NATS for cross-container events and the dashboard WebSocket docker compose -f docker-compose.yml -f docker-compose.nats.yml up -d --build
docker-compose.external.yml An external MCP server that authenticates with a service token docker compose -f docker-compose.yml -f docker-compose.external.yml up
docker-compose.machines.yml An MQTT machine broker, a site NATS and a mock line (layer it on the NATS override) docker compose -f docker-compose.yml -f docker-compose.nats.yml -f docker-compose.machines.yml up -d --build

With the NATS override, EVENT_TRANSPORT=nats replaces Socket.IO and the dashboard receives events over the NATS WebSocket on port 9222.

-v deletes the named Postgres and MinIO volumes. Everything starts from an empty database:

Terminal window
docker compose down -v
docker compose up -d --build
docker compose exec app npm run seed

The contributor stack mounts anonymous volumes at /app/node_modules and /app/dashboard/node_modules. Compose reuses them across up --build, so the container keeps the old packages after you change package.json. Renew the anonymous volumes:

Terminal window
docker compose up -d --build -V

-V (--renew-anon-volumes) replaces only anonymous volumes. The named pgdata and miniodata volumes, and your data, stay.