Skip to main content
Browse docs
By Audience
Getting Started
Configuration
Use Cases
IDE Integration
Third-Party Integrations
Engineering Cache
Console
API Reference
Gateway
Workflow Guides
Templates
Providers and SDKs
Industry Guides
Advanced Guides
Browse by Role
Deployment Guides
In-Depth Guides
Tutorials
FAQ

Docker Deployment Guide

Docker Compose is the primary deployment method for self-hosted Keeptrusts installations. This guide covers production-ready compose topologies, volume management, logging, resource limits, and operational patterns.

Use this page when

  • You are deploying Keeptrusts with Docker Compose for self-hosted installations.
  • You need production-ready compose topologies with resource limits, volume management, and logging.
  • You are configuring multi-container setups including API, console, gateway, and PostgreSQL.
  • You need operational patterns for container health checks, log rotation, and troubleshooting.

Primary audience

  • Primary: Technical Engineers
  • Secondary: AI Agents, Technical Leaders

Compose Topologies

Keeptrusts provides several compose files for different deployment scenarios:

FilePurposeComponents
docker-compose.ymlFull application stackAPI, console, gateway, Postgres
docker-compose.infra.ymlInfrastructure onlyPostgres (5434), Redpanda
docker-compose.test.ymlTest infrastructurePostgres (5433)
docker-compose.split.ymlSplit topologyAPI + separate worker binaries
docker-compose.yml (--profile scale)Scaled gatewayHosted gateway with nginx ingress

Production Deployment

Full Stack Compose

# docker-compose.production.yml
services:
keeptrusts-api:
image: keeptrusts/api:latest
restart: unless-stopped
ports:
- "8080:8080"
environment:
- DATABASE_URL=postgres://keeptrusts:${DB_PASSWORD}@postgres:5432/keeptrusts
- KEEPTRUSTS_JWT_SECRET=${JWT_SECRET}
- KEEPTRUSTS_SECRET_ENCRYPTION_KEY=${ENCRYPTION_KEY}
- KEEPTRUSTS_CORS_ALLOWED_ORIGINS=https://console.example.com
- RUST_LOG=info
depends_on:
postgres:
condition: service_healthy
deploy:
resources:
limits:
cpus: '2.0'
memory: 1G
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 10s
timeout: 5s
retries: 3
start_period: 30s

keeptrusts-gateway:
image: keeptrusts/gateway:latest
restart: unless-stopped
command: ["gateway", "run", "--listen", "0.0.0.0:41002", "--policy-config", "/etc/keeptrusts/policy-config.yaml"]
ports:
- "41002:41002"
environment:
- KEEPTRUSTS_API_URL=http://keeptrusts-api:8080
volumes:
- ./policy-config.yaml:/etc/keeptrusts/policy-config.yaml:ro
deploy:
resources:
limits:
cpus: '2.0'
memory: 512M
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:41002/health"]
interval: 10s
timeout: 5s
retries: 3

keeptrusts-console:
image: keeptrusts/console:latest
restart: unless-stopped
ports:
- "3000:3000"
environment:
- KEEPTRUSTS_API_URL=http://keeptrusts-api:8080
- NEXT_PUBLIC_GATEWAY_URL=https://gateway.example.com
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M

postgres:
image: postgres:16-alpine
restart: unless-stopped
volumes:
- pgdata:/var/lib/postgresql/data
environment:
- POSTGRES_DB=keeptrusts
- POSTGRES_USER=keeptrusts
- POSTGRES_PASSWORD=${DB_PASSWORD}
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
healthcheck:
test: ["CMD-SHELL", "pg_isready -U keeptrusts"]
interval: 10s
timeout: 5s
retries: 5
shm_size: '256mb'

volumes:
pgdata:
driver: local

Environment File

# .env — never commit this file
DB_PASSWORD=your-secure-database-password
JWT_SECRET=your-jwt-secret-minimum-32-characters
ENCRYPTION_KEY=your-aes-gcm-siv-encryption-key

Start the Stack

# Pull latest images
docker compose -f docker-compose.production.yml pull

# Start all services
docker compose -f docker-compose.production.yml up -d

# Verify all services are healthy
docker compose -f docker-compose.production.yml ps

Volume Management

PostgreSQL Data Volume

# List volumes
docker volume ls | grep pgdata

# Inspect volume mount point
docker volume inspect keeptrusts_pgdata

# Backup volume data
docker run --rm \
-v keeptrusts_pgdata:/source:ro \
-v /var/backups:/backup \
alpine tar czf /backup/pgdata-$(date +%Y%m%d).tar.gz -C /source .

# Restore volume data
docker volume create keeptrusts_pgdata
docker run --rm \
-v keeptrusts_pgdata:/target \
-v /var/backups:/backup:ro \
alpine tar xzf /backup/pgdata-20250420.tar.gz -C /target

Named Volumes for Persistence

volumes:
pgdata:
driver: local
driver_opts:
type: none
o: bind
device: /data/keeptrusts/postgres
exports:
driver: local
driver_opts:
type: none
o: bind
device: /data/keeptrusts/exports

Logging

JSON Log Driver

services:
keeptrusts-api:
logging:
driver: "json-file"
options:
max-size: "50m"
max-file: "10"
tag: "{{.Name}}"

Centralized Logging with Fluentd

services:
keeptrusts-api:
logging:
driver: fluentd
options:
fluentd-address: "localhost:24224"
tag: "keeptrusts.api"
fluentd-async: "true"

