Skip to content

CyberOrigen DigitalOcean Deployment Guide

Complete checklist for deploying CyberOrigen to DigitalOcean instead of AWS.


Prerequisites

  • [ ] DigitalOcean account (use referral link for $200 credit: https://digitalocean.com)
  • [ ] Domain name with DNS access (e.g., Cloudflare, Namecheap)
  • [ ] Stripe account (already have - just need to update webhook URLs)
  • [ ] Anthropic API key (https://console.anthropic.com)
  • [ ] Resend API key (already have)

Phase 1: Create DigitalOcean Resources

1.1 Create Droplet

  1. Go to https://cloud.digitalocean.com/droplets/new
  2. Choose:
    • Region: NYC1 or closest to your users
    • Image: Marketplace → Docker on Ubuntu 22.04
    • Size: Basic → Regular → $24/mo (4GB RAM, 2 vCPUs, 80GB SSD)
    • Authentication: SSH Key (recommended) or Password
    • Hostname: cyberorigen-prod
  3. Click "Create Droplet"
  4. Note the IP address: _______________
  1. Go to https://cloud.digitalocean.com/databases/new
  2. Choose:
    • Engine: PostgreSQL 15
    • Size: Basic → $15/mo (1GB RAM, 1 vCPU)
    • Region: Same as Droplet
    • Name: cyberorigen-db
  3. Click "Create Database Cluster"
  4. Wait for provisioning (~5 minutes)
  5. Note connection details:
    • Host: _______________
    • Port: 25060 (default for managed DB)
    • Database: defaultdb (or create cyberorigen)
    • User: doadmin
    • Password: _______________

Alternative: Run PostgreSQL in Docker (saves $15/mo but less reliable)

1.3 Create Spaces Bucket (S3-Compatible Storage)

  1. Go to https://cloud.digitalocean.com/spaces/new
  2. Choose:
    • Region: NYC3 (or same region as droplet)
    • Name: cyberorigen-evidence
    • File Listing: Restricted
  3. Click "Create Space"
  4. Go to API → Spaces Keys → Generate New Key
  5. Note:
    • Access Key: _______________
    • Secret Key: _______________
    • Endpoint: https://nyc3.digitaloceanspaces.com

Phase 2: Configure DNS

2.1 Add DNS Records

In your DNS provider (Cloudflare, Namecheap, etc.):

TypeNameValueTTL
Abackend<DROPLET_IP>Auto
Aapp<DROPLET_IP>Auto
A@<DROPLET_IP>Auto (optional, for root domain)

Example for cyberorigen.com:

  • backend.cyberorigen.com → Droplet IP
  • app.cyberorigen.com → Droplet IP

2.2 Wait for DNS Propagation

Check propagation: https://dnschecker.org


Phase 3: Server Setup

3.1 SSH into Droplet

bash
ssh root@<DROPLET_IP>

3.2 Create App Directory

bash
mkdir -p /opt/cyberorigen
cd /opt/cyberorigen

3.3 Clone Repository

bash
git clone https://github.com/YOUR_USERNAME/co-development.git .
# Or use deploy key for private repo

3.4 Create Environment File

bash
nano .env

Paste the following (fill in your values):

env
# ===========================================
# CyberOrigen Production Environment
# DigitalOcean Deployment
# ===========================================

# ---- Core Settings ----
ENVIRONMENT=production
DEBUG=false
SECRET_KEY=<generate-with: openssl rand -hex 32>
ENCRYPTION_KEY=<generate-with: python3 -c "import secrets; print(secrets.token_urlsafe(32))">

# ---- API Settings ----
API_HOST=0.0.0.0
API_PORT=8000
FRONTEND_URL=https://app.cyberorigen.com

# ---- Database (DigitalOcean Managed PostgreSQL) ----
POSTGRES_HOST=<your-db-host>.db.ondigitalocean.com
POSTGRES_PORT=25060
POSTGRES_DB=cyberorigen
POSTGRES_USER=doadmin
POSTGRES_PASSWORD=<your-db-password>

# ---- Redis ----
REDIS_URL=redis://redis:6379

# ---- AI Configuration ----
# CRITICAL: Set to false to use direct API instead of Bedrock
AI_TIER_ENFORCEMENT=false
ANTHROPIC_API_KEY=sk-ant-api03-<your-key>
GEMINI_API_KEY=<your-key>
OPENAI_API_KEY=<your-key>

# Default to Claude direct API
BEDROCK_MODEL_ID=claude-sonnet-4-20250514

# ---- Storage (DigitalOcean Spaces) ----
STORAGE_BACKEND=minio
MINIO_ENDPOINT=https://nyc3.digitaloceanspaces.com
MINIO_BUCKET=cyberorigen-evidence
MINIO_ACCESS_KEY=<your-spaces-access-key>
MINIO_SECRET_KEY=<your-spaces-secret-key>
MINIO_USE_SSL=true

# Quarantine storage (same bucket, different prefix)
QUARANTINE_S3_BUCKET=cyberorigen-evidence
QUARANTINE_S3_REGION=nyc3

# ---- Email (Resend) ----
RESEND_API_KEY=re_<your-key>

# ---- Stripe Billing ----
STRIPE_SECRET_KEY=sk_live_<your-key>
STRIPE_PUBLISHABLE_KEY=pk_live_<your-key>
STRIPE_WEBHOOK_SECRET=whsec_<your-key>

# ---- Security Scanning ----
MAX_CONCURRENT_SCANS=3
SCAN_TIMEOUT_MINUTES=120

# ---- Threat Scanning ----
THREAT_SCANNING_ENABLED=true
CLAMAV_HOST=clamav
CLAMAV_PORT=3310

# ---- PII Redaction ----
PII_REDACTION_ENABLED=true
PII_REDACTION_LOG_DETECTIONS=true

# ---- Peppermint Ticketing ----
PEPPERMINT_ENABLED=true
PEPPERMINT_API_URL=http://peppermint:5003
PEPPERMINT_UI_URL=https://tickets.cyberorigen.com
[email protected]
PEPPERMINT_ADMIN_PASSWORD=<strong-password>

3.5 Create Docker Compose for Production

bash
nano docker-compose.prod.yml
yaml
version: '3.8'

services:
  # ===========================================
  # Backend API
  # ===========================================
  api:
    build:
      context: ./backend
      dockerfile: Dockerfile
    container_name: cyberorigen-api
    restart: unless-stopped
    env_file: .env
    ports:
      - "8000:8000"
    volumes:
      - ./backend:/app
      - evidence_data:/app/evidence_storage
      - quarantine_data:/app/quarantine_storage
    depends_on:
      - redis
      - clamav
    networks:
      - cyberorigen
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  # ===========================================
  # Frontend (Production Build)
  # ===========================================
  frontend:
    build:
      context: ./ui_cyberorigen
      dockerfile: Dockerfile
    container_name: cyberorigen-frontend
    restart: unless-stopped
    ports:
      - "3000:80"
    depends_on:
      - api
    networks:
      - cyberorigen

  # ===========================================
  # Redis (Session & Cache)
  # ===========================================
  redis:
    image: redis:7-alpine
    container_name: cyberorigen-redis
    restart: unless-stopped
    volumes:
      - redis_data:/data
    networks:
      - cyberorigen
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 3

  # ===========================================
  # ClamAV (Malware Scanning)
  # ===========================================
  clamav:
    image: clamav/clamav:latest
    container_name: cyberorigen-clamav
    restart: unless-stopped
    volumes:
      - clamav_data:/var/lib/clamav
    networks:
      - cyberorigen
    healthcheck:
      test: ["CMD", "clamdscan", "--version"]
      interval: 60s
      timeout: 10s
      retries: 3

  # ===========================================
  # Caddy (Reverse Proxy + Auto SSL)
  # ===========================================
  caddy:
    image: caddy:2-alpine
    container_name: cyberorigen-caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config
    depends_on:
      - api
      - frontend
    networks:
      - cyberorigen

volumes:
  redis_data:
  clamav_data:
  evidence_data:
  quarantine_data:
  caddy_data:
  caddy_config:

networks:
  cyberorigen:
    driver: bridge

3.6 Create Caddyfile (Auto SSL)

bash
nano Caddyfile
# Backend API
backend.cyberorigen.com {
    reverse_proxy api:8000

    # Security headers
    header {
        X-Content-Type-Options "nosniff"
        X-Frame-Options "DENY"
        Referrer-Policy "strict-origin-when-cross-origin"
    }
}

# Frontend App
app.cyberorigen.com {
    reverse_proxy frontend:3000

    header {
        X-Content-Type-Options "nosniff"
        X-Frame-Options "SAMEORIGIN"
    }
}

# Redirect www to non-www (optional)
www.cyberorigen.com {
    redir https://cyberorigen.com{uri} permanent
}

Phase 4: Deploy

4.1 Build and Start Containers

bash
cd /opt/cyberorigen
docker-compose -f docker-compose.prod.yml build
docker-compose -f docker-compose.prod.yml up -d

4.2 Check Container Status

bash
docker-compose -f docker-compose.prod.yml ps
docker-compose -f docker-compose.prod.yml logs -f api

4.3 Run Database Migrations

bash
docker-compose -f docker-compose.prod.yml exec api alembic upgrade head

4.4 Create Platform Admin User

bash
docker-compose -f docker-compose.prod.yml exec api python -c "
from models.database import SessionLocal, User, Organization
from passlib.context import CryptContext
import uuid

pwd_context = CryptContext(schemes=['bcrypt'], deprecated='auto')
db = SessionLocal()

# Create org
org = Organization(
    name='CyberOrigen Platform',
    org_id=str(uuid.uuid4()),
    subscription_tier='ENTERPRISE',
    is_active=True
)
db.add(org)
db.commit()

# Create admin
admin = User(
    email='[email protected]',
    username='admin',
    hashed_password=pwd_context.hash('<YOUR_ADMIN_PASSWORD>'),
    is_platform_admin=True,
    organization_id=org.id,
    is_active=True
)
db.add(admin)
db.commit()
print(f'Admin created: {admin.email}')
db.close()
"

Phase 5: Update External Services

5.1 Update Stripe Webhook

  1. Go to https://dashboard.stripe.com/webhooks
  2. Update webhook endpoint URL to: https://backend.cyberorigen.com/api/billing/webhook
  3. Note the new webhook secret and update .env

5.2 Update Resend Domain

  1. Verify sending domain in Resend dashboard
  2. Ensure SPF/DKIM records are correct

5.3 Update Frontend API URL

In ui_cyberorigen/vite.config.ts, the proxy should point to production:

typescript
proxy: {
  '/api': {
    target: 'https://backend.cyberorigen.com',
    // ...
  }
}

Phase 6: Testing Checklist

6.1 API Health

bash
curl https://backend.cyberorigen.com/health
# Expected: {"status": "healthy", ...}

6.2 Authentication

bash
curl -X POST https://backend.cyberorigen.com/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "[email protected]", "password": "<password>"}'
# Expected: {"access_token": "...", ...}

6.3 Frontend

  • [ ] Open https://app.cyberorigen.com
  • [ ] Login works
  • [ ] Dashboard loads
  • [ ] Scans can be created
  • [ ] AI chat responds (using Anthropic direct API)

6.4 Stripe

  • [ ] Billing page loads pricing
  • [ ] Test checkout flow (use Stripe test mode first)
  • [ ] Webhooks received (check Stripe dashboard)

6.5 Storage

  • [ ] Upload evidence file
  • [ ] File appears in DigitalOcean Spaces bucket
  • [ ] Download works

Phase 7: Monitoring & Maintenance

7.1 View Logs

bash
# All services
docker-compose -f docker-compose.prod.yml logs -f

# Specific service
docker-compose -f docker-compose.prod.yml logs -f api

7.2 Restart Services

bash
docker-compose -f docker-compose.prod.yml restart api

7.3 Update Deployment

bash
cd /opt/cyberorigen
git pull origin main
docker-compose -f docker-compose.prod.yml build
docker-compose -f docker-compose.prod.yml up -d
docker-compose -f docker-compose.prod.yml exec api alembic upgrade head

7.4 Backup Database

bash
# DigitalOcean Managed DB has automatic backups
# For manual backup:
pg_dump -h <host> -U doadmin -d cyberorigen > backup_$(date +%Y%m%d).sql

Cost Summary

ResourceMonthly Cost
Droplet (4GB)$24
Managed PostgreSQL$15
Spaces (250GB included)$5
Total$44/mo

Optional additions:

  • Increase Droplet to 8GB: +$24 (total $48)
  • Load balancer: +$12
  • Managed Redis: +$15

Troubleshooting

Container won't start

bash
docker-compose -f docker-compose.prod.yml logs api
# Check for missing env vars or connection errors

Database connection refused

  • Check POSTGRES_HOST is the full DO hostname
  • Ensure Droplet IP is in database trusted sources
  • Verify port is 25060 (not 5432)

SSL certificate errors

bash
docker-compose -f docker-compose.prod.yml logs caddy
# Caddy auto-provisions certs, check DNS is correct

AI not responding

  • Verify AI_TIER_ENFORCEMENT=false
  • Check ANTHROPIC_API_KEY is valid
  • Test key: curl https://api.anthropic.com/v1/messages -H "x-api-key: $ANTHROPIC_API_KEY"

Spaces upload fails

  • Check endpoint is https://nyc3.digitaloceanspaces.com (with region)
  • Verify access key has write permissions
  • Ensure MINIO_USE_SSL=true

Quick Reference Commands

bash
# SSH to server
ssh root@<DROPLET_IP>

# Go to app directory
cd /opt/cyberorigen

# View running containers
docker ps

# View logs
docker-compose -f docker-compose.prod.yml logs -f

# Restart everything
docker-compose -f docker-compose.prod.yml restart

# Full rebuild
docker-compose -f docker-compose.prod.yml down
docker-compose -f docker-compose.prod.yml build --no-cache
docker-compose -f docker-compose.prod.yml up -d

# Run migrations
docker-compose -f docker-compose.prod.yml exec api alembic upgrade head

# Enter API container shell
docker-compose -f docker-compose.prod.yml exec api bash

Document Version: 1.0 Created: 2024-12-23 For: CyberOrigen GRC Platform

Agentic AI-Powered Security & Compliance