Production Deployment
This guide covers deploying Quantbot to production environments with Docker, cloud platforms, and advanced configuration options.
Deployment Overview
Quantbot supports multiple deployment strategies:
- Docker Compose: Single-server deployment with all services
- Kubernetes: Scalable container orchestration
- Cloud Platforms: AWS, GCP, Azure with managed services
- Serverless: Backend as serverless functions with managed databases
Docker Production Deployment
Production Docker Compose
Create a production-ready docker-compose.prod.yml
:
version: '3.8'
services:
frontend:
build:
context: ./Quantbot-FE
dockerfile: Dockerfile.prod
ports:
- "80:80"
- "443:443"
environment:
- VITE_API_BASE_URL=https://api.yourdomain.com/api/v1
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/ssl/certs
depends_on:
- backend
restart: unless-stopped
backend:
build:
context: ./Quantbot-BE
dockerfile: Dockerfile.prod
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql+asyncpg://quantbot_admin:${DB_PASSWORD}@postgres:5432/quantbot
- NEO4J_URI=bolt://neo4j:7687
- NEO4J_USER=neo4j
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
- JWT_SECRET_KEY=${JWT_SECRET_KEY}
- GOOGLE_API_KEY=${GOOGLE_API_KEY}
- OPENAI_API_KEY=${OPENAI_API_KEY}
- NEWS_API_KEY=${NEWS_API_KEY}
- FINNHUB_API_KEY=${FINNHUB_API_KEY}
- FMP_API_KEY=${FMP_API_KEY}
- OPIK_API_KEY=${OPIK_API_KEY}
- OPIK_WORKSPACE=${OPIK_WORKSPACE}
- OPIK_PROJECT_NAME=${OPIK_PROJECT_NAME}
depends_on:
- postgres
- neo4j
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
postgres:
image: pgvector/pgvector:pg16
environment:
- POSTGRES_DB=quantbot
- POSTGRES_USER=quantbot_admin
- POSTGRES_PASSWORD=${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
- ./backup:/backup
ports:
- "5432:5432"
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U quantbot_admin -d quantbot"]
interval: 10s
timeout: 5s
retries: 5
neo4j:
image: neo4j:5.15-community
environment:
- NEO4J_AUTH=neo4j/${NEO4J_PASSWORD}
- NEO4J_PLUGINS=["graph-data-science"]
- NEO4J_dbms_security_procedures_unrestricted=gds.*
volumes:
- neo4j_data:/data
- neo4j_logs:/logs
- neo4j_conf:/conf
ports:
- "7474:7474"
- "7687:7687"
restart: unless-stopped
healthcheck:
test: ["CMD", "cypher-shell", "-u", "neo4j", "-p", "${NEO4J_PASSWORD}", "RETURN 1"]
interval: 30s
timeout: 10s
retries: 3
redis:
image: redis:7-alpine
command: redis-server --requirepass ${REDIS_PASSWORD}
environment:
- REDIS_PASSWORD=${REDIS_PASSWORD}
volumes:
- redis_data:/data
ports:
- "6379:6379"
restart: unless-stopped
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 3
volumes:
postgres_data:
neo4j_data:
neo4j_logs:
neo4j_conf:
redis_data:
Production Environment Variables
Create a secure .env.prod
file:
# Database
DB_PASSWORD=your-super-secure-database-password
NEO4J_PASSWORD=your-super-secure-neo4j-password
REDIS_PASSWORD=your-super-secure-redis-password
# JWT Security
JWT_SECRET_KEY=your-256-bit-secret-key-for-jwt-tokens
JWT_ACCESS_TOKEN_EXPIRE_MINUTES=60
JWT_REFRESH_TOKEN_EXPIRE_DAYS=7
# API Keys
GOOGLE_API_KEY=your-production-google-api-key
OPENAI_API_KEY=your-production-openai-api-key
NEWS_API_KEY=your-production-news-api-key
FINNHUB_API_KEY=your-production-finnhub-api-key
FMP_API_KEY=your-production-fmp-api-key
# Observability
OPIK_API_KEY=your-production-opik-api-key
OPIK_WORKSPACE=quantbot-production
OPIK_PROJECT_NAME=quantbot
# Memory Configuration
MEMORY_MAX_EPISODES_PER_USER=50000
MEMORY_RETENTION_DAYS=730
MEMORY_ENABLE_ENCRYPTION=true
# Performance
QUANTBOT_WORKFLOW=production
Deployment Commands
# Deploy to production
docker compose -f docker-compose.prod.yml --env-file .env.prod up -d
# View production logs
docker compose -f docker-compose.prod.yml logs -f
# Update production deployment
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d --force-recreate
# Scale services
docker compose -f docker-compose.prod.yml up -d --scale backend=3
Cloud Platform Deployment
AWS Deployment
Option 1: AWS ECS with Fargate
# docker-compose.aws.yml
version: '3.8'
x-aws-cluster: quantbot-cluster
x-aws-vpc: vpc-12345678
services:
backend:
image: ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/quantbot-backend:latest
x-aws-role: arn:aws:iam::${AWS_ACCOUNT_ID}:role/quantbot-execution-role
environment:
- DATABASE_URL=postgresql+asyncpg://${RDS_USERNAME}:${RDS_PASSWORD}@${RDS_ENDPOINT}:5432/quantbot
- NEO4J_URI=${NEO4J_ENDPOINT}
deploy:
replicas: 2
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
frontend:
image: ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/quantbot-frontend:latest
ports:
- "80:80"
- "443:443"
x-aws-load_balancer: quantbot-alb
Deployment Script
#!/bin/bash
# deploy-aws.sh
# Build and push images to ECR
aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com
# Backend
docker build -t quantbot-backend ./Quantbot-BE
docker tag quantbot-backend:latest $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/quantbot-backend:latest
docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/quantbot-backend:latest
# Frontend
docker build -t quantbot-frontend ./Quantbot-FE
docker tag quantbot-frontend:latest $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/quantbot-frontend:latest
docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/quantbot-frontend:latest
# Deploy with Docker Compose for ECS
docker compose -f docker-compose.aws.yml up
Google Cloud Platform (GCP)
Cloud Run Deployment
# cloudbuild.yaml
steps:
# Build backend
- name: 'gcr.io/cloud-builders/docker'
args:
- 'build'
- '-t'
- 'gcr.io/$PROJECT_ID/quantbot-backend'
- './Quantbot-BE'
# Push backend
- name: 'gcr.io/cloud-builders/docker'
args:
- 'push'
- 'gcr.io/$PROJECT_ID/quantbot-backend'
# Deploy backend to Cloud Run
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
entrypoint: 'gcloud'
args:
- 'run'
- 'deploy'
- 'quantbot-backend'
- '--image'
- 'gcr.io/$PROJECT_ID/quantbot-backend'
- '--region'
- 'us-central1'
- '--allow-unauthenticated'
- '--set-env-vars'
- 'DATABASE_URL=postgresql+asyncpg://user:pass@/quantbot?host=/cloudsql/$PROJECT_ID:us-central1:quantbot-db'
# Build and deploy frontend
- name: 'gcr.io/cloud-builders/docker'
args:
- 'build'
- '-t'
- 'gcr.io/$PROJECT_ID/quantbot-frontend'
- './Quantbot-FE'
- name: 'gcr.io/cloud-builders/docker'
args:
- 'push'
- 'gcr.io/$PROJECT_ID/quantbot-frontend'
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
entrypoint: 'gcloud'
args:
- 'run'
- 'deploy'
- 'quantbot-frontend'
- '--image'
- 'gcr.io/$PROJECT_ID/quantbot-frontend'
- '--region'
- 'us-central1'
- '--allow-unauthenticated'
Kubernetes Deployment
Kubernetes Manifests
# quantbot-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: quantbot
---
# quantbot-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: quantbot-config
namespace: quantbot
data:
DATABASE_URL: "postgresql+asyncpg://quantbot_admin:password@postgres:5432/quantbot"
NEO4J_URI: "bolt://neo4j:7687"
NEO4J_USER: "neo4j"
---
# quantbot-secrets.yaml
apiVersion: v1
kind: Secret
metadata:
name: quantbot-secrets
namespace: quantbot
type: Opaque
stringData:
JWT_SECRET_KEY: "your-secret-key"
GOOGLE_API_KEY: "your-google-api-key"
OPENAI_API_KEY: "your-openai-api-key"
NEWS_API_KEY: "your-news-api-key"
---
# quantbot-backend-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: quantbot-backend
namespace: quantbot
spec:
replicas: 3
selector:
matchLabels:
app: quantbot-backend
template:
metadata:
labels:
app: quantbot-backend
spec:
containers:
- name: backend
image: quantbot/backend:latest
ports:
- containerPort: 8000
envFrom:
- configMapRef:
name: quantbot-config
- secretRef:
name: quantbot-secrets
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 5
periodSeconds: 5
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
---
# quantbot-backend-service.yaml
apiVersion: v1
kind: Service
metadata:
name: quantbot-backend-service
namespace: quantbot
spec:
selector:
app: quantbot-backend
ports:
- protocol: TCP
port: 8000
targetPort: 8000
type: ClusterIP
---
# quantbot-frontend-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: quantbot-frontend
namespace: quantbot
spec:
replicas: 2
selector:
matchLabels:
app: quantbot-frontend
template:
metadata:
labels:
app: quantbot-frontend
spec:
containers:
- name: frontend
image: quantbot/frontend:latest
ports:
- containerPort: 80
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "200m"
---
# quantbot-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: quantbot-ingress
namespace: quantbot
annotations:
kubernetes.io/ingress.class: "nginx"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- quantbot.yourdomain.com
secretName: quantbot-tls
rules:
- host: quantbot.yourdomain.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: quantbot-backend-service
port:
number: 8000
- path: /
pathType: Prefix
backend:
service:
name: quantbot-frontend-service
port:
number: 80
Deploy to Kubernetes
# Apply all manifests
kubectl apply -f k8s/
# Check deployment status
kubectl get pods -n quantbot
kubectl get services -n quantbot
kubectl get ingress -n quantbot
# Scale deployment
kubectl scale deployment quantbot-backend --replicas=5 -n quantbot
# View logs
kubectl logs -f deployment/quantbot-backend -n quantbot
SSL/TLS Configuration
Let's Encrypt with Nginx
# nginx/nginx.conf
upstream backend {
server backend:8000;
}
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
ssl_certificate /etc/ssl/certs/fullchain.pem;
ssl_certificate_key /etc/ssl/certs/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
ssl_prefer_server_ciphers off;
# Frontend
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
}
# Backend API
location /api/ {
proxy_pass http://backend;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# CORS
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
}
# WebSocket support (if needed)
location /ws/ {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
}
}
Database Migration and Backup
Production Database Setup
# Run migrations
docker compose -f docker-compose.prod.yml exec backend alembic upgrade head
# Create database backup
docker compose -f docker-compose.prod.yml exec postgres pg_dump -U quantbot_admin quantbot > backup_$(date +%Y%m%d_%H%M%S).sql
# Restore from backup
docker compose -f docker-compose.prod.yml exec postgres psql -U quantbot_admin quantbot < backup_20250101_120000.sql
# Neo4j backup
docker compose -f docker-compose.prod.yml exec neo4j neo4j-admin database dump --to-path=/backup neo4j
Automated Backup Script
#!/bin/bash
# backup.sh - Run daily backups
BACKUP_DIR="/backup/$(date +%Y/%m)"
mkdir -p $BACKUP_DIR
# PostgreSQL backup
docker compose -f docker-compose.prod.yml exec postgres pg_dump -U quantbot_admin quantbot | gzip > $BACKUP_DIR/postgres_$(date +%Y%m%d_%H%M%S).sql.gz
# Neo4j backup
docker compose -f docker-compose.prod.yml exec neo4j neo4j-admin database dump neo4j --to-path=/backup/neo4j_$(date +%Y%m%d_%H%M%S).dump
# Cleanup old backups (keep 30 days)
find /backup -type f -mtime +30 -delete
# Upload to cloud storage (optional)
aws s3 sync /backup s3://quantbot-backups/
Monitoring and Observability
Health Checks
# Add to backend: app/api/health.py
from fastapi import APIRouter, HTTPException
from app.core.database import DatabaseManager
from app.services.market_service import MarketService
router = APIRouter()
@router.get("/health")
async def health_check():
"""Comprehensive health check endpoint."""
health_status = {
"status": "healthy",
"timestamp": datetime.utcnow().isoformat(),
"services": {}
}
# Database check
try:
db_manager = DatabaseManager()
await db_manager.get_session()
health_status["services"]["database"] = "healthy"
except Exception as e:
health_status["services"]["database"] = f"unhealthy: {str(e)}"
health_status["status"] = "unhealthy"
# Market service check
try:
market_service = MarketService()
await market_service.get_stock_data("AAPL", "1d")
health_status["services"]["market_data"] = "healthy"
except Exception as e:
health_status["services"]["market_data"] = f"degraded: {str(e)}"
if health_status["status"] == "unhealthy":
raise HTTPException(status_code=503, detail=health_status)
return health_status
Prometheus Metrics
# app/core/metrics.py
from prometheus_client import Counter, Histogram, Gauge
import time
# API metrics
api_requests = Counter('quantbot_api_requests_total', 'Total API requests', ['method', 'endpoint', 'status'])
api_duration = Histogram('quantbot_api_request_duration_seconds', 'API request duration')
active_users = Gauge('quantbot_active_users', 'Number of active users')
# AI metrics
ai_requests = Counter('quantbot_ai_requests_total', 'Total AI requests')
ai_response_time = Histogram('quantbot_ai_response_time_seconds', 'AI response time')
tool_usage = Counter('quantbot_tool_usage_total', 'Tool usage count', ['tool_name'])
Logging Configuration
# app/core/logging.py
import logging
from pythonjsonlogger import jsonlogger
def setup_logging():
logHandler = logging.StreamHandler()
formatter = jsonlogger.JsonFormatter(
fmt='%(asctime)s %(name)s %(levelname)s %(message)s'
)
logHandler.setFormatter(formatter)
logger = logging.getLogger()
logger.addHandler(logHandler)
logger.setLevel(logging.INFO)
return logger
Security Configuration
Production Security Checklist
- API Keys: Store in secure environment variables or secret managers
- JWT Security: Use strong secret keys (256-bit minimum)
- Database Security: Use strong passwords, limit network access
- HTTPS: Use valid SSL certificates, redirect HTTP to HTTPS
- CORS: Configure appropriate origins, avoid wildcards in production
- Rate Limiting: Implement API rate limiting
- Input Validation: Validate and sanitize all inputs
- Security Headers: Implement security headers in Nginx/proxy
- Network Security: Use firewalls, VPNs, or security groups
- Regular Updates: Keep dependencies and base images updated
Environment-Specific Security
# Production environment variables
export JWT_SECRET_KEY=$(openssl rand -hex 32)
export DB_PASSWORD=$(openssl rand -base64 32)
export NEO4J_PASSWORD=$(openssl rand -base64 32)
# Use AWS Secrets Manager, GCP Secret Manager, or Azure Key Vault
aws secretsmanager create-secret --name "quantbot/api-keys" --secret-string '{"GOOGLE_API_KEY":"..."}'
Performance Optimization
Production Optimizations
# app/core/config.py - Production settings
class ProductionConfig:
# Database connection pooling
DATABASE_POOL_SIZE = 20
DATABASE_MAX_OVERFLOW = 30
DATABASE_POOL_TIMEOUT = 30
# API rate limiting
RATE_LIMIT_PER_MINUTE = 60
RATE_LIMIT_BURST = 10
# Caching
CACHE_TTL = 300 # 5 minutes
MEMORY_CACHE_SIZE = 1000
# AI optimizations
MAX_CONCURRENT_AI_REQUESTS = 10
AI_TIMEOUT = 30
# Memory system
MEMORY_BATCH_SIZE = 100
MEMORY_SIMILARITY_THRESHOLD = 0.8
CDN Configuration
# CloudFront distribution for static assets
Resources:
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- DomainName: yourdomain.com
Id: quantbot-origin
CustomOriginConfig:
HTTPPort: 80
HTTPSPort: 443
OriginProtocolPolicy: https-only
DefaultCacheBehavior:
TargetOriginId: quantbot-origin
ViewerProtocolPolicy: redirect-to-https
CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad # CachingOptimized
Enabled: true
Comment: Quantbot CDN
This comprehensive deployment guide provides production-ready configurations for various platforms and includes essential considerations for security, monitoring, and performance optimization.