Docker Deployment¶
Deploy TradeTally using Docker and Docker Compose for a production-ready setup.
Quick Start¶
# Download docker-compose.yaml
curl -O https://raw.githubusercontent.com/GeneBO98/tradetally/refs/heads/main/docker-compose.yaml
# Download environment template
curl -O https://raw.githubusercontent.com/GeneBO98/tradetally/main/.env.example
mv .env.example .env
# Edit .env with your configuration
nano .env
# Start TradeTally
docker-compose up -d
# View logs
docker-compose logs -f app
TradeTally will be available at http://localhost:8080.
Prerequisites¶
- Docker Engine 20.10+
- Docker Compose 2.0+
- 2GB+ RAM available
- 10GB+ disk space
Docker Image¶
TradeTally is available as a pre-built Docker image:
Docker Hub: potentialmidas/tradetally
Configuration¶
Required Environment Variables¶
Create a .env file with the following variables:
# Database Configuration
DB_USER=trader
DB_PASSWORD=CHANGE_THIS_PASSWORD
DB_NAME=tradetally
# JWT Configuration
JWT_SECRET=CHANGE_THIS_TO_LONG_RANDOM_STRING
# Registration Control
REGISTRATION_MODE=open
# API Keys (Optional but recommended)
FINNHUB_API_KEY=your_finnhub_api_key
ALPHA_VANTAGE_API_KEY=your_alpha_vantage_api_key
OPENFIGI_API_KEY=your_openfigi_api_key
Security
Must change DB_PASSWORD and JWT_SECRET before deploying to production!
Optional Environment Variables¶
# Node Environment
NODE_ENV=production
PORT=3000
# Frontend Configuration
FRONTEND_URL=http://localhost
# File Upload (50MB limit)
MAX_FILE_SIZE=52428800
# Email Configuration (Optional)
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
[email protected]
EMAIL_PASS=your_app_password
# Push Notifications (Optional)
ENABLE_PUSH_NOTIFICATIONS=false
APNS_KEY_ID=ABC123DEFG
APNS_TEAM_ID=1234567890
APNS_KEY_PATH=/path/to/keys/AuthKey.p8
# Broker Sync Configuration (Optional)
# Required if using Schwab integration
BROKER_ENCRYPTION_KEY=your_32_byte_hex_key # Generate with: openssl rand -hex 32
SCHWAB_CLIENT_ID=your_schwab_client_id
SCHWAB_CLIENT_SECRET=your_schwab_client_secret
SCHWAB_REDIRECT_URI=https://your-domain.com/api/broker-sync/connections/schwab/callback
Feature Toggles¶
Control background services and features to optimize resource usage:
# Background Services (set to 'false' to disable)
ENABLE_PRICE_MONITORING=true # Real-time price monitoring for watchlists
ENABLE_TRADE_ENRICHMENT=true # Auto-enrich trades with market data
ENABLE_JOB_RECOVERY=true # Recover failed background jobs
ENABLE_GAMIFICATION=true # Achievements and badges system
ENABLE_TRIAL_EMAILS=true # Trial expiration email notifications
ENABLE_OPTIONS_SCHEDULER=true # Options-related scheduled tasks
ENABLE_BACKUP_SCHEDULER=true # Automated backup scheduling
ENABLE_ENRICHMENT_CACHE_CLEANUP=true # Clean stale enrichment cache
FEATURES_BEHAVIORAL_ANALYTICS_ENABLED=true # Behavioral pattern analysis
# API Documentation
ENABLE_SWAGGER=true # Enable Swagger API docs at /api-docs
# Database
RUN_MIGRATIONS=true # Auto-run migrations on startup
System Configuration¶
# Logging
LOG_LEVEL=INFO # DEBUG, INFO, WARN, ERROR
# Timezone (affects admin metrics)
TZ=UTC # Server timezone
# Rate Limiting (set RATE_LIMIT_ENABLED=false for self-hosted)
RATE_LIMIT_ENABLED=true # Enable API rate limiting
RATE_LIMIT_MAX=1000 # Max requests per window
RATE_LIMIT_WINDOW_MS=900000 # Window duration (15 minutes)
Docker Compose Configuration¶
Production Setup¶
version: '3.8'
services:
# PostgreSQL Database
postgres:
image: postgres:16-alpine
container_name: tradetally-db
environment:
POSTGRES_USER: ${DB_USER:-trader}
POSTGRES_PASSWORD: ${DB_PASSWORD:-trader_password}
POSTGRES_DB: ${DB_NAME:-tradetally}
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
networks:
- trader-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-trader} -d ${DB_NAME:-tradetally}"]
interval: 10s
timeout: 5s
retries: 5
# Application (Frontend + Backend)
app:
image: potentialmidas/tradetally:latest
container_name: tradetally-app
depends_on:
postgres:
condition: service_healthy
environment:
# Backend environment variables
NODE_ENV: ${NODE_ENV:-production}
PORT: ${PORT:-3000}
DB_HOST: postgres
DB_PORT: 5432
DB_USER: ${DB_USER:-trader}
DB_PASSWORD: ${DB_PASSWORD:-trader_password}
DB_NAME: ${DB_NAME:-tradetally}
JWT_SECRET: ${JWT_SECRET:-your_jwt_secret_here}
JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-7d}
# Frontend API URL
VITE_API_URL: ${VITE_API_URL:-http://localhost/api}
# CORS Configuration
FRONTEND_URL: ${FRONTEND_URL:-http://localhost:5173}
CORS_ORIGINS: ${CORS_ORIGINS:-}
# Registration Control
REGISTRATION_MODE: ${REGISTRATION_MODE:-open}
# API Documentation
ENABLE_SWAGGER: ${ENABLE_SWAGGER:-true}
# External API Keys
FINNHUB_API_KEY: ${FINNHUB_API_KEY:-}
ALPHA_VANTAGE_API_KEY: ${ALPHA_VANTAGE_API_KEY:-}
GEMINI_API_KEY: ${GEMINI_API_KEY:-}
# Schwab OAuth Configuration
SCHWAB_CLIENT_ID: ${SCHWAB_CLIENT_ID:-}
SCHWAB_CLIENT_SECRET: ${SCHWAB_CLIENT_SECRET:-}
SCHWAB_REDIRECT_URI: ${SCHWAB_REDIRECT_URI:-}
BROKER_ENCRYPTION_KEY: ${BROKER_ENCRYPTION_KEY:-}
# Database Configuration
RUN_MIGRATIONS: ${RUN_MIGRATIONS:-true}
# Feature Toggles
ENABLE_PRICE_MONITORING: ${ENABLE_PRICE_MONITORING:-true}
ENABLE_TRADE_ENRICHMENT: ${ENABLE_TRADE_ENRICHMENT:-true}
ENABLE_GAMIFICATION: ${ENABLE_GAMIFICATION:-true}
# Logging
LOG_LEVEL: ${LOG_LEVEL:-INFO}
# Timezone
TZ: ${TZ:-UTC}
# Rate Limiting
RATE_LIMIT_ENABLED: ${RATE_LIMIT_ENABLED:-true}
RATE_LIMIT_MAX: ${RATE_LIMIT_MAX:-1000}
RATE_LIMIT_WINDOW_MS: ${RATE_LIMIT_WINDOW_MS:-900000}
ports:
- "8080:80"
- "3001:3000"
volumes:
- ./backend/src/logs:/app/backend/src/logs
- ./backend/src/data:/app/backend/src/data
- ./backend/uploads:/app/backend/uploads
networks:
- trader-network
restart: unless-stopped
networks:
trader-network:
driver: bridge
volumes:
postgres_data:
driver: local
Development Setup¶
Use docker-compose.dev.yaml for development with hot-reload:
Managing the Container¶
Start Services¶
Stop Services¶
View Logs¶
# All logs
docker-compose logs -f
# Application logs only
docker-compose logs -f app
# Database logs only
docker-compose logs -f postgres
Restart Services¶
Update to Latest Version¶
Networking¶
Default Ports¶
| Service | Host Port | Container Port | Description |
|---|---|---|---|
| Frontend/Nginx | 8080 | 80 | Web interface |
| Backend API | 3001 | 3000 | REST API (direct access) |
| PostgreSQL | 5432 | 5432 | Database |
Port Configuration
The default docker-compose.yaml maps port 8080 to the web interface. Access TradeTally at http://localhost:8080. Change 8080:80 to 80:80 if you want to use port 80.
Reverse Proxy Setup¶
If using a reverse proxy (Nginx, Caddy, Traefik):
server {
listen 80;
server_name tradetally.example.com;
location / {
proxy_pass http://localhost:80;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $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;
}
client_max_body_size 50M;
}
Data Persistence¶
Volume Mounts¶
- postgres_data: Database files (persisted)
- ./backend/src/logs: Application logs (host mount)
- ./backend/src/data: Application data, including CUSIP cache (host mount)
- ./backend/uploads: User uploaded files and attachments (host mount)
Backup Database¶
# Create backup
docker-compose exec postgres pg_dump -U trader tradetally > backup_$(date +%Y%m%d).sql
# Restore backup
docker-compose exec -T postgres psql -U trader tradetally < backup_20240101.sql
Backup Application Data¶
SSL/HTTPS Setup¶
Using Certbot¶
# Install Certbot
sudo apt install certbot python3-certbot-nginx
# Get SSL certificate
sudo certbot --nginx -d tradetally.example.com
# Auto-renewal
sudo crontab -e
# Add: 0 12 * * * /usr/bin/certbot renew --quiet
Docker with SSL¶
Update docker-compose.yaml to mount SSL certificates:
services:
app:
volumes:
- ./ssl/cert.pem:/etc/ssl/certs/cert.pem:ro
- ./ssl/key.pem:/etc/ssl/private/key.pem:ro
environment:
- SSL_ENABLED=true
Health Checks¶
Application Health¶
# Check application status
curl http://localhost/api/health
# Expected response
{"status":"ok","database":"connected"}
Database Health¶
Monitoring¶
Container Stats¶
Log Monitoring¶
# Watch application logs
tail -f backend/src/logs/*.log
# Watch Nginx access logs
docker-compose exec app tail -f /var/log/nginx/access.log
Troubleshooting¶
Container Won't Start¶
# Check container logs
docker-compose logs app
# Check if ports are in use
lsof -i :80
lsof -i :5432
# Restart services
docker-compose restart
Database Connection Issues¶
# Verify database is running
docker-compose ps postgres
# Check database logs
docker-compose logs postgres
# Test database connection
docker-compose exec app psql -h postgres -U trader -d tradetally -c "SELECT 1;"
Permission Issues¶
# Fix volume permissions
sudo chown -R $USER:$USER backend/src/logs backend/src/data
# Restart container
docker-compose restart app
Out of Memory¶
# Check memory usage
docker stats tradetally-app
# Increase memory limit in docker-compose.yaml
services:
app:
deploy:
resources:
limits:
memory: 2G
Production Considerations¶
Security¶
- Change default passwords
- Use strong JWT secret
- Enable SSL/HTTPS
- Configure firewall rules
- Regular security updates
Performance¶
- Use SSD for database volume
- Allocate adequate RAM (4GB+ recommended)
- Configure connection pooling
- Enable gzip compression
Backups¶
- Automated daily database backups
- Off-site backup storage
- Test restore procedures
- Backup application data
Monitoring¶
- Set up uptime monitoring
- Configure log aggregation
- Monitor disk space
- Track API usage
Advanced Configuration¶
Custom Port¶
External Database¶
Multiple Instances¶
Use Docker Swarm or Kubernetes for load balancing:
# Docker Swarm
docker stack deploy -c docker-compose.yaml tradetally
# Kubernetes
kubectl apply -f kubernetes/
Next Steps¶
- Installation Guide - Install from source
- Quick Start - Get started quickly
- API Configuration - Configure external APIs