Deployment Guide

This guide covers deployment strategies, production configurations, and operational best practices.

Table of Contents


Pre-Deployment Checklist

Security

  • ✅ API keys stored in environment variables (not hardcoded)
  • ✅ Use IP whitelisting on Binance
  • ✅ Enable withdrawal whitelist
  • ✅ Use sub-account for trading
  • ✅ Rotate API keys regularly

See: Security Guide for detailed credential management

Testing

  • ✅ Test on testnet first
  • ✅ Verify order placement/cancellation
  • ✅ Test with small position sizes
  • ✅ Monitor for 24 hours before scaling

See: Getting Started for testing procedures

Monitoring

  • ✅ Set up log aggregation (Loki/Elasticsearch)
  • ✅ Configure alerts for errors
  • ✅ Monitor API response times
  • ✅ Track position P&L
  • ✅ Set up Grafana MCP for AI-powered monitoring

See: Monitoring Guide for comprehensive observability setup

Infrastructure

  • ✅ Run on reliable server (not laptop)
  • ✅ Use systemd for process management
  • ✅ Configure automatic restarts
  • ✅ Set up backup strategies

Production Deployment Options

Choose the deployment method that best fits your infrastructure:

graph LR
    A[Deployment Options] --> B[Systemd Service]
    A --> C[Docker Container]
    A --> D[Kubernetes Pod]
    
    B --> B1[Single Server<br/>Minimal Complexity<br/>systemctl management]
    C --> C1[Docker Compose<br/>Local/Cloud<br/>With monitoring stack]
    D --> D1[High Availability<br/>Auto-scaling<br/>Production scale]
    
    style B fill:#90caf9
    style C fill:#a5d6a7
    style D fill:#ce93d8

Best for single-server deployments with minimal complexity.

Service Configuration

Create /etc/systemd/system/wealth.service:

[Unit]
Description=Wealth Trading Bot
After=network.target

[Service]
Type=simple
User=trader
WorkingDirectory=/home/trader
Environment="CREDENTIALS_PASSPHRASE=your-secure-passphrase"
Environment="WEALTH__EXECUTION__MODE=live"
Environment="WEALTH__LICENSING__LICENSE_KEY=your-license-key"
ExecStart=/usr/local/bin/wealth run
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Enable and Start

# Reload systemd configuration
sudo systemctl daemon-reload

# Enable service to start on boot
sudo systemctl enable wealth

# Start the service
sudo systemctl start wealth

# Check service status
sudo systemctl status wealth

# View logs
sudo journalctl -u wealth -f

Management Commands

# Stop the service
sudo systemctl stop wealth

# Restart the service
sudo systemctl restart wealth

# Check service health
sudo systemctl is-active wealth

# View recent logs
sudo journalctl -u wealth -n 100

Docker Deployment

Best for containerized environments and cloud deployments.

# Pull the latest image
docker pull ghcr.io/thiras/wealth:latest

# Run with encrypted credentials
docker run -d --name wealth \
  -v $(pwd)/config.toml:/app/config.toml \
  -v $(pwd)/credentials.encrypted.json:/app/credentials.encrypted.json \
  -e CREDENTIALS_PASSPHRASE=your-passphrase \
  -e WEALTH__EXECUTION__MODE=live \
  -e WEALTH__LICENSING__LICENSE_KEY=your-license-key \
  ghcr.io/thiras/wealth:latest

See compose.yml in the project root for a complete setup including OpenTelemetry Collector and Grafana.

# Download compose file
curl -LO https://raw.githubusercontent.com/thiras/wealth/main/compose.yml

# Start all services
docker compose up -d

# View logs
docker compose logs -f wealth

# Stop all services
docker compose down

Building Custom Image


Kubernetes (Advanced)

Best for production-scale deployments requiring high availability and orchestration.

The official Helm chart provides a complete Kubernetes deployment with security best practices:

