.env.production, all defined in docker-stack.yml.
For a scalable, highly-available deployment, deploy Latitude to a Kubernetes cluster using our Helm chart instead — see Cluster deployment.
Quick start
Get the deploy files
Create a folder Give permissions to the initialization scripts for postgres and seaweedfs:
mkdir -p latitude and download all files into it:Create your environment file
The
.env.example file documents the neccessary production variables, create a copy of it and modify it to your needs.Generate the secrets
Generate a unique value for each key and paste them into Moreover, remember to change the default infrastructure passwords (
.env.production:POSTGRES_PASSWORD_*, CLICKHOUSE_PASSWORD…) too!Configure an email transport
Choose one of the email providers supported (Mailgun, Sendgrid, SMTP…) and configure it so login (and other) emails reach you.
Pull the images and start
migrations container runs first and the application services wait for it to finish.What gets deployed
| Container | Image | Purpose |
|---|---|---|
web | latitudedata/web | The Latitude UI |
api | latitudedata/api | Public API & MCP server |
ingest | latitudedata/ingest | OTLP trace ingestion |
workers | latitudedata/workers | BullMQ background jobs |
workflows | latitudedata/workflows | Temporal workers |
migrations | latitudedata/migrations | One-shot Postgres & ClickHouse migrations |
postgres | pgvector/pgvector | Primary store + pgvector |
clickhouse | clickhouse/clickhouse-server | Span/telemetry OLAP store |
redis, redis-bullmq | redis | Cache + queues |
temporal | temporalio/auto-setup | Workflow engine (Postgres-backed) |
seaweedfs | chrislusf/seaweedfs | S3-compatible object store |
Secrets
All configuration, secrets included, lives in.env.production. Keep .env.production out of version control and back it up with your other operational secrets.
See the secrets reference for what each application secret does.
AI features
The stack boots and core observability (ingest + trace viewing) works without API keys. AI-dependent features stay disabled until you add credentials for the providers you configure:| Capability | Providers | Feature |
|---|---|---|
| Generation | Amazon Bedrock (default), Anthropic, OpenAI, Google, or any OpenAI-compatible endpoint | Flaggers, evaluations, issue summarization, taxonomy naming, AI generation |
| Embeddings | Voyage AI (default), OpenAI, Google, or any OpenAI-compatible endpoint | Semantic trace/issue search, search highlights, issue clustering |
| Reranking | Voyage AI (default) or Amazon Bedrock | Issue-discovery candidate matching |
Scaling
docker-stack.yml also runs under Docker Swarm (docker swarm init, then docker stack deploy -c docker-stack.yml latitude), which is the better fit for scaling. The stateless application services — web, api, ingest, workers, workflows — scale horizontally: raise their deploy.replicas in the file (or docker service scale latitude_api=3), and Swarm load-balances across replicas, including across extra machines joined with docker swarm join.
The bundled stateful services (Postgres, ClickHouse, Redis, Temporal, SeaweedFS) stay single-instance — for HA, point them at managed/external instances (Bring your own infrastructure) or move to the Cluster deployment. On plain Compose (one host), the services with no published ports — workers and workflows — can still scale directly: docker compose -f docker-stack.yml up -d --scale workers=3.
Backups
Persisted state lives in thepostgres_data, clickhouse_data, seaweedfs_data, and redis_bullmq_data volumes. Back them up regularly:
- Postgres —
docker compose -f docker-stack.yml exec postgres pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB"(the source of truth for projects, users, and metadata). - ClickHouse — back up
clickhouse_dataor use ClickHouseBACKUP(span/telemetry data). - Object store — back up
seaweedfs_data(or rely on your managed S3’s durability).
Upgrading
Pin a specificX.Y.Z tag for Latitude’s images in production so upgrades are deliberate. For easiness, you can bump LAT_IMAGE_TAG to a new release (or use :latest) in .env.production. Then pull the new images and restart the services.
migrations container runs automatically on every up, applying any new Postgres and ClickHouse migrations before the application services start.
Health and observability
Every service exposes an HTTP health endpoint, wired as the container healthchecks indocker-stack.yml (/health; the web app uses /api/health; workers/workflows listen on internal ports 9090/9091). Check them with docker compose -f docker-stack.yml ps — every service should report healthy. OpenTelemetry export is available through the LAT_OBSERVABILITY_* variables in .env.production.
TLS and reverse proxy
docker-stack.yml publishes web (3000), api (3001), and ingest (3002) on the host over plain HTTP. For anything internet-facing, put a TLS-terminating reverse proxy (Caddy, nginx, Traefik) in front, route your domain(s) to those ports, and set the LAT_*_URL / *_ORIGINS values to the public https:// URLs.
Custom domain
Latitude exposes three public surfaces, each typically on its own hostname behind your reverse proxy: the web UI, the API (which also hosts the MCP server), and ingest (OTLP traces)..env.example ships these pointing at localhost; for a real domain you must update the public URLs and the origin allowlists, so that browsers, the API, and MCP clients all agree on where each service lives.
In .env.production:
LAT_*_URL exactly matches (scheme included) the URL your reverse proxy serves, and the proxy forwards each host to the matching service port. Leave the LAT_*_PORT values as their defaults (3000 / 3001 / 3002): they’re the ports each service listens on internally, not part of the public hostname.
MCP clients connect to
${LAT_API_URL}/v1/mcp but sign in via OAuth against the web origin, so both LAT_WEB_URL and LAT_API_URL must be correct.Bring your own infrastructure
Each infra service indocker-stack.yml is a clearly-marked, independently removable block. To use an existing or managed datastore, comment out its block and point the matching LAT_* value at your instance:
| Dependency | Repoint | Notes |
|---|---|---|
| Postgres | LAT_DATABASE_*, LAT_ADMIN_DATABASE_* | Needs the vector (pgvector) extension and a schema-create admin role |
| ClickHouse | LAT_CLICKHOUSE_* | Dedicated LAT_CLICKHOUSE_DB database |
| Redis (cache) | LAT_REDIS_* | Latitude namespaces all keys under latitude: |
| Redis (queue) | LAT_BULLMQ_* | Latitude namespaces all keys under latitude: |
| Temporal | LAT_TEMPORAL_* | Pointing to Temporal Cloud is recommended |
| Object storage | LAT_STORAGE_* | Point at any S3-compatible store or the local filesystem |
Next steps
Configuration reference
The full Latitude configurable environment-variable reference for self-hosting.