llm-gateway/deploy/setup-erik.sh
Rene Fichtmueller 3a00ff4d33 feat: initial llm-gateway implementation
- Complete Fastify gateway with 8-stage pipeline
- Circuit breaker (opossum) per model tier
- Rate limiting per caller
- Ban list validation (EN/DE/auto-detected)
- TIP validator (SFF-8024, part numbers, wavelengths)
- Prometheus metrics
- pg-boss async queue
- PostgreSQL audit log + review queue
- 9 prompt templates (TIP, LinkedIn, ShieldX)
- Learning engine scaffolding
- Auto-learning: ban-list, few-shot, routing, prompt optimizer
2026-04-02 22:48:55 +02:00

196 lines
6.8 KiB
Bash
Executable File

#!/bin/bash
# ============================================================
# LLM Gateway — Full server setup for Erik (217.154.82.179)
#
# Run ONCE on a fresh server. Idempotent: safe to re-run.
# Prerequisites: PostgreSQL 17, Node.js 22, git, pm2
# ============================================================
set -euo pipefail
GATEWAY_DIR="/opt/llm-gateway"
LOG_DIR="/var/log/llm-gateway"
GITEA_REPO="http://gitea.context-x.org/rene/llm-gateway.git"
DB_NAME="llm_gateway"
DB_USER="llm"
DB_PASS="llm_secure_password"
PM2_USER="${SUDO_USER:-root}"
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; }
section() { echo -e "\n${GREEN}==============================${NC}"; echo -e "${GREEN}$*${NC}"; echo -e "${GREEN}==============================${NC}"; }
# -------------------------------------------------------
# 0. Preflight checks
# -------------------------------------------------------
section "0. Preflight checks"
[[ $EUID -eq 0 ]] || error "Run as root: sudo bash deploy/setup-erik.sh"
command -v node >/dev/null || error "Node.js not found. Install Node.js 22 first."
command -v npm >/dev/null || error "npm not found."
command -v psql >/dev/null || error "psql not found. Install PostgreSQL 17 first."
command -v pm2 >/dev/null || error "pm2 not found. Run: npm install -g pm2"
command -v git >/dev/null || error "git not found."
NODE_VER=$(node --version | cut -d. -f1 | tr -d 'v')
[[ $NODE_VER -ge 22 ]] || warn "Node.js 22+ recommended. Found: $(node --version)"
info "All preflight checks passed."
# -------------------------------------------------------
# 1. Create application directory
# -------------------------------------------------------
section "1. Creating application directory"
if [[ -d "$GATEWAY_DIR" ]]; then
warn "$GATEWAY_DIR already exists — skipping git clone (will pull later)"
else
git clone "$GITEA_REPO" "$GATEWAY_DIR"
info "Cloned repository to $GATEWAY_DIR"
fi
cd "$GATEWAY_DIR"
# -------------------------------------------------------
# 2. Create log directory
# -------------------------------------------------------
section "2. Creating log directory"
mkdir -p "$LOG_DIR"
chown -R "$PM2_USER:$PM2_USER" "$LOG_DIR" 2>/dev/null || true
info "Log directory: $LOG_DIR"
# -------------------------------------------------------
# 3. PostgreSQL — database + user + migrations
# -------------------------------------------------------
section "3. Setting up PostgreSQL"
# Create user if not exists
if sudo -u postgres psql -tAc "SELECT 1 FROM pg_roles WHERE rolname='$DB_USER'" | grep -q 1; then
info "PostgreSQL user '$DB_USER' already exists."
else
sudo -u postgres psql -c "CREATE USER $DB_USER WITH PASSWORD '$DB_PASS';"
info "Created PostgreSQL user '$DB_USER'."
fi
# Create database if not exists
if sudo -u postgres psql -tAc "SELECT 1 FROM pg_database WHERE datname='$DB_NAME'" | grep -q 1; then
info "Database '$DB_NAME' already exists."
else
sudo -u postgres psql -c "CREATE DATABASE $DB_NAME OWNER $DB_USER;"
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE $DB_NAME TO $DB_USER;"
info "Created database '$DB_NAME'."
fi
# Run migrations
info "Running migrations..."
MIGRATION_DIR="$GATEWAY_DIR/packages/gateway/src/db/migrations"
if [[ -d "$MIGRATION_DIR" ]]; then
for sql_file in "$MIGRATION_DIR"/*.sql; do
[[ -f "$sql_file" ]] || continue
filename=$(basename "$sql_file")
info " Applying migration: $filename"
PGPASSWORD="$DB_PASS" psql -U "$DB_USER" -d "$DB_NAME" -h localhost -f "$sql_file" \
&& info "$filename" \
|| warn " Migration $filename may have already been applied (ignoring error)"
done
else
warn "Migration directory not found at $MIGRATION_DIR — skipping migrations"
fi
# Learning engine migrations
LEARNING_MIGRATION_DIR="$GATEWAY_DIR/packages/learning/src/db/migrations"
if [[ -d "$LEARNING_MIGRATION_DIR" ]]; then
for sql_file in "$LEARNING_MIGRATION_DIR"/*.sql; do
[[ -f "$sql_file" ]] || continue
filename=$(basename "$sql_file")
info " Applying learning migration: $filename"
PGPASSWORD="$DB_PASS" psql -U "$DB_USER" -d "$DB_NAME" -h localhost -f "$sql_file" \
&& info "$filename" \
|| warn " Migration $filename may have already been applied (ignoring error)"
done
fi
# -------------------------------------------------------
# 4. npm install + build
# -------------------------------------------------------
section "4. Installing dependencies and building"
cd "$GATEWAY_DIR"
npm install
npm run build
info "Build complete."
# -------------------------------------------------------
# 5. PM2 — register and start processes
# -------------------------------------------------------
section "5. Starting PM2 processes"
# If already registered, reload; otherwise start fresh
if pm2 list | grep -q "llm-gateway"; then
info "PM2 process 'llm-gateway' exists — reloading..."
pm2 reload llm-gateway
else
info "Starting PM2 processes from ecosystem config..."
pm2 start "$GATEWAY_DIR/deploy/ecosystem.config.cjs"
fi
# Save PM2 state so it survives reboots
pm2 save
# Register PM2 startup script (only if not already done)
if ! systemctl is-enabled pm2-root &>/dev/null 2>&1 && ! systemctl is-enabled "pm2-$PM2_USER" &>/dev/null 2>&1; then
info "Registering PM2 startup hook..."
pm2 startup systemd -u "$PM2_USER" --hp "/root" | tail -1 | bash || true
fi
# -------------------------------------------------------
# 6. Health check
# -------------------------------------------------------
section "6. Health check"
info "Waiting 5s for gateway to start..."
sleep 5
MAX_RETRIES=10
RETRY_DELAY=3
HEALTH_URL="http://localhost:3100/health/live"
for i in $(seq 1 $MAX_RETRIES); do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$HEALTH_URL" 2>/dev/null || echo "000")
if [[ "$STATUS" == "200" ]]; then
info "Health check PASSED (HTTP 200)"
break
fi
if [[ $i -eq $MAX_RETRIES ]]; then
warn "Health check did not return 200 after ${MAX_RETRIES} attempts (got: $STATUS)"
warn "Check logs: pm2 logs llm-gateway"
else
info " Attempt $i/$MAX_RETRIES — got HTTP $STATUS, retrying in ${RETRY_DELAY}s..."
sleep $RETRY_DELAY
fi
done
# -------------------------------------------------------
# 7. Summary
# -------------------------------------------------------
section "Setup complete"
echo ""
echo " Gateway: http://localhost:3100"
echo " Health: http://localhost:3100/health"
echo " Logs: pm2 logs llm-gateway"
echo " PM2 UI: pm2 monit"
echo ""
echo " Next steps:"
echo " 1. Add Cloudflare tunnel ingress (see deploy/cloudflare-tunnel.md)"
echo " 2. Pull Ollama models: bash scripts/pull-models.sh"
echo " 3. Verify: curl http://localhost:3100/health"
echo ""