# Login to GitHub Container Registry
helm registry login ghcr.io -u YOUR_GITHUB_USERNAME

# Install the chart
helm install wealth oci://ghcr.io/thiras/charts/wealth \
  --version 0.52.3 \
  --namespace wealth \
  --create-namespace \
  --set credentials.existingSecret=wealth-secrets \
  --set wealth.executionMode=live

# Verify the installation
helm list -n wealth
kubectl get pods -n wealth

Create secrets first:

# Create namespace
kubectl create namespace wealth

# Create secrets for credentials
kubectl create secret generic wealth-secrets \
  --namespace wealth \
  --from-literal=CREDENTIALS_PASSPHRASE=your-passphrase \
  --from-literal=BINANCE_API_KEY=xxx \
  --from-literal=BINANCE_SECRET_KEY=yyy

Verify chart signature (recommended):

# Verify with Cosign
cosign verify oci://ghcr.io/thiras/charts/wealth:0.52.3 \
  --certificate-identity-regexp="https://github.com/thiras/wealth/.github/workflows/helm-release.yml@.*" \
  --certificate-oidc-issuer="https://token.actions.githubusercontent.com"

For chart configuration options, see:

helm show values oci://ghcr.io/thiras/charts/wealth --version 0.52.3

tmux Session (Optional)

For terminal-based access with detach support, enable tmux. The dashboard runs inside a tmux session, allowing you to detach (Ctrl+B D) and reattach without stopping the bot.

wealth:
  command: dashboard  # Required for tmux mode

tmux:
  enabled: true
  sessionName: wealth  # Custom session name (optional)

Access the dashboard:

# Attach to the pod (connects to tmux session)
kubectl attach -it <pod-name>

# To detach: Press Ctrl+B, then D
# The bot continues running in the background

# To reattach later:
kubectl attach -it <pod-name>

Note: tmux and ttyd are mutually exclusive. If both are enabled, ttyd takes precedence.

ttyd Web Terminal (Optional)

The Helm chart supports browser-based access to the TUI dashboard via ttyd. When enabled, ttyd runs as the main process and spawns the wealth dashboard, allowing you to view and interact with the TUI from your browser. This provides proper detach support - just close the browser tab and the bot continues running.

# Enable ttyd web terminal for dashboard access
ttyd:
  enabled: true
  port: 7681

  # Optional: Enable basic authentication (recommended for production)
  auth:
    enabled: true
    username: "admin"
    password: "secure-password"  # Use --set or external secrets, not in VCS

  # Optional: Expose via ingress (path added to all configured hosts)
  ingress:
    enabled: true
    path: /terminal
    pathType: Prefix

Access the dashboard:

# Port forward to the pod
kubectl port-forward pod/<pod-name> 7681:7681

# Open in browser
open http://localhost:7681

You can also access via ingress if configured: https://wealth.example.com/terminal

Security Note: ttyd provides full terminal access to the dashboard. Use authentication and network policies in production.

OpenTelemetry Collector Sidecar

The Helm chart includes an OTEL Collector sidecar for metrics, logs, and traces. With the Prometheus exporter enabled (default), metrics can be scraped by in-cluster Prometheus:

otelCollector:
  enabled: true
  
  # Prometheus exporter for ServiceMonitor scraping (default: enabled)
  prometheus:
    enabled: true   # Exposes :8889/metrics for Prometheus
    port: 8889
  
  # In-cluster endpoints (no auth required)
  lokiEndpoint: "http://loki-gateway.meta.svc.cluster.local:3100"
  tempoEndpoint: "tempo.meta.svc.cluster.local:4317"
  
  # OR Grafana Cloud (with auth)
  grafanaCloud:
    username: "123456"
    apiToken: "glc_xxx..."
    prometheusEndpoint: "https://prometheus-xxx.grafana.net/api/prom/push"
    lokiEndpoint: "https://logs-xxx.grafana.net"
    tempoEndpoint: "https://tempo-xxx.grafana.net:443"

