#!/usr/bin/env bash # # deploy.sh — run this ON THE SERVER, from inside the cloned repo # (the app lives at /opt/bizgaze-support). # # What it does: # 1. Snapshots the current working tree (code + .env + certs, excluding .git) # into a rotating backup, keeping the newest $KEEP_BACKUPS. # 2. Pulls the latest commit of $GIT_BRANCH (git reset --hard, so the box # always matches origin exactly). # 3. Rebuilds the image and recreates the container. The named data volume # (data.db) persists; the untracked .env / server/cert.pem / server/key.pem # are gitignored and therefore preserved across every pull. # 4. Verifies the app is serving. # # Usage (on the server): # cd /opt/bizgaze-support # ./deploy.sh # pull latest + rebuild # ./deploy.sh --no-pull # rebuild current checkout (no git pull) # ./deploy.sh --rollback # restore newest backup snapshot + rebuild # # Fire it from your laptop without logging in: # plink -ssh -P 61 -pw '' root@118.95.33.89 \ # "cd /opt/bizgaze-support && ./deploy.sh" set -euo pipefail GIT_BRANCH="${GIT_BRANCH:-master}" KEEP_BACKUPS="${KEEP_BACKUPS:-3}" CONTAINER="${CONTAINER:-bizgaze-support}" cd "$(dirname "$(readlink -f "$0")")" APP_DIR="$(pwd)" BK_DIR="${APP_DIR}.backups" log() { printf '\033[1;36m==>\033[0m %s\n' "$*"; } ok() { printf '\033[1;32m ✓\033[0m %s\n' "$*"; } warn(){ printf '\033[1;33m ! %s\033[0m\n' "$*"; } die() { printf '\033[1;31mERROR:\033[0m %s\n' "$*" >&2; exit 1; } [ -d .git ] || die "Not a git checkout. Run the one-time bootstrap first (see DEPLOY.md)." command -v docker >/dev/null || die "docker not found on this host." # --- args --- DO_PULL=1; ROLLBACK=0 for a in "$@"; do case "$a" in --no-pull) DO_PULL=0 ;; --rollback) ROLLBACK=1 ;; -h|--help) grep '^#' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; *) die "Unknown argument: $a" ;; esac; done snapshot() { mkdir -p "$BK_DIR" local ts rev ts="$(date +%Y%m%d-%H%M%S)" rev="$(git rev-parse --short HEAD 2>/dev/null || echo nogit)" log "Snapshot -> $BK_DIR/${ts}-${rev}.tgz" tar --exclude=./.git --exclude=./node_modules \ --exclude=./server/node_modules -czf "$BK_DIR/${ts}-${rev}.tgz" -C "$APP_DIR" . # rotate: keep newest $KEEP_BACKUPS local old old="$(ls -1t "$BK_DIR"/*.tgz 2>/dev/null | tail -n +$((KEEP_BACKUPS + 1)) || true)" if [ -n "$old" ]; then echo "Pruning old backups:"; echo "$old" | sed 's/^/ rm /' echo "$old" | xargs -r rm -f fi } rebuild() { [ -f .env ] || warn "No .env present — TURN/SSO secrets will be unset." log "Rebuilding and recreating the container …" docker compose config >/dev/null || die "docker-compose.yml is invalid." docker compose up -d --build docker compose ps } verify() { log "Verifying /api/ice …" if docker exec "$CONTAINER" wget -qO- http://localhost:8090/api/ice 2>/dev/null | grep -q iceServers; then ok "App is serving." else warn "Could not confirm /api/ice — check: docker logs $CONTAINER" fi } # --- rollback mode --- if [ "$ROLLBACK" -eq 1 ]; then latest="$(ls -1t "$BK_DIR"/*.tgz 2>/dev/null | head -n1 || true)" [ -n "$latest" ] || die "No backups found in $BK_DIR" log "Rolling back from: $latest" snapshot # snapshot the (broken) current state first tar -xzf "$latest" -C "$APP_DIR" rebuild; verify ok "Rolled back to $latest" exit 0 fi # --- normal deploy --- snapshot if [ "$DO_PULL" -eq 1 ]; then log "Fetching origin/$GIT_BRANCH …" git fetch origin "$GIT_BRANCH" git reset --hard "origin/$GIT_BRANCH" # untracked .env / *.pem are preserved ok "Now at $(git rev-parse --short HEAD): $(git log -1 --pretty=%s)" fi rebuild verify ok "Deploy complete. Backups kept: $KEEP_BACKUPS (in $BK_DIR)." echo " Rollback with: ./deploy.sh --rollback"