fluentd:
image: fluent/fluentd:v1.16
ports:
- "24224:24224"
volumes:
- ./fluentd/conf:/fluentd/etc
restart: unless-stopped

Viewing Logs

# Follow all service logs
docker compose logs -f

# Follow specific service
docker compose logs -f keeptrusts-api

# Last 100 lines from gateway
docker compose logs --tail=100 keeptrusts-gateway

# Filter errors
docker compose logs keeptrusts-api 2>&1 | grep -i error

# Logs since a specific time
docker compose logs --since="2025-04-20T14:00:00" keeptrusts-api

Multi-Gateway Scaling

Scaled Gateway with nginx

# docker-compose.scale.yml
services:
nginx:
image: nginx:alpine
ports:
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./certs:/etc/nginx/certs:ro
depends_on:
- keeptrusts-gateway

keeptrusts-gateway:
image: keeptrusts/gateway:latest
deploy:
replicas: 3
environment:
- KEEPTRUSTS_API_URL=http://keeptrusts-api:8080
volumes:
- ./policy-config.yaml:/etc/keeptrusts/policy-config.yaml:ro
# Scale gateway instances
docker compose -f docker-compose.scale.yml up -d --scale keeptrusts-gateway=5

Network Configuration

Internal Service Communication

services:
keeptrusts-api:
networks:
- internal
- database
keeptrusts-gateway:
networks:
- frontend
- internal
keeptrusts-console:
networks:
- frontend
- internal
postgres:
networks:
- database

networks:
frontend:
internal:
internal: true
database:
internal: true

Within Docker Compose, use service names as hostnames: http://keeptrusts-api:8080, not IP addresses.

Health Monitoring

Container Health Status

# Check all container health
docker compose ps --format "table {{.Name}}\t{{.Status}}\t{{.Health}}"

# Watch health continuously
watch -n 5 'docker compose ps --format "table {{.Name}}\t{{.Status}}"'

Automated Health Recovery

Docker's restart policy handles basic recovery:

services:
keeptrusts-api:
restart: unless-stopped
# Combined with healthcheck, Docker will restart unhealthy containers

Production Readiness Checklist

#!/usr/bin/env bash
# docker-production-check.sh
set -euo pipefail

echo "=== Docker Production Readiness ==="

# 1. Non-root containers
echo "[1/6] Checking non-root execution..."
for svc in keeptrusts-api keeptrusts-gateway keeptrusts-console; do
uid=$(docker compose exec "$svc" id -u 2>/dev/null || echo "N/A")
echo " $svc: uid=$uid"
done

# 2. Resource limits
echo "[2/6] Checking resource limits..."
docker compose config | grep -A2 "limits:" || echo " WARNING: No resource limits set"

# 3. Volume persistence
echo "[3/6] Checking volumes..."
docker volume ls | grep keeptrusts || echo " WARNING: No named volumes"

# 4. Health checks
echo "[4/6] Checking health endpoints..."
for port in 8080 41002 3000; do
status=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:$port/health" 2>/dev/null || echo "unreachable")
echo " Port $port: $status"
done

# 5. Log rotation
echo "[5/6] Checking log configuration..."
docker compose config | grep -A2 "max-size" || echo " WARNING: No log rotation configured"

# 6. Restart policy
echo "[6/6] Checking restart policies..."
docker compose config | grep "restart:" || echo " WARNING: No restart policy"

echo "=== Check complete ==="

Troubleshooting

# Container won't start — check logs
docker compose logs keeptrusts-api | tail -50

# Database connection refused
docker compose exec keeptrusts-api curl -s postgres:5432 || echo "DB unreachable"

# Port already in use
lsof -i :41002
docker compose down && docker compose up -d

# Disk full — check volumes
docker system df
docker volume ls -q | xargs docker volume inspect --format '{{ .Name }}: {{ .Mountpoint }}'

Next steps

For AI systems

  • Canonical terms: Keeptrusts Docker deployment, docker-compose, container orchestration, volume management, resource limits, production topology, split workers.
  • Key config/commands: docker-compose.yml (full stack), docker-compose.infra.yml (infrastructure), docker-compose.test.yml (test DB); docker compose up -d --build; resource limits via deploy.resources.limits; health checks with service_healthy dependency.
  • Best next pages: Network Configuration, Security Hardening, Upgrade & Maintenance.

For engineers

  • Prerequisites: Docker 24+ and Docker Compose v2; .env file with DB_PASSWORD, JWT_SECRET, ENCRYPTION_KEY, and KEEPTRUSTS_CORS_ALLOWED_ORIGINS.
  • Use service_healthy depends_on conditions to ensure PostgreSQL is ready before API startup; configure resource limits (API: 2 CPU/1 GB; gateway: 1 CPU/512 MB).
  • Validate with: docker compose logs keeptrusts-api | tail -50 for startup errors; curl -s http://localhost:8080/health; docker system df for disk usage.
  • For split topology (separate worker binaries), use docker-compose.split.yml with dedicated export and lifecycle workers.

For leaders

  • Docker Compose is the primary self-hosted deployment method — no Kubernetes required for standard deployments.
  • Resource limits prevent any single service from consuming all host resources during traffic spikes.
  • Multiple compose profiles support different deployment scales without infrastructure rewrites.
  • Upgrade path is straightforward: docker compose pull && docker compose up -d with database migrations auto-applied.