#!/usr/bin/env bash # Run this ON the EC2 instance (via SSH) after provisioning. # Installs Docker and nginx, then configures the Cloudflare Origin Certificate. # No Certbot or Let's Encrypt — Cloudflare terminates SSL at the edge. # # Prerequisites: # 1. Generate a Cloudflare Origin Certificate for musehub.ai: # Cloudflare Dashboard → musehub.ai → SSL/TLS → Origin Server # → Create Certificate → RSA 2048 → 15 years # Save certificate → /etc/ssl/cloudflare/origin.pem # Save private key → /etc/ssl/cloudflare/origin.key # # 2. In Cloudflare: SSL/TLS → Overview → set mode to "Full (Strict)" # # Usage (from your Mac): # scp -i ~/.ssh/musehub-key.pem -r deploy/ ubuntu@musehub.ai:/home/ubuntu/ # # Copy cert files: # scp -i ~/.ssh/musehub-key.pem origin.pem origin.key ubuntu@musehub.ai:/home/ubuntu/ # ssh -i ~/.ssh/musehub-key.pem ubuntu@musehub.ai # chmod +x ~/deploy/setup-ec2.sh && ~/deploy/setup-ec2.sh set -euo pipefail DOMAIN="musehub.ai www.musehub.ai" SITE_NAME="musehub" APP_DIR="/opt/musehub" echo "==> [1/7] System update" sudo apt-get update -qq && sudo apt-get upgrade -y -qq echo "==> [2/7] Install Docker" curl -fsSL https://get.docker.com | sudo sh sudo usermod -aG docker ubuntu echo " Docker installed. NOTE: You may need to log out/in for the group to take effect." echo " For this script we use 'sudo docker' throughout." echo "==> [3/7] Install nginx" sudo apt-get install -y -qq nginx echo "==> [4/7] Install Cloudflare Origin Certificate" sudo mkdir -p /etc/ssl/cloudflare # Copy certs from home dir if present (scp'd in before running this script) if [ -f ~/origin.pem ] && [ -f ~/origin.key ]; then sudo cp ~/origin.pem /etc/ssl/cloudflare/origin.pem sudo cp ~/origin.key /etc/ssl/cloudflare/origin.key sudo chmod 644 /etc/ssl/cloudflare/origin.pem sudo chmod 640 /etc/ssl/cloudflare/origin.key sudo chown root:root /etc/ssl/cloudflare/origin.pem /etc/ssl/cloudflare/origin.key echo " Origin certificate installed." else echo "" echo " !! CERT FILES NOT FOUND — install them manually before nginx will start:" echo " scp origin.pem origin.key ubuntu@:/home/ubuntu/" echo " sudo cp ~/origin.pem /etc/ssl/cloudflare/origin.pem" echo " sudo cp ~/origin.key /etc/ssl/cloudflare/origin.key" echo " sudo chmod 640 /etc/ssl/cloudflare/origin.key" echo " sudo nginx -s reload" echo "" fi echo "==> [5/7] Configure nginx" # Blue-green active-port file: deploy.sh rewrites this and does nginx -s reload echo "server 127.0.0.1:1337;" | sudo tee /etc/nginx/musehub-active-port > /dev/null # Install the Cloudflare-ready nginx config, substituting the domain(s) sudo sed "s/DOMAIN_PLACEHOLDER/$DOMAIN/g" \ "$(dirname "$0")/nginx-cf.conf" \ | sudo tee /etc/nginx/sites-available/$SITE_NAME > /dev/null sudo ln -sf /etc/nginx/sites-available/$SITE_NAME /etc/nginx/sites-enabled/$SITE_NAME sudo rm -f /etc/nginx/sites-enabled/default sudo nginx -t sudo systemctl reload nginx echo " nginx configured for $DOMAIN" echo "==> [6/7] Create app directory" sudo mkdir -p "$APP_DIR" sudo chown ubuntu:ubuntu "$APP_DIR" echo " $APP_DIR ready — sync code from your Mac with:" echo " rsync -az --exclude='.env' --exclude='node_modules/' --exclude='__pycache__/' \\" echo " --exclude='.muse/' --exclude='*.pyc' \\" echo " -e 'ssh -i ~/.ssh/musehub-key.pem' \\" echo " ~/musehub/ ubuntu@\$(hostname -I | awk '{print \$1}'):$APP_DIR/" echo "==> [7/7] Create production .env" if [ ! -f "$APP_DIR/.env" ]; then DB_PASSWORD=$(openssl rand -hex 16) WEBHOOK_SECRET_KEY=$(python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" 2>/dev/null || echo "GENERATE_ME_WITH_FERNET") cat > "$APP_DIR/.env" << EOF DEBUG=false DATABASE_URL=postgresql+asyncpg://musehub:${DB_PASSWORD}@postgres:5432/musehub DB_PASSWORD=${DB_PASSWORD} CORS_ORIGINS=["https://musehub.ai", "https://www.musehub.ai"] WEBHOOK_SECRET_KEY=${WEBHOOK_SECRET_KEY} MUSEHUB_ALLOWED_ORIGINS=["musehub.ai", "www.musehub.ai"] EOF echo " .env created with generated secrets" echo "" echo " !! SAVE THESE — they are in $APP_DIR/.env !!" cat "$APP_DIR/.env" echo "" else echo " .env already exists, skipping generation" fi echo "" echo "============================================================" echo " SETUP COMPLETE" echo "============================================================" echo " https://$DOMAIN is live" echo " App dir : $APP_DIR" echo " Secrets : $APP_DIR/.env (back these up!)" echo "" echo " Next: sync code, run migrations, start the stack:" echo " rsync -az ... ~/musehub/ ubuntu@:$APP_DIR/" echo " cd $APP_DIR && sudo docker compose up -d postgres musehub-runner" echo " sudo docker compose build musehub" echo " sudo docker compose run --rm --no-deps musehub alembic upgrade head" echo " sudo docker run -d --name musehub-blue --network musehub-internal \\" echo " --env-file .env -e SKIP_MIGRATIONS=1 \\" echo " -e DATABASE_URL=postgresql+asyncpg://musehub:\$(grep ^DB_PASSWORD .env | cut -d= -f2)@postgres:5432/musehub \\" echo " -v musehub_data:/data -p 127.0.0.1:1337:1337 --restart unless-stopped musehub/musehub" echo " bash deploy/deploy.sh --init" echo "" echo " Subsequent deploys (zero downtime):" echo " rsync ... && bash deploy/deploy.sh" echo " Run deploy/seed.sh to create your account + repos" echo "============================================================"