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:
| File | Purpose | Components |
|---|---|---|
docker-compose.yml | Full application stack | API, console, gateway, Postgres |
docker-compose.infra.yml | Infrastructure only | Postgres (5434), Redpanda |
docker-compose.test.yml | Test infrastructure | Postgres (5433) |
docker-compose.split.yml | Split topology | API + separate worker binaries |
docker-compose.yml (--profile scale) | Scaled gateway | Hosted 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
- Network Configuration — port and firewall setup
- Security Hardening — container security best practices
- Upgrade & Maintenance — container update procedures
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 viadeploy.resources.limits; health checks withservice_healthydependency. - Best next pages: Network Configuration, Security Hardening, Upgrade & Maintenance.
For engineers
- Prerequisites: Docker 24+ and Docker Compose v2;
.envfile withDB_PASSWORD,JWT_SECRET,ENCRYPTION_KEY, andKEEPTRUSTS_CORS_ALLOWED_ORIGINS. - Use
service_healthydepends_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 -50for startup errors;curl -s http://localhost:8080/health;docker system dffor disk usage. - For split topology (separate worker binaries), use
docker-compose.split.ymlwith 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 -dwith database migrations auto-applied.