# 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 ### Recommended Specifications **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](https://cloud.digitalocean.com/droplets/new) 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 ```bash ssh root@YOUR_DROPLET_IP ``` ### Update System ```bash apt update && apt upgrade -y ``` ### Create Non-Root User ```bash adduser vipcoord usermod -aG sudo vipcoord usermod -aG docker vipcoord # Will add docker group later ``` ### Configure Firewall (UFW) ```bash # 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 ```bash # 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 ### Option A: Public Gitea (Recommended) If your Gitea is publicly accessible: ```bash # 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** ```bash # 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: ```bash # 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 ```bash # 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 ```bash # On droplet cd /home/vipcoord # Copy and edit environment file cp .env.digitalocean.example .env.digitalocean nano .env.digitalocean ``` **Update these values:** ```env # 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 ```bash # 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 ### Option A: Caddy (Recommended - Easiest) Create `Caddyfile`: ```bash nano Caddyfile ``` ```caddy your-domain.com { reverse_proxy localhost:80 } ``` Run Caddy: ```bash 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`: ```yaml 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](https://manage.auth0.com/) 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: ```bash nano /home/vipcoord/backup-db.sh ``` ```bash #!/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: ```bash 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 ```bash # 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 ```bash docker ps docker compose -f docker-compose.digitalocean.yml ps ``` ### Monitor Resources ```bash # Real-time resource usage docker stats # Disk usage df -h docker system df ``` ## Step 10: Updating Application When you push new images to Gitea: ```bash # 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 ```bash # 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 ```bash # 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 - **Digital Ocean Docs:** https://docs.digitalocean.com/ - **Docker Docs:** https://docs.docker.com/ - **Auth0 Docs:** https://auth0.com/docs ## 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`