Files
vip-coordinator/DIGITAL_OCEAN_DEPLOYMENT.md
kyle e9de71ce29 feat: add Digital Ocean deployment configuration
- Create docker-compose.digitalocean.yml for registry-based deployment
- Add .env.digitalocean.example template for cloud deployment
- Add comprehensive DIGITAL_OCEAN_DEPLOYMENT.md guide
- Configure image pulling from Gitea registry
- Include SSL setup with Caddy/Traefik
- Add backup, monitoring, and security instructions

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-31 20:09:48 +01:00

9.8 KiB

VIP Coordinator - Digital Ocean Deployment Guide

Overview

This guide walks you through deploying VIP Coordinator to Digital Ocean using pre-built Docker images from your Gitea registry.

Prerequisites

  • Digital Ocean account
  • Docker images pushed to Gitea registry (completed )
  • Domain name (recommended) or will use droplet IP
  • Auth0 account configured

Architecture

Internet
    │
    ├─> Your Domain (optional)
    │
    ↓
[Digital Ocean Droplet]
    │
    ├─> Caddy/Traefik (Reverse Proxy + SSL)
    │       ↓
    ├─> Frontend Container (port 80)
    │       ↓
    ├─> Backend Container (port 3000)
    │       ↓
    ├─> PostgreSQL Container
    │       ↓
    └─> Redis Container

Step 1: Create Digital Ocean Droplet

Minimum (Testing):

  • Size: Basic Droplet - $12/month
  • RAM: 2GB
  • CPU: 1 vCPU
  • Storage: 50GB SSD
  • Region: Choose closest to your users

Recommended (Production):

  • Size: General Purpose - $24/month
  • RAM: 4GB
  • CPU: 2 vCPUs
  • Storage: 80GB SSD
  • Region: Choose closest to your users

Create Droplet

  1. Go to Digital Ocean
  2. Choose Image: Ubuntu 24.04 LTS x64
  3. Choose Size: Select based on recommendations above
  4. Choose Region: Select closest region
  5. Authentication: SSH keys (recommended) or password
  6. Hostname: vip-coordinator
  7. Tags: production, vip-coordinator
  8. Backups: Enable weekly backups (recommended)
  9. Click Create Droplet

Step 2: Initial Server Setup

SSH into Droplet

ssh root@YOUR_DROPLET_IP

Update System

apt update && apt upgrade -y

Create Non-Root User

adduser vipcoord
usermod -aG sudo vipcoord
usermod -aG docker vipcoord  # Will add docker group later

Configure Firewall (UFW)

# Enable UFW
ufw default deny incoming
ufw default allow outgoing

# Allow SSH
ufw allow OpenSSH

# Allow HTTP and HTTPS
ufw allow 80/tcp
ufw allow 443/tcp

# Enable firewall
ufw enable

# Check status
ufw status

Step 3: Install Docker

# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

# Add user to docker group
usermod -aG docker vipcoord

# Install Docker Compose
apt install docker-compose-plugin -y

# Verify installation
docker --version
docker compose version

Step 4: Configure Gitea Registry Access

If your Gitea is publicly accessible:

# Login to Gitea registry
docker login YOUR_PUBLIC_GITEA_URL:3000 -u kyle
# Enter your Gitea token: 2f4370ce710a4a1f84e8bf6c459fe63041376c0e

Option B: Gitea on LAN (Requires VPN/Tunnel)

If your Gitea is on LAN (192.168.68.53):

Solutions:

  1. Tailscale VPN (Recommended)

    • Install Tailscale on both your local machine and Digital Ocean droplet
    • Access Gitea via Tailscale IP
  2. SSH Tunnel

    # On your local machine
    ssh -L 3000:192.168.68.53:3000 root@YOUR_DROPLET_IP
    
  3. Expose Gitea Publicly (Not Recommended for Security)

    • Configure port forwarding on your router
    • Use dynamic DNS service
    • Set up Cloudflare tunnel

Option C: Alternative - Push to Docker Hub

If Gitea access is complex, push images to Docker Hub instead:

# On your local machine
docker tag 192.168.68.53:3000/kyle/vip-coordinator/backend:latest kyle/vip-coordinator-backend:latest
docker tag 192.168.68.53:3000/kyle/vip-coordinator/frontend:latest kyle/vip-coordinator-frontend:latest

docker push kyle/vip-coordinator-backend:latest
docker push kyle/vip-coordinator-frontend:latest

Then update docker-compose.digitalocean.yml to use Docker Hub images.

Step 5: Deploy Application

Copy Files to Droplet

# On your local machine
scp docker-compose.digitalocean.yml root@YOUR_DROPLET_IP:/home/vipcoord/
scp .env.digitalocean.example root@YOUR_DROPLET_IP:/home/vipcoord/

Configure Environment

# On droplet
cd /home/vipcoord

# Copy and edit environment file
cp .env.digitalocean.example .env.digitalocean
nano .env.digitalocean

Update these values:

# If using LAN Gitea via Tailscale
GITEA_REGISTRY=100.x.x.x:3000

# If using public Gitea
GITEA_REGISTRY=gitea.yourdomain.com:3000

# If using Docker Hub
# Comment out GITEA_REGISTRY and update image names in docker-compose