Metrics flow:

App → OTLP → OTEL Collector → Prometheus Exporter (:8889) → ServiceMonitor scrape

Note: The app's /metrics endpoint returns JSON config info, not Prometheus format. Enable otelCollector.prometheus.enabled=true for Prometheus-compatible metrics.

See Monitoring Guide for details on the metrics architecture.

Manual Deployment (Without Helm)

For environments where Helm is not available:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: wealth-trading-bot
spec:
  replicas: 1
  selector:
    matchLabels:
      app: wealth
  template:
    metadata:
      labels:
        app: wealth
    spec:
      containers:
      - name: wealth
        image: wealth:latest
        env:
        - name: CREDENTIALS_PASSPHRASE
          valueFrom:
            secretKeyRef:
              name: wealth-secrets
              key: credentials-passphrase
        - name: WEALTH__LICENSING__LICENSE_KEY
          valueFrom:
            secretKeyRef:
              name: wealth-secrets
              key: license-key
        - name: WEALTH__EXECUTION__MODE
          value: "live"
        volumeMounts:
        - name: credentials
          mountPath: /app/credentials.encrypted.json
          subPath: credentials.encrypted.json
          readOnly: true
        - name: credentials
          mountPath: /app/.credentials.salt
          subPath: .credentials.salt
          readOnly: true
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"

Secrets Management

# Create secret for API credentials
kubectl create secret generic exchange-credentials \
  --from-literal=binance-api-key=xxx \
  --from-literal=binance-secret-key=yyy

# Apply deployment
kubectl apply -f deployment.yaml

# Check pod status
kubectl get pods -l app=wealth

# View logs
kubectl logs -l app=wealth -f

Deployment Best Practices

1. Environment Separation

Maintain separate configurations for different environments:

# Development
export WEALTH__EXECUTION__MODE=paper
# Configure testnet in config.toml or use encrypted credentials with testnet keys

# Staging
export WEALTH__EXECUTION__MODE=paper
# Use production API endpoints with paper mode for testing

# Production
export WEALTH__EXECUTION__MODE=live
export WEALTH__LICENSING__LICENSE_KEY=your-license-key
# Use encrypted credentials with production API keys

2. Graceful Shutdown

The bot implements graceful shutdown (6-8 seconds typical):

What happens:

  1. Stop accepting - No new trades initiated
  2. Close positions - All active positions closed safely
  3. Cleanup - Statistics printed, connections closed

Trigger Options:

# Interactive mode
Ctrl+C

# Send graceful shutdown signal
kill -SIGTERM $(pidof wealth)

# Docker/Kubernetes (automatic on stop)
docker stop wealth  # Sends SIGTERM, waits 10s, then SIGKILL

Monitoring Shutdown:

  • Watch logs for "Shutdown signal received" messages
  • Verify "All positions closed successfully" message
  • Check final statistics in logs before exit

Configuration:

# Docker Compose
services:
  wealth:
    stop_grace_period: 10s

# Kubernetes
terminationGracePeriodSeconds: 10

3. Health Checks

Use the health endpoint for container orchestration:

# Check bot health
curl http://localhost:9090/health

# Kubernetes liveness probe
livenessProbe:
  httpGet:
    path: /health
    port: 9090
  initialDelaySeconds: 30
  periodSeconds: 10

4. Log Rotation

Configure log rotation to prevent disk space issues:

# systemd journal rotation
sudo journalctl --vacuum-time=7d
sudo journalctl --vacuum-size=500M

5. Backup Strategies

  • Backup configuration files regularly
  • Document API key rotation procedures


Next Steps

After deployment:

  1. Monitor logs for the first 24 hours
  2. Verify metrics are being collected
  3. Test graceful shutdown and automatic restart
  4. Set up alerting for critical errors
  5. Document your deployment-specific configurations

For ongoing operations, see the Monitoring Guide.