#!/bin/bash set -e GREEN='\033[0;32m' YELLOW='\033[1;33m' RED='\033[0;31m' BLUE='\033[0;34m' BOLD='\033[1m' NC='\033[0m' print_header() { echo "" echo -e "${BLUE}${BOLD}════════════════════════════════════════════════════════════${NC}" echo -e "${BLUE}${BOLD} Kaboot Production Setup${NC}" echo -e "${BLUE}${BOLD}════════════════════════════════════════════════════════════${NC}" echo "" } print_step() { echo -e "${GREEN}${BOLD}▶ $1${NC}" } print_warning() { echo -e "${YELLOW}⚠ $1${NC}" } print_error() { echo -e "${RED}✖ $1${NC}" } print_success() { echo -e "${GREEN}✔ $1${NC}" } print_header KABOOT_DOMAIN="" AUTH_DOMAIN="" GEMINI_API_KEY="" while [[ $# -gt 0 ]]; do case $1 in --domain) KABOOT_DOMAIN="$2" shift 2 ;; --auth-domain) AUTH_DOMAIN="$2" shift 2 ;; --gemini-key) GEMINI_API_KEY="$2" shift 2 ;; --help|-h) echo "Usage: $0 [OPTIONS]" echo "" echo "Options:" echo " --domain DOMAIN Main application domain (e.g., kaboot.example.com)" echo " --auth-domain DOMAIN Authentication domain (e.g., auth.example.com)" echo " --gemini-key KEY Gemini API key for system AI (optional)" echo " --help, -h Show this help message" echo "" echo "If options are not provided, you will be prompted for them." exit 0 ;; *) print_error "Unknown option: $1" exit 1 ;; esac done if [ ! -f ".env.example" ]; then print_error "Error: .env.example not found. Run this script from the project root." exit 1 fi if [ -f ".env" ]; then print_warning ".env file already exists." read -p "Overwrite existing configuration? (y/N): " -n 1 -r echo "" if [[ ! $REPLY =~ ^[Yy]$ ]]; then echo "Aborting. Existing configuration preserved." exit 0 fi fi echo -e "${BOLD}Domain Configuration${NC}" echo "────────────────────────────────────────────────────────────" if [ -z "$KABOOT_DOMAIN" ]; then read -p "Enter your main domain (e.g., kaboot.example.com): " KABOOT_DOMAIN fi if [ -z "$KABOOT_DOMAIN" ]; then print_error "Domain is required." exit 1 fi if [ -z "$AUTH_DOMAIN" ]; then DEFAULT_AUTH="auth.${KABOOT_DOMAIN}" read -p "Enter your auth domain [$DEFAULT_AUTH]: " AUTH_DOMAIN AUTH_DOMAIN=${AUTH_DOMAIN:-$DEFAULT_AUTH} fi echo "" echo -e "${BOLD}System AI Configuration (Optional)${NC}" echo "────────────────────────────────────────────────────────────" echo "You can provide a Gemini API key to enable AI quiz generation" echo "for all users without requiring them to set up their own key." echo -e "${YELLOW}Note: This key will be embedded in the frontend and visible to users.${NC}" echo "" if [ -z "$GEMINI_API_KEY" ]; then read -p "Enter Gemini API key (or press Enter to skip): " GEMINI_API_KEY fi echo "" print_step "Generating secrets..." PG_PASS=$(openssl rand -base64 36 | tr -d '\n' | tr -d '/') AUTHENTIK_SECRET_KEY=$(openssl rand -base64 60 | tr -d '\n' | tr -d '/') AUTHENTIK_BOOTSTRAP_PASSWORD=$(openssl rand -base64 24 | tr -d '\n' | tr -d '/') AUTHENTIK_BOOTSTRAP_TOKEN=$(openssl rand -hex 32) ENCRYPTION_KEY=$(openssl rand -base64 36 | tr -d '\n' | tr -d '/') print_success "Secrets generated" print_step "Creating .env file..." cat > .env << EOF # Kaboot Production Configuration # Generated by setup-prod.sh on $(date) # Database PG_PASS=${PG_PASS} PG_USER=authentik PG_DB=authentik # Authentik Secrets AUTHENTIK_SECRET_KEY=${AUTHENTIK_SECRET_KEY} AUTHENTIK_BOOTSTRAP_PASSWORD=${AUTHENTIK_BOOTSTRAP_PASSWORD} AUTHENTIK_BOOTSTRAP_TOKEN=${AUTHENTIK_BOOTSTRAP_TOKEN} AUTHENTIK_ERROR_REPORTING=false # Backend Encryption ENCRYPTION_KEY=${ENCRYPTION_KEY} # OIDC Configuration (Production) OIDC_ISSUER=https://${AUTH_DOMAIN}/application/o/kaboot/ OIDC_JWKS_URI=https://${AUTH_DOMAIN}/application/o/kaboot/jwks/ # Security CORS_ORIGIN=https://${KABOOT_DOMAIN} NODE_ENV=production LOG_REQUESTS=true # System AI (optional - server-side quiz generation) GEMINI_API_KEY=${GEMINI_API_KEY} EOF print_success "Created .env" print_step "Creating Caddyfile..." cat > Caddyfile << EOF # Kaboot Production Caddyfile # Generated by setup-prod.sh on $(date) ${KABOOT_DOMAIN} { root * /srv/frontend file_server try_files {path} /index.html handle /api/* { reverse_proxy kaboot-backend:3001 } handle /health { reverse_proxy kaboot-backend:3001 } } ${AUTH_DOMAIN} { reverse_proxy authentik-server:9000 { header_up X-Forwarded-Proto {scheme} header_up X-Forwarded-Host {host} transport http { keepalive 30s } } } EOF print_success "Created Caddyfile" print_step "Creating production Authentik blueprint..." BLUEPRINT_DIR="authentik/blueprints" PROD_BLUEPRINT="${BLUEPRINT_DIR}/kaboot-setup-production.yaml" DEV_BLUEPRINT="${BLUEPRINT_DIR}/kaboot-setup.yaml" if [ -f "${BLUEPRINT_DIR}/kaboot-setup-production.yaml.example" ]; then sed "s/kaboot.example.com/${KABOOT_DOMAIN}/g; s/auth.example.com/${AUTH_DOMAIN}/g" \ "${BLUEPRINT_DIR}/kaboot-setup-production.yaml.example" > "$PROD_BLUEPRINT" print_success "Created production blueprint" else print_warning "Production blueprint example not found, skipping..." fi if [ -f "$DEV_BLUEPRINT" ]; then rm "$DEV_BLUEPRINT" print_success "Removed development blueprint" fi print_step "Installing frontend dependencies..." npm install --silent 2>/dev/null || npm install print_success "Dependencies installed" print_step "Building frontend with production URLs..." VITE_API_URL="https://${KABOOT_DOMAIN}" \ VITE_BACKEND_URL="https://${KABOOT_DOMAIN}" \ VITE_AUTHENTIK_URL="https://${AUTH_DOMAIN}" \ VITE_OIDC_CLIENT_ID="kaboot-spa" \ VITE_OIDC_APP_SLUG="kaboot" \ npm run build --silent 2>/dev/null || npm run build if [ -n "$GEMINI_API_KEY" ]; then print_success "System AI will be available (key configured for backend)" else print_warning "No Gemini API key provided - users must configure their own" fi print_success "Frontend built" echo "" echo -e "${GREEN}${BOLD}════════════════════════════════════════════════════════════${NC}" echo -e "${GREEN}${BOLD} Setup Complete!${NC}" echo -e "${GREEN}${BOLD}════════════════════════════════════════════════════════════${NC}" echo "" echo -e "${BOLD}Configuration Summary${NC}" echo "────────────────────────────────────────────────────────────" echo -e " Main Domain: ${BLUE}https://${KABOOT_DOMAIN}${NC}" echo -e " Auth Domain: ${BLUE}https://${AUTH_DOMAIN}${NC}" if [ -n "$GEMINI_API_KEY" ]; then echo -e " System AI: ${GREEN}Enabled${NC}" else echo -e " System AI: ${YELLOW}Disabled (users need own API key)${NC}" fi echo "" echo -e "${BOLD}Authentik Admin${NC}" echo "────────────────────────────────────────────────────────────" echo -e " Admin URL: ${BLUE}https://${AUTH_DOMAIN}/if/admin/${NC}" echo -e " Username: ${YELLOW}akadmin${NC}" echo -e " Password: ${YELLOW}${AUTHENTIK_BOOTSTRAP_PASSWORD}${NC}" echo "" echo -e "${RED}${BOLD}⚠ SAVE THESE CREDENTIALS - They won't be shown again!${NC}" echo "" echo -e "${BOLD}Files Created${NC}" echo "────────────────────────────────────────────────────────────" echo " .env - Environment variables" echo " Caddyfile - Reverse proxy config" echo " authentik/blueprints/kaboot-setup-production.yaml" echo " dist/ - Built frontend" echo "" echo -e "${BOLD}Next Steps${NC}" echo "────────────────────────────────────────────────────────────" echo "" echo " 1. Ensure DNS records point to this server:" echo -e " ${KABOOT_DOMAIN} → ${BLUE}${NC}" echo -e " ${AUTH_DOMAIN} → ${BLUE}${NC}" echo "" echo " 2. Start the production stack:" echo -e " ${YELLOW}docker compose -f docker-compose.prod.yml -f docker-compose.caddy.yml up -d${NC}" echo "" echo " 3. Wait for services to start (~60 seconds for Authentik)" echo "" echo " 4. Verify all services are running:" echo -e " ${YELLOW}docker compose -f docker-compose.prod.yml -f docker-compose.caddy.yml ps${NC}" echo "" echo " 5. Check Authentik blueprint was applied:" echo -e " ${YELLOW}docker compose -f docker-compose.prod.yml logs authentik-server | grep -i blueprint${NC}" echo "" echo " 6. Access your app at:" echo -e " ${BLUE}https://${KABOOT_DOMAIN}${NC}" echo ""