#!/usr/bin/env bash # Music Orchestrator — production deploy script for Ubuntu # Run as a regular user with sudo access. Do NOT run as root. # # First run: bash deploy.sh # Update: bash deploy.sh (re-run at any time — it's idempotent) set -euo pipefail # ── Config ───────────────────────────────────────────────────────────────────── INSTALL_DIR="/opt/music-orchestrator" SERVICE_NAME="music-orchestrator" SERVICE_USER="$(whoami)" NGINX_SITE="music-orchestrator" # Where your Plex library lives on this machine. # Can be changed later by editing $INSTALL_DIR/backend/.env DEFAULT_MUSIC_DIR="$HOME/Music" # Colours GREEN="\033[0;32m"; YELLOW="\033[0;33m"; RED="\033[0;31m"; NC="\033[0m" info() { echo -e "${GREEN}[+]${NC} $*"; } warn() { echo -e "${YELLOW}[!]${NC} $*"; } section() { echo -e "\n${GREEN}── $* ──────────────────────────────────────────────────${NC}"; } # ── Checks ───────────────────────────────────────────────────────────────────── section "Checking prerequisites" if [[ $EUID -eq 0 ]]; then echo -e "${RED}[✗]${NC} Do not run this script as root. Run as your regular user." exit 1 fi SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if [[ ! -f "$SCRIPT_DIR/backend/main.py" ]]; then echo -e "${RED}[✗]${NC} Run this script from the music-orchestrator project root." exit 1 fi # ── System dependencies ──────────────────────────────────────────────────────── section "Installing system packages" sudo apt-get update -qq sudo apt-get install -y \ python3 python3-pip python3-venv \ ffmpeg \ nginx \ nodejs npm \ --no-install-recommends info "System packages ready" # ── Install directory ────────────────────────────────────────────────────────── section "Setting up install directory ($INSTALL_DIR)" sudo mkdir -p "$INSTALL_DIR" sudo chown "$SERVICE_USER:$SERVICE_USER" "$INSTALL_DIR" # Sync project files (rsync excludes dev artifacts) rsync -a --delete \ --exclude='.git' \ --exclude='node_modules' \ --exclude='frontend/dist' \ --exclude='backend/venv' \ --exclude='backend/__pycache__' \ --exclude='backend/tmp' \ --exclude='backend/Music' \ --exclude='.env' \ "$SCRIPT_DIR/" "$INSTALL_DIR/" info "Project files synced to $INSTALL_DIR" # ── Backend: Python virtualenv ───────────────────────────────────────────────── section "Setting up Python virtual environment" python3 -m venv "$INSTALL_DIR/backend/venv" "$INSTALL_DIR/backend/venv/bin/pip" install --quiet --upgrade pip "$INSTALL_DIR/backend/venv/bin/pip" install --quiet -r "$INSTALL_DIR/backend/requirements.txt" info "Python dependencies installed" # ── Backend: .env ────────────────────────────────────────────────────────────── section "Configuring backend .env" ENV_FILE="$INSTALL_DIR/backend/.env" if [[ ! -f "$ENV_FILE" ]]; then # First install — prompt for music dir echo "" warn "Where is your Plex music library? (press Enter for default: $DEFAULT_MUSIC_DIR)" read -r -p " Music directory: " MUSIC_DIR_INPUT MUSIC_DIR="${MUSIC_DIR_INPUT:-$DEFAULT_MUSIC_DIR}" mkdir -p "$MUSIC_DIR" cat > "$ENV_FILE" </dev/null | cut -d= -f2 || echo "/tmp/music-orchestrator") mkdir -p "$TEMP_DIR" # ── Frontend: build ──────────────────────────────────────────────────────────── section "Building React frontend" cd "$INSTALL_DIR/frontend" npm install --silent npm run build info "Frontend built to $INSTALL_DIR/frontend/dist" # ── nginx ────────────────────────────────────────────────────────────────────── section "Configuring nginx" sudo cp "$INSTALL_DIR/nginx.conf" "/etc/nginx/sites-available/$NGINX_SITE" # Enable the site, remove default if present sudo ln -sf "/etc/nginx/sites-available/$NGINX_SITE" "/etc/nginx/sites-enabled/$NGINX_SITE" sudo rm -f /etc/nginx/sites-enabled/default sudo nginx -t # validate config before reloading sudo systemctl enable nginx --quiet sudo systemctl reload nginx info "nginx configured and reloaded" # ── systemd service ──────────────────────────────────────────────────────────── section "Installing systemd service" # The service uses %i (instance name) for User= — we pass the username as the instance SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}@.service" sudo cp "$INSTALL_DIR/music-orchestrator.service" "$SERVICE_FILE" sudo systemctl daemon-reload sudo systemctl enable "${SERVICE_NAME}@${SERVICE_USER}" --quiet sudo systemctl restart "${SERVICE_NAME}@${SERVICE_USER}" # Wait a moment and check it started cleanly sleep 2 if systemctl is-active --quiet "${SERVICE_NAME}@${SERVICE_USER}"; then info "Service started successfully" else echo -e "${RED}[✗]${NC} Service failed to start. Check logs with:" echo " journalctl -u ${SERVICE_NAME}@${SERVICE_USER} -n 50" exit 1 fi # ── Done ─────────────────────────────────────────────────────────────────────── section "Deploy complete" LOCAL_IP=$(hostname -I | awk '{print $1}') echo "" echo -e " ${GREEN}Music Orchestrator is running at:${NC}" echo -e " http://$LOCAL_IP" echo "" echo " Useful commands:" echo " View logs: journalctl -u ${SERVICE_NAME}@${SERVICE_USER} -f" echo " Restart API: sudo systemctl restart ${SERVICE_NAME}@${SERVICE_USER}" echo " Edit config: nano $ENV_FILE" echo "" echo " To update after code changes: just re-run bash deploy.sh" echo ""