diff --git a/deploy.sh b/deploy.sh index 39c411e2..0ebc3ee0 100755 --- a/deploy.sh +++ b/deploy.sh @@ -2,22 +2,10 @@ 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 +# Semblance — deploy script (run directly on server) +# /opt/semblance/deploy.sh # ───────────────────────────────────────────────────────────────────────────── -SSH_HOST="optical-dev" DEPLOY_DIR="/opt/semblance" FRONTEND_DEST="/var/www/html/semblance" @@ -25,78 +13,63 @@ echo "======================================" echo "Semblance — starting deployment" echo "======================================" -# ── Pre-flight: backend/.env must exist on server ──────────────────────────── +cd "$DEPLOY_DIR" + +# ── Pre-flight ──────────────────────────────────────────────────────────────── 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" +echo "[pre-flight] Checking backend/.env..." +if [ ! -f backend/.env ]; then + echo "ERROR: backend/.env not found." + echo " cp backend/.env.example backend/.env && nano 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" + if ! grep -q "^${VAR}=.\+" backend/.env 2>/dev/null; then + echo "ERROR: $VAR is not set in backend/.env" exit 1 fi done -echo "✓ backend/.env present and required vars set" +echo "✓ backend/.env OK" -# ── Step 1: Pull latest code on server ─────────────────────────────────────── +# ── Step 1: Pull latest code ────────────────────────────────────────────────── echo "" -echo "[1/5] Pulling latest code on server..." -ssh "$SSH_HOST" "cd $DEPLOY_DIR && git pull" +echo "[1/4] Pulling latest code..." +git pull -# ── Step 2: Build frontend locally ─────────────────────────────────────────── +# ── Step 2: Build frontend (Node in Docker) ─────────────────────────────────── 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 "[2/4] Building frontend..." +sudo mkdir -p "$FRONTEND_DEST" +docker compose --profile build run --rm frontend +sudo chown -R www-data:www-data "$FRONTEND_DEST" echo "✓ Frontend deployed to $FRONTEND_DEST" -# ── Step 4: Ensure Apache proxy config for semblance ───────────────────────── +# ── Step 3: Ensure Apache proxy config ─────────────────────────────────────── echo "" -echo "[4/5] Ensuring Apache proxy config..." -ssh "$SSH_HOST" " - CONF='/etc/apache2/sites-enabled/optical-dev.oliver.solutions.conf' +echo "[3/4] Ensuring Apache proxy config..." +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 -" +if sudo 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\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 ─────────────────────────────── +# ── Step 4: Rebuild and restart backend + mongo ─────────────────────────────── 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 "[4/4] Rebuilding and restarting Docker services..." +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 " https://optical-dev.oliver.solution/semblance/" echo "======================================" diff --git a/docker-compose.yml b/docker-compose.yml index 656f3bda..74aec9ad 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,18 @@ services: + frontend: + image: node:20-alpine + working_dir: /app + volumes: + - .:/app + - /var/www/html/semblance:/app/dist-out + command: > + sh -c "cp .env.production .env && + npm ci --silent && + npm run build && + cp -r dist/* /app/dist-out/" + profiles: + - build + mongo: image: mongo:7 restart: unless-stopped diff --git a/server-deploy.sh b/server-deploy.sh deleted file mode 100755 index 645beeea..00000000 --- a/server-deploy.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/bash -set -e - -# ───────────────────────────────────────────────────────────────────────────── -# Semblance — server-side deploy script -# Run this DIRECTLY ON THE SERVER: /opt/semblance/server-deploy.sh -# -# Does NOT build the frontend (Node not on server). -# Frontend must be deployed from local Mac via: ./deploy.sh -# ───────────────────────────────────────────────────────────────────────────── - -DEPLOY_DIR="/opt/semblance" -FRONTEND_DEST="/var/www/html/semblance" - -echo "======================================" -echo "Semblance — server-side deployment" -echo "======================================" - -cd "$DEPLOY_DIR" - -# ── Pre-flight ──────────────────────────────────────────────────────────────── -if [ ! -f backend/.env ]; then - echo "ERROR: backend/.env not found." - echo " cp backend/.env.example backend/.env && nano backend/.env" - exit 1 -fi - -for VAR in SECRET_KEY JWT_SECRET_KEY OPENAI_API_KEY GEMINI_API_KEY; do - if ! grep -q "^${VAR}=.\+" backend/.env 2>/dev/null; then - echo "ERROR: $VAR is not set in backend/.env" - exit 1 - fi -done -echo "✓ backend/.env OK" - -# ── Step 1: Pull latest code ────────────────────────────────────────────────── -echo "" -echo "[1/3] Pulling latest code..." -git pull - -# ── Step 2: Ensure frontend dir exists ─────────────────────────────────────── -echo "" -echo "[2/3] Ensuring frontend directory..." -sudo mkdir -p "$FRONTEND_DEST" -sudo chown -R www-data:www-data "$FRONTEND_DEST" -echo "✓ $FRONTEND_DEST ready" - -# ── Step 3: Rebuild and restart Docker services ─────────────────────────────── -echo "" -echo "[3/3] Rebuilding and restarting Docker services..." -docker compose up -d --build - -echo "" -echo "Container status:" -docker compose ps - -echo "" -echo "======================================" -echo "Server deployment complete!" -echo " Backend: http://127.0.0.1:5137" -echo "" -echo "NOTE: Frontend not deployed (requires local build)." -echo " Run ./deploy.sh from your Mac to deploy the frontend." -echo "======================================"