Advanced Deployments
Production-grade deployment configurations with Vault, observability, Keycloak, and high availability
This guide covers advanced Docker Compose configurations for production-grade deployments, including secret management, observability, enterprise authentication, load balancing, and high availability.
Available Configurations
| Configuration | Use Case | Components |
|---|---|---|
vault.yml | Secret management | PostgreSQL, Redis, HashiCorp Vault |
observability.yml | Full monitoring stack | OTEL, Prometheus, Grafana, Jaeger, Loki |
keycloak.yml | Enterprise authentication | Keycloak, OAuth2 Proxy |
traefik.yml | Load-balanced gateway | Traefik, 3× Gateway instances |
postgres-ha.yml | Database high availability | PostgreSQL Primary + 2 Replicas, PgBouncer |
redis-cluster.yml | Cache high availability | 6-node Redis Cluster |
dlq.yml | Async processing & retries | RabbitMQ or NATS JetStream |
production.yml | Full production reference | All components combined |
Secret Management with Vault
Uses HashiCorp Vault for secure secret storage with Vault Agent for automatic secret injection.
Setup
# 1. Start Vault
docker compose -f docker-compose.vault.yml up vault -d
# 2. Initialize Vault (save the unseal keys and root token!)
docker exec hadrian-vault vault operator init
# 3. Unseal Vault (repeat with 3 different keys)
docker exec hadrian-vault vault operator unseal <key-1>
docker exec hadrian-vault vault operator unseal <key-2>
docker exec hadrian-vault vault operator unseal <key-3>
# 4. Login and configure
export VAULT_ADDR=http://localhost:8200
vault login <root-token>
# 5. Enable KV secrets engine and store secrets
vault secrets enable -path=secret kv-v2
vault kv put secret/gateway \
openrouter_api_key="sk-or-..." \
anthropic_api_key="sk-ant-..." \
openai_api_key="sk-..."
# 6. Create AppRole for gateway (see Vault docs)
# 7. Start all services
docker compose -f docker-compose.vault.yml up -dSave the unseal keys and root token securely! You'll need them to unseal Vault after restarts. For production, consider using auto-unseal with a cloud KMS.
Observability Stack
Full monitoring, tracing, and logging stack with OpenTelemetry.
Setup
docker compose -f docker-compose.observability.yml up -dEndpoints
| Service | URL | Credentials |
|---|---|---|
| Gateway | http://localhost:8080 | - |
| Grafana | http://localhost:3001 | admin/admin |
| Prometheus | http://localhost:9090 | - |
| Jaeger UI | http://localhost:16686 | - |
| Alertmanager | http://localhost:9093 | - |
Features
- OpenTelemetry Collector: Unified telemetry pipeline for metrics, traces, and logs
- Prometheus: Metrics collection with pre-configured alerting rules
- Grafana: Dashboards with auto-provisioned datasources
- Jaeger: Distributed tracing for request flow visualization
- Loki + Promtail: Log aggregation from all containers
- Alertmanager: Alert routing to Slack, PagerDuty, or email
Alerting Configuration
Edit config/alertmanager.yml to configure alert destinations:
receivers:
- name: "slack"
slack_configs:
- api_url: "https://hooks.slack.com/services/..."
channel: "#alerts"
- name: "pagerduty"
pagerduty_configs:
- service_key: "<integration-key>"Enterprise Authentication with Keycloak
Enterprise identity management with OIDC/OAuth2.
Setup
docker compose -f docker-compose.keycloak.yml up -dEndpoints
| Service | URL | Credentials |
|---|---|---|
| Gateway | http://localhost:8080 | - |
| Keycloak Admin | http://localhost:8080 | admin/admin |
| OIDC Discovery | http://localhost:8080/realms/hadrian/.well-known/openid-configuration | - |
Configuration Steps
- Access Keycloak admin console
- Create realm "hadrian"
- Create client "hadrian" with confidential access type
- Configure client credentials in
.env:
OIDC_CLIENT_ID=hadrian
OIDC_CLIENT_SECRET=<client-secret-from-keycloak>OAuth2 Proxy (Optional)
Add OAuth2 Proxy for browser-based authentication:
docker compose -f docker-compose.keycloak.yml --profile oauth2-proxy up -d
# Access gateway through OAuth2 Proxy at http://localhost:4180Load Balancing with Traefik
Reverse proxy with automatic HTTPS, load balancing, and rate limiting.
Setup
docker compose -f docker-compose.traefik.yml up -dEndpoints
| Service | URL |
|---|---|
| Gateway (HTTPS) | https://gateway.localhost |
| Traefik Dashboard | http://localhost:8080 |
Features
- 3 gateway instances with round-robin load balancing
- Automatic HTTPS with Let's Encrypt (configure for production)
- Rate limiting: 100 req/s with 50 burst
- Security headers: HSTS, XSS protection, content-type sniffing prevention
- Sticky sessions for consistent routing
- Health checks with automatic failover
Production HTTPS
For production deployments with real SSL certificates:
-
Update environment variables:
DOMAIN=gateway.example.com ACME_EMAIL=admin@example.com -
Uncomment Let's Encrypt configuration in the compose file
-
Ensure ports 80/443 are publicly accessible for ACME challenges
Database High Availability
PostgreSQL with streaming replication for read scaling and failover.
Setup
docker compose -f docker-compose.postgres-ha.yml up -dConnection Endpoints
| Connection | Host | Port |
|---|---|---|
| Primary (writes) | pgbouncer-primary | 6432 |
| Replicas (reads) | pgbouncer-replica | 6433 |
Architecture
- Primary PostgreSQL: Handles all write operations
- 2 Read Replicas: Streaming replication for read scaling
- PgBouncer: Connection pooling for both primary and replicas
- HAProxy (optional): Load balancing across replicas
Gateway Configuration
Configure read/write splitting in hadrian.toml:
[database]
url = "postgres://gateway:pass@pgbouncer-primary:6432/gateway"
read_url = "postgres://gateway:pass@pgbouncer-replica:6432/gateway"Read replicas are eventually consistent. Use the primary connection for operations that require immediate consistency.
Cache High Availability
6-node Redis Cluster for high availability caching.
Setup
# Start Redis nodes
docker compose -f docker-compose.redis-cluster.yml up -d
# Initialize cluster (one-time)
docker compose -f docker-compose.redis-cluster.yml --profile init up redis-cluster-initCluster Topology
| Node | Role |
|---|---|
| redis-1, redis-2, redis-3 | Masters |
| redis-4, redis-5, redis-6 | Replicas |
The cluster provides automatic failover if a master node goes down.
Redis Insight UI (Optional)
docker compose -f docker-compose.redis-cluster.yml --profile ui up -d redis-insight
# Access at http://localhost:8001Async Processing with Message Queues
RabbitMQ for reliable async operations with dead letter handling.
Setup with RabbitMQ
docker compose -f docker-compose.dlq.yml up -dEndpoints
| Service | URL | Credentials |
|---|---|---|
| Gateway | http://localhost:8080 | - |
| RabbitMQ Management | http://localhost:15672 | guest/guest |
Pre-configured Queues
| Queue | Purpose |
|---|---|
usage.tracking | Async usage tracking with DLQ |
webhooks | Webhook delivery with priority and DLQ |
audit.log | Audit log stream |
Alternative: NATS JetStream
For a lighter-weight message queue:
docker compose -f docker-compose.dlq.yml --profile nats up -d
# NATS monitoring: http://localhost:8222Full Production Reference
Comprehensive production setup combining all components.
Setup
# Configure all environment variables
cp ../.env.example .env
# Edit .env with production values
# Start everything
docker compose -f docker-compose.production.yml up -dIncluded Components
- Traefik with automatic HTTPS
- 3 load-balanced gateway instances
- PostgreSQL with read replica and PgBouncer
- 3-node Redis cluster
- RabbitMQ for async processing
- Keycloak for authentication
- Full observability stack (OTEL, Prometheus, Grafana, Jaeger, Loki)
Network Isolation
| Network | Services |
|---|---|
frontend | Traefik, Grafana, Keycloak (public-facing) |
backend | Databases, Redis, RabbitMQ (internal only) |
Configuration Files
The deploy/config/ directory contains configuration for all services:
config/
├── alertmanager.yml # Alert routing (Slack, PagerDuty, email)
├── grafana/
│ └── provisioning/
│ ├── dashboards/ # Dashboard auto-provisioning
│ └── datasources/ # Datasource configuration
├── loki.yaml # Log aggregation settings
├── nats.conf # NATS JetStream configuration
├── otel-collector.yaml # OpenTelemetry pipeline
├── prometheus.yml # Prometheus scrape config
├── prometheus-alerts.yml # Alerting rules
├── promtail.yaml # Log collection from Docker
├── rabbitmq/
│ ├── definitions.json # Queue/exchange topology
│ └── rabbitmq.conf # RabbitMQ settings
├── redis-cluster.conf # Redis cluster settings
├── traefik/
│ └── dynamic/ # Dynamic Traefik configuration
├── vault/
│ └── config.hcl # Vault server configuration
└── vault-agent/
├── agent.hcl # Vault Agent configuration
└── templates/ # Secret templatesEnvironment Variables
Key variables for advanced deployments:
| Variable | Description | Required For |
|---|---|---|
OPENROUTER_API_KEY | OpenRouter API key | All |
POSTGRES_PASSWORD | PostgreSQL password | postgres, postgres-ha, production |
RABBITMQ_PASSWORD | RabbitMQ password | dlq, production |
KEYCLOAK_ADMIN_PASSWORD | Keycloak admin password | keycloak, production |
OIDC_CLIENT_SECRET | OIDC client secret | keycloak, production |
GRAFANA_PASSWORD | Grafana admin password | observability, production |
DOMAIN | Your domain name | traefik, production |
ACME_EMAIL | Let's Encrypt email | traefik, production |
Scaling
Horizontal Scaling (Gateway)
# Scale to 5 gateway instances
docker compose -f docker-compose.traefik.yml up -d --scale gateway=5Vertical Scaling (Resources)
Add resource limits to any service:
services:
gateway:
deploy:
resources:
limits:
cpus: "2"
memory: 2G
reservations:
cpus: "0.5"
memory: 512MHealth Checks
All services include health checks. Monitor status:
# Check all service health
docker compose -f docker-compose.postgres.yml ps
# View health check details
docker inspect --format='{{json .State.Health}}' hadrian | jqTroubleshooting
View Logs
# All services
docker compose -f docker-compose.postgres.yml logs -f
# Specific service
docker compose -f docker-compose.postgres.yml logs -f gateway
# Last 100 lines
docker compose -f docker-compose.postgres.yml logs --tail=100 gatewayCommon Issues
Gateway can't connect to database:
# Check database is healthy
docker compose -f docker-compose.postgres.yml ps postgres
# Check network connectivity
docker exec hadrian ping postgresRedis cluster not forming:
# Check cluster status
docker exec hadrian-redis-1 redis-cli cluster info
# Re-run cluster init
docker compose -f docker-compose.redis-cluster.yml --profile init up redis-cluster-initVault sealed after restart:
# Unseal with your keys
docker exec hadrian-vault vault operator unseal <key>Production Checklist
- Configure real domain name and SSL certificates
- Set strong passwords for all services
- Enable Vault with proper unsealing strategy (auto-unseal recommended)
- Configure alerting destinations (Slack, PagerDuty, email)
- Set up database backups
- Configure log retention policies
- Review and adjust resource limits
- Set up external monitoring (uptime checks)
- Configure firewall rules (only expose necessary ports)
- Enable audit logging
Next Steps
- Docker Deployment - Basic Docker deployment guide
- Security - Authentication, authorization, and security best practices
- Configuration Reference - All gateway configuration options