#!/bin/bash set -e # ───────────────────────────────────────────────────────────────────────────── # Semblance — deploy script # Builds frontend locally, rsyncs dist/ to server, restarts Docker services. # # Server: optical-dev.oliver.solution (Ubuntu 24.04, Apache2, Docker) # SSH alias: optical-dev (see ~/.ssh/config) # # First-time setup on server (run once manually): # ssh optical-dev # sudo mkdir -p /opt/semblance && sudo chown vadym.samoilenko:vadym.samoilenko /opt/semblance # git clone git@bitbucket.org:zlalani/semblance-dev.git /opt/semblance # cp /opt/semblance/backend/.env.example /opt/semblance/backend/.env # nano /opt/semblance/backend/.env # fill in real values # cd /opt/semblance && docker compose up -d --build # ───────────────────────────────────────────────────────────────────────────── SSH_HOST="optical-dev" DEPLOY_DIR="/opt/semblance" FRONTEND_DEST="/var/www/html/semblance" echo "======================================" echo "Semblance — starting deployment" echo "======================================" # ── Pre-flight: backend/.env must exist on server ──────────────────────────── echo "" echo "[pre-flight] Checking backend/.env on server..." if ! ssh "$SSH_HOST" "test -f $DEPLOY_DIR/backend/.env"; then echo "" echo "ERROR: $DEPLOY_DIR/backend/.env not found on server." echo "Run on server:" echo " cp $DEPLOY_DIR/backend/.env.example $DEPLOY_DIR/backend/.env" echo " nano $DEPLOY_DIR/backend/.env" exit 1 fi for VAR in SECRET_KEY JWT_SECRET_KEY OPENAI_API_KEY GEMINI_API_KEY; do if ! ssh "$SSH_HOST" "grep -q '^${VAR}=.\+' $DEPLOY_DIR/backend/.env 2>/dev/null"; then echo "ERROR: $VAR is not set in backend/.env on server" exit 1 fi done echo "✓ backend/.env present and required vars set" # ── Step 1: Pull latest code on server ─────────────────────────────────────── echo "" echo "[1/5] Pulling latest code on server..." ssh "$SSH_HOST" "cd $DEPLOY_DIR && git pull" # ── Step 2: Build frontend locally ─────────────────────────────────────────── echo "" echo "[2/5] Building frontend locally..." cp .env.production .env npm install --silent npm run build echo "✓ Frontend built (dist/)" # ── Step 3: Deploy frontend to server ──────────────────────────────────────── echo "" echo "[3/5] Deploying frontend to server..." ssh "$SSH_HOST" "sudo mkdir -p $FRONTEND_DEST" rsync -az --delete dist/ "$SSH_HOST:$FRONTEND_DEST/" ssh "$SSH_HOST" "sudo chown -R www-data:www-data $FRONTEND_DEST" echo "✓ Frontend deployed to $FRONTEND_DEST" # ── Step 4: Ensure Apache proxy config for semblance ───────────────────────── echo "" echo "[4/5] Ensuring Apache proxy config..." ssh "$SSH_HOST" " CONF='/etc/apache2/sites-enabled/optical-dev.oliver.solutions.conf' if grep -q 'semblance_back' \"\$CONF\" 2>/dev/null; then echo '✓ Apache semblance config already present' else echo 'Adding semblance blocks to Apache config...' sudo sed -i 's|| # ----------------------------------------------------------------\n # Semblance — Quart/Hypercorn backend at :5137\n # ----------------------------------------------------------------\n\n # WebSocket (Socket.IO)\n RewriteCond %{HTTP:Upgrade} websocket [NC]\n RewriteCond %{HTTP:Connection} upgrade [NC]\n RewriteRule ^/semblance_back/socket.io/(.*) ws://127.0.0.1:5137/socket.io/\$1 [P,L]\n\n # REST API\n ProxyPass /semblance_back/api/ http://127.0.0.1:5137/api/\n ProxyPassReverse /semblance_back/api/ http://127.0.0.1:5137/api/\n\n # Socket.IO HTTP polling fallback\n ProxyPass /semblance_back/socket.io/ http://127.0.0.1:5137/socket.io/\n ProxyPassReverse /semblance_back/socket.io/ http://127.0.0.1:5137/socket.io/\n\n # Semblance SPA — served at /semblance/\n Alias /semblance $FRONTEND_DEST\n \n Options -Indexes +FollowSymLinks\n AllowOverride None\n Require all granted\n RewriteEngine On\n RewriteBase /semblance/\n RewriteCond %{REQUEST_FILENAME} !-f\n RewriteCond %{REQUEST_FILENAME} !-d\n RewriteRule ^ index.html [L]\n \n\n|' \"\$CONF\" sudo apache2ctl configtest && sudo systemctl reload apache2 echo '✓ Apache config updated and reloaded' fi " # ── Step 5: Rebuild and restart Docker services ─────────────────────────────── echo "" echo "[5/5] Rebuilding and restarting Docker services..." ssh "$SSH_HOST" " cd $DEPLOY_DIR docker compose pull mongo 2>/dev/null || true docker compose up -d --build echo '' echo 'Container status:' docker compose ps " echo "" echo "======================================" echo "Deployment complete!" echo " Frontend: https://optical-dev.oliver.solution/semblance/" echo " API: https://optical-dev.oliver.solution/semblance_back/api/" echo "======================================"