#!/bin/bash # Split deploy for unstable Tailscale connections # Each step is a separate short SSH session — no long-lived connections set -e TARGET="$1" if [ -z "$TARGET" ]; then echo "Usage: $0 user@host"; exit 1; fi SSH_KEY="${ARCHIPELAGO_SSH_KEY:-$HOME/.ssh/archipelago-deploy}" SSH="ssh -o StrictHostKeyChecking=no -o ServerAliveInterval=15 -o ServerAliveCountMax=4 -o ConnectTimeout=10 -i $SSH_KEY" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" TARGET_DIR="/home/archipelago/archy" echo "=== Deploying to $TARGET (split mode) ===" # Step 1: rsync code echo "[$(date +%H:%M:%S)] Step 1: Syncing code..." rsync -az --delete \ --exclude='.git' --exclude='node_modules' --exclude='target/debug' \ --exclude='target/release/deps' --exclude='target/release/build' \ --exclude='target/release/.fingerprint' --exclude='target/release/incremental' \ --exclude='web/dist' --exclude='.DS_Store' \ -e "$SSH" \ "$PROJECT_DIR/" "$TARGET:$TARGET_DIR/" || { echo "rsync failed"; exit 1; } echo " Synced." # Step 2: Start frontend build in background on remote echo "[$(date +%H:%M:%S)] Step 2: Building frontend (background)..." $SSH "$TARGET" "cd $TARGET_DIR/neode-ui && nohup bash -c 'npm install --silent 2>&1 && npm run build 2>&1' > /tmp/frontend-build.log 2>&1 &" sleep 3 while true; do sleep 5 status=$($SSH "$TARGET" "pgrep -f 'vite build' >/dev/null 2>&1 && echo running || (pgrep -f 'npm run build' >/dev/null 2>&1 && echo running || echo done)") if [ "$status" = "done" ]; then break; fi echo " still building frontend..." done $SSH "$TARGET" "tail -5 /tmp/frontend-build.log" echo " Frontend built." # Step 3: Start Rust build in background on remote echo "[$(date +%H:%M:%S)] Step 3: Building backend (background)..." $SSH "$TARGET" "cd $TARGET_DIR && nohup bash -c 'source ~/.cargo/env 2>/dev/null && cd core && cargo build --release 2>&1' > /tmp/rust-build.log 2>&1 &" sleep 3 while true; do sleep 10 status=$($SSH "$TARGET" "pgrep -f 'cargo build' >/dev/null 2>&1 && echo running || echo done") if [ "$status" = "done" ]; then break; fi echo " still building backend..." done $SSH "$TARGET" "tail -5 /tmp/rust-build.log" result=$($SSH "$TARGET" "[ -f $TARGET_DIR/core/target/release/archipelago ] && echo ok || echo fail") if [ "$result" != "ok" ]; then echo " Backend build failed!"; exit 1; fi echo " Backend built." # Step 4: Deploy binary echo "[$(date +%H:%M:%S)] Step 4: Deploying binary..." $SSH "$TARGET" "sudo systemctl stop archipelago 2>/dev/null; sudo cp $TARGET_DIR/core/target/release/archipelago /usr/local/bin/ && echo ' binary deployed'" # Step 5: Deploy frontend echo "[$(date +%H:%M:%S)] Step 5: Deploying frontend..." $SSH "$TARGET" "sudo find /opt/archipelago/web-ui -mindepth 1 -maxdepth 1 ! -name 'aiui' ! -name 'claude-login.html' -exec rm -rf {} + && sudo cp -rf $TARGET_DIR/web/dist/neode-ui/* /opt/archipelago/web-ui/ && sudo chown -R 1000:1000 /opt/archipelago/web-ui && echo ' frontend deployed'" # Step 6: Deploy AIUI if present AIUI_DIST="$PROJECT_DIR/../AIUI/packages/app/dist" if [ -d "$AIUI_DIST" ]; then echo "[$(date +%H:%M:%S)] Step 6: Deploying AIUI..." $SSH "$TARGET" "sudo mkdir -p /opt/archipelago/web-ui/aiui" cd "$AIUI_DIST" && tar cf - . | $SSH "$TARGET" "sudo tar xf - -C /opt/archipelago/web-ui/aiui/" $SSH "$TARGET" "sudo chown -R 1000:1000 /opt/archipelago/web-ui/aiui" echo " AIUI deployed." fi # Step 7: Restart services echo "[$(date +%H:%M:%S)] Step 7: Restarting services..." $SSH "$TARGET" "sudo systemctl start archipelago && sudo systemctl restart nginx && echo ' services restarted'" # Step 8: Health check echo "[$(date +%H:%M:%S)] Step 8: Health check..." sleep 3 IP=$(echo "$TARGET" | cut -d@ -f2) health=$(curl -s -o /dev/null -w '%{http_code}' --connect-timeout 5 "http://$IP/health" 2>/dev/null || echo "000") echo " Health: $health" echo "=== Deploy complete for $TARGET ==="