# Strong database password
POSTGRES_PASSWORD=YOUR_STRONG_PASSWORD_HERE

# Auth0 configuration (same as before)
AUTH0_DOMAIN=dev-s855cy3bvjjbkljt.us.auth0.com
AUTH0_CLIENT_ID=JXEVOIfS5eYCkeKbbCWIkBYIvjqdSP5d
AUTH0_AUDIENCE=https://vip-coordinator-api
AUTH0_ISSUER=https://dev-s855cy3bvjjbkljt.us.auth0.com/

Start Services

# Start all services
docker compose -f docker-compose.digitalocean.yml --env-file .env.digitalocean up -d

# Check status
docker compose -f docker-compose.digitalocean.yml ps

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

Step 6: Set Up Reverse Proxy with SSL

Create Caddyfile:

nano Caddyfile
your-domain.com {
    reverse_proxy localhost:80
}

Run Caddy:

docker run -d \
  --name caddy \
  -p 80:80 \
  -p 443:443 \
  -v /home/vipcoord/Caddyfile:/etc/caddy/Caddyfile \
  -v caddy_data:/data \
  -v caddy_config:/config \
  --restart unless-stopped \
  caddy:latest

Caddy automatically handles:

  • SSL certificate from Let's Encrypt
  • HTTP to HTTPS redirect
  • Certificate renewal

Option B: Traefik

Create docker-compose.traefik.yml:

version: '3.8'

services:
  traefik:
    image: traefik:v2.10
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.letsencrypt.acme.email=your@email.com"
      - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
      - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./letsencrypt:/letsencrypt"
    restart: unless-stopped

Step 7: Configure Auth0

Update Auth0 application settings:

  1. Go to Auth0 Dashboard
  2. Select your application
  3. Allowed Callback URLs: Add https://your-domain.com
  4. Allowed Web Origins: Add https://your-domain.com
  5. Allowed Logout URLs: Add https://your-domain.com
  6. Click Save Changes

Step 8: Database Backups

Automated Daily Backups

Create backup script:

nano /home/vipcoord/backup-db.sh
#!/bin/bash
BACKUP_DIR="/home/vipcoord/backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

mkdir -p $BACKUP_DIR

docker exec vip-coordinator-postgres pg_dump -U vip_user vip_coordinator | gzip > $BACKUP_DIR/vip_coordinator_$TIMESTAMP.sql.gz

# Keep only last 7 days
find $BACKUP_DIR -name "vip_coordinator_*.sql.gz" -mtime +7 -delete

Make executable and add to cron:

chmod +x /home/vipcoord/backup-db.sh

# Add to crontab (daily at 2 AM)
crontab -e
# Add this line:
0 2 * * * /home/vipcoord/backup-db.sh

Step 9: Monitoring and Logging

View Logs

# All services
docker compose -f docker-compose.digitalocean.yml logs -f

# Specific service
docker compose -f docker-compose.digitalocean.yml logs -f backend

# Last 100 lines
docker compose -f docker-compose.digitalocean.yml logs --tail=100 backend

Check Container Health

docker ps
docker compose -f docker-compose.digitalocean.yml ps

Monitor Resources

# Real-time resource usage
docker stats

# Disk usage
df -h
docker system df

Step 10: Updating Application

When you push new images to Gitea:

# On droplet
cd /home/vipcoord

# Pull latest images
docker compose -f docker-compose.digitalocean.yml pull

# Restart with new images
docker compose -f docker-compose.digitalocean.yml down
docker compose -f docker-compose.digitalocean.yml up -d

# Verify
docker compose -f docker-compose.digitalocean.yml ps
docker compose -f docker-compose.digitalocean.yml logs -f

Troubleshooting

Application Not Accessible

  1. Check firewall: ufw status
  2. Check containers: docker ps
  3. Check logs: docker compose logs -f
  4. Check Auth0 callback URLs match your domain

Database Connection Issues

# Check postgres is running
docker exec vip-coordinator-postgres pg_isready -U vip_user

# Check backend can connect
docker compose logs backend | grep -i database

SSL Certificate Issues

# Caddy logs
docker logs caddy

# Force certificate renewal
docker exec caddy caddy reload --config /etc/caddy/Caddyfile

Security Checklist

  • Firewall configured (only 22, 80, 443 open)
  • SSH key authentication (disable password auth)
  • Non-root user for application
  • Strong database password
  • Auth0 callbacks restricted to production domain
  • Automated backups configured
  • SSL/TLS enabled
  • Regular system updates scheduled
  • Fail2ban installed for SSH protection
  • Docker containers run as non-root users

Cost Estimation

Monthly Costs:

  • Droplet (4GB): $24/month
  • Backups (20%): ~$5/month
  • Total: ~$29/month

Optional:

  • Domain name: $10-15/year
  • Digital Ocean Managed Database (if scaling): $15/month+

Support

Next Steps

  1. Set up domain name (optional but recommended)
  2. Configure monitoring (Uptime Robot, etc.)
  3. Set up log aggregation (Digital Ocean Monitoring, Papertrail)
  4. Configure automated updates
  5. Add staging environment for testing

Deployment completed! 🚀

Your VIP Coordinator is now live at https://your-domain.com