#!/bin/bash ################################################################################ # Lux Studio — Production Deployment Script # # Usage: # cd /opt/cinema-studio-pro # sudo ./deploy.sh # # What it does: # 1. Builds the React frontend using frontend/.env.production # 2. Deploys built files → /var/www/html/lux-studio/ # 3. Deploys backend PHP → /var/www/html/lux-studio/api/ # 4. Verifies the deployment # # Apache serves PHP directly — no systemd service or proxy needed. # Apache configuration (AllowOverride, modules) is managed separately by the operator. # The backend .env on the server is never overwritten (preserves API keys). ################################################################################ set -e # ─── Colors ─────────────────────────────────────────────────────────────────── RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # ─── Configuration ───────────────────────────────────────────────────────────── SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" FRONTEND_SRC="$SCRIPT_DIR/frontend" BACKEND_SRC="$SCRIPT_DIR/backend" WEB_ROOT="/var/www/html/lux-studio" API_ROOT="$WEB_ROOT/api" # PHP files that must never be deployed to the server SKIP_PHP=("test.php" "config.example.php") # ─── Helper functions ───────────────────────────────────────────────────────── step() { echo ""; echo -e "${YELLOW}[$1] $2...${NC}"; } ok() { echo -e "${GREEN} ✓ $1${NC}"; } warn() { echo -e "${YELLOW} ⚠ $1${NC}"; } fail() { echo -e "${RED} Error: $1${NC}"; exit 1; } # ─── Header ─────────────────────────────────────────────────────────────────── echo "" echo -e "${BLUE}========================================" echo -e " Lux Studio — Production Deployment" echo -e "========================================${NC}" echo "" echo " Source: $SCRIPT_DIR" echo " Frontend: $WEB_ROOT" echo " Backend: $API_ROOT" echo "" # ─── Root check ─────────────────────────────────────────────────────────────── [[ $EUID -ne 0 ]] && fail "This script must be run as root. Use: sudo ./deploy.sh" # ───────────────────────────────────────────────────────────────────────────── step "1/6" "Preflight checks" # ───────────────────────────────────────────────────────────────────────────── [ -d "$FRONTEND_SRC" ] || fail "frontend/ directory not found in $SCRIPT_DIR" [ -d "$BACKEND_SRC" ] || fail "backend/ directory not found in $SCRIPT_DIR" [ -f "$FRONTEND_SRC/.env.production" ] \ || fail "frontend/.env.production not found — cannot build for production" [ -f "$BACKEND_SRC/.env.production" ] \ || warn "backend/.env.production not found — /api/.env will not be created automatically" # Check required system commands for cmd in php node npm; do command -v "$cmd" &>/dev/null \ && ok "$cmd: $(command -v $cmd)" \ || fail "$cmd is not installed" done ok "Preflight passed" # ───────────────────────────────────────────────────────────────────────────── step "2/6" "Building frontend" # ───────────────────────────────────────────────────────────────────────────── cd "$FRONTEND_SRC" # Always use .env.production for production builds — never use a cached .env cp .env.production .env ok "frontend/.env overwritten from .env.production" # Install npm dependencies if node_modules is absent or package.json changed echo " Checking npm dependencies..." npm install --silent ok "npm dependencies ready" echo " Building (this may take 30–60 seconds)..." npm run build ok "Build complete → frontend/dist/" # Confirm the correct API path was baked into the bundle if grep -qo "lux-studio/api" dist/assets/*.js 2>/dev/null; then ok "API URL verified in bundle: lux-studio/api" else fail "Bundle does not contain 'lux-studio/api'. Check VITE_API_URL in frontend/.env.production" fi cd "$SCRIPT_DIR" # ───────────────────────────────────────────────────────────────────────────── step "3/6" "Deploying frontend to $WEB_ROOT" # ───────────────────────────────────────────────────────────────────────────── mkdir -p "$WEB_ROOT" # Delete old assets/ first — Vite produces differently hash-named files each # build. Leaving old files causes stale JS to be served. if [ -d "$WEB_ROOT/assets" ]; then rm -rf "$WEB_ROOT/assets" ok "Old assets/ removed (hash names change each build)" fi # Copy built output cp "$FRONTEND_SRC/dist/index.html" "$WEB_ROOT/index.html" cp -r "$FRONTEND_SRC/dist/assets" "$WEB_ROOT/assets" ok "index.html and assets/ deployed" # Copy static public assets (logos, favicon — not always present in all builds) for item in LUX_STUDIO_LOGO.svg LUX_STUDIO_LOGO.png; do src="$FRONTEND_SRC/dist/$item" [ -e "$src" ] && cp "$src" "$WEB_ROOT/$item" done ok "Static assets deployed (LUX_STUDIO_LOGO.svg, LUX_STUDIO_LOGO.png)" # .htaccess is NOT copied into dist/ by Vite — must be taken from source if [ -f "$FRONTEND_SRC/.htaccess" ]; then cp "$FRONTEND_SRC/.htaccess" "$WEB_ROOT/.htaccess" ok ".htaccess deployed from frontend/.htaccess (not from dist/)" else warn "frontend/.htaccess not found — React Router deep links will break" fi chown -R www-data:www-data "$WEB_ROOT" chmod -R 755 "$WEB_ROOT" ok "Permissions set (www-data:www-data, 755)" # ───────────────────────────────────────────────────────────────────────────── step "4/6" "Deploying backend PHP to $API_ROOT" # ───────────────────────────────────────────────────────────────────────────── mkdir -p "$API_ROOT" # Copy all .php files from backend/ except those in SKIP_PHP PHP_COUNT=0 for php_file in "$BACKEND_SRC"/*.php; do filename=$(basename "$php_file") skip=false for skip_name in "${SKIP_PHP[@]}"; do [ "$filename" = "$skip_name" ] && skip=true && break done if [ "$skip" = false ]; then cp "$php_file" "$API_ROOT/$filename" PHP_COUNT=$((PHP_COUNT + 1)) fi done ok "$PHP_COUNT PHP files deployed (skipped: ${SKIP_PHP[*]})" # Copy backend .htaccess (security rules, blocks .env/vendor/direct class access) if [ -f "$BACKEND_SRC/.htaccess" ]; then cp "$BACKEND_SRC/.htaccess" "$API_ROOT/.htaccess" ok "Backend .htaccess deployed" fi # ── .env handling ────────────────────────────────────────────────────────────── # The production .env contains the real GEMINI_API_KEY. # NEVER overwrite it — only create it if it does not exist yet. if [ -f "$API_ROOT/.env" ]; then ok "/api/.env already exists — not overwritten (production secrets preserved)" else if [ -f "$BACKEND_SRC/.env.production" ]; then cp "$BACKEND_SRC/.env.production" "$API_ROOT/.env" ok "Created /api/.env from backend/.env.production" echo "" warn "ACTION REQUIRED: Verify GEMINI_API_KEY and FRONTEND_URL in /api/.env:" warn " sudo nano $API_ROOT/.env" echo "" else warn "backend/.env.production not found — /api/.env was NOT created" warn "Create it manually: sudo nano $API_ROOT/.env" warn "Required keys: GEMINI_API_KEY, FRONTEND_URL, SSO_ENABLED" fi fi # Create uploads directory (PHP writes generated images/videos here) mkdir -p "$API_ROOT/uploads/sessions" # Set ownership before chmod so chmod applies correctly chown -R www-data:www-data "$API_ROOT" chmod -R 755 "$API_ROOT" # www-data must be able to write generated files chmod -R 777 "$API_ROOT/uploads" ok "Permissions set (uploads/: 777 for www-data writes)" # ───────────────────────────────────────────────────────────────────────────── step "5/6" "Verifying deployment" # ───────────────────────────────────────────────────────────────────────────── ERRORS=0 check() { # $1 = path to check, $2 = label, $3 = "warn" (non-fatal) or empty (fatal) if [ -e "$1" ]; then ok "$2" elif [ "$3" = "warn" ]; then warn "$2 not found" else echo -e "${RED} ✗ $2 — MISSING${NC}" ERRORS=$((ERRORS+1)) fi } # Frontend check "$WEB_ROOT/index.html" "index.html" check "$WEB_ROOT/assets" "assets/ directory" check "$WEB_ROOT/.htaccess" ".htaccess (frontend)" warn # Backend check "$API_ROOT/api.php" "api.php" check "$API_ROOT/AuthMiddleware.php" "AuthMiddleware.php ← api.php requires this" check "$API_ROOT/video_api.php" "video_api.php" check "$API_ROOT/enhance_prompt.php" "enhance_prompt.php" check "$API_ROOT/.htaccess" ".htaccess (backend)" check "$API_ROOT/uploads/sessions" "uploads/sessions/" if [ -f "$API_ROOT/.env" ]; then ok "/api/.env present" else echo -e "${RED} ✗ /api/.env MISSING — all API calls will fail without it${NC}" ERRORS=$((ERRORS+1)) fi # Confirm bundle has the right API URL if grep -qo "lux-studio/api" "$WEB_ROOT"/assets/*.js 2>/dev/null; then ok "Bundle contains correct API path (lux-studio/api)" else warn "Could not verify API path in deployed bundle" fi # ───────────────────────────────────────────────────────────────────────────── step "6/6" "Summary" # ───────────────────────────────────────────────────────────────────────────── echo "" echo -e "${BLUE} Deployed:${NC}" echo " Frontend → $WEB_ROOT" echo " Backend → $API_ROOT" echo "" echo -e "${BLUE} Live URL:${NC}" echo " https://ai-sandbox.oliver.solutions/lux-studio/" echo "" echo -e "${BLUE} Useful commands:${NC}" echo " Check .env: sudo cat $API_ROOT/.env" echo " Apache errors: sudo tail -f /var/log/apache2/error.log" echo " Reload Apache: sudo systemctl reload apache2" echo " Re-deploy: cd $SCRIPT_DIR && sudo ./deploy.sh" echo "" echo -e "${BLUE} Test checklist:${NC}" echo " 1. Hard refresh in browser: Ctrl + Shift + R" echo " 2. F12 → Network: API calls go to /lux-studio/api/ (not /lux-studio-back/)" echo " 3. No 404 errors in the Network tab" echo " 4. Create a project and generate an image with a 10+ word prompt" echo "" if [ $ERRORS -gt 0 ]; then echo -e "${YELLOW} ⚠ $ERRORS check(s) failed — review the output above before testing${NC}" echo "" exit 1 else echo -e "${GREEN} ✓ All checks passed — deployment successful!${NC}" echo "" fi