#!/usr/bin/env bash set -euo pipefail # ────────────────────────────────────────────── # worst-scan-web — VPS minimal setup # Run AFTER: scp deploy.tar.gz to ~/ and extract # tar xzf ~/deploy.tar.gz -C ~/worst-scan-web # ────────────────────────────────────────────── APP_DIR="${HOME}/worst-scan-web" SERVICE_NAME="worst-scan-web" CADDYFILE="/etc/caddy/Caddyfile" RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m' log() { printf "${GREEN}✓${NC} %s\n" "$1"; } warn() { printf "${YELLOW}⚠${NC} %s\n" "$1"; } err() { printf "${RED}✗${NC} %s\n" "$1"; } info() { printf "${CYAN}→${NC} %s\n" "$1"; } # ── Sudo ────────────────────────────────────── # Valida credenciales una vez; las siguientes llamadas usan el sudo cacheado, # sin exponer la contraseña en texto plano en el script. sudo -v || (err "sudo required" && exit 1) SU() { sudo "$@"; } # ── Swap (prevent OOM during compile) ───────── if [ "$(free -m | awk '/^Swap:/{print $2}')" -lt 512 ]; then info "Creating 1GB swap file..." SU dd if=/dev/zero of=/swapfile bs=1M count=1024 status=none SU chmod 600 /swapfile SU mkswap /swapfile >/dev/null SU swapon /swapfile if ! grep -q /swapfile /etc/fstab 2>/dev/null; then echo '/swapfile none swap sw 0 0' | SU tee -a /etc/fstab >/dev/null fi log "Swap created" fi # ── Node.js + Caddy ────────────────────────── if ! command -v node &>/dev/null || [ "$(node -v | cut -d. -f1 | tr -d v)" -lt 22 ]; then info "Installing Node.js 22..." curl -fsSL https://deb.nodesource.com/setup_22.x | SU bash SU apt install -y -qq nodejs log "Node.js $(node -v) installed" fi if ! command -v caddy &>/dev/null; then info "Installing Caddy..." SU apt install -y -qq debian-keyring debian-archive-keyring apt-transport-https curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/setup.deb.sh' | SU bash SU apt install -y -qq caddy log "Caddy installed" fi # ── China npm mirror ───────────────────────── npm config set registry https://registry.npmmirror.com # ── App dir ────────────────────────────────── mkdir -p "$APP_DIR/data" # ── .env ───────────────────────────────────── if [ ! -f "$APP_DIR/.env" ]; then cat > "$APP_DIR/.env" << 'ENV' API_BASE_URL=http://127.0.0.1:8080/api/v1 API_KEY= WEB_PASSWORD= WEBHOOK_SECRET= DB_PATH=/home/ren/worst-scan-web/data/worst-scan.db COVERS_DIR=/home/ren/worst-scan-web/data/covers ENV log ".env created" fi # ── systemd service ────────────────────────── SU tee "/etc/systemd/system/$SERVICE_NAME.service" > /dev/null </dev/null; then warn "Caddy already configured" else SU tee -a "$CADDYFILE" > /dev/null </dev/null || true SU systemctl restart caddy # ── Health check ───────────────────────────── info "Waiting for web..." for i in $(seq 1 15); do if curl -fsS http://127.0.0.1:3000/api/health >/dev/null 2>&1; then log "Web is healthy"; break fi sleep 2 done IP=$(curl -fsSL http://checkip.amazonaws.com 2>/dev/null || echo "localhost") printf "\n${GREEN}WORST-SCAN-WEB READY${NC}\n" printf " http://%s/setup\n" "$IP" printf "\n"