#!/usr/bin/env bash set -euo pipefail # AgentHub Bootstrap Script — J10 Phase 1 LAN Deployment # Idempotent setup for Ubuntu 22.04/24.04 LTS # Target: < 15 min from bare metal to running stack AGENTHUB_USER="agenthub" AGENTHUB_UID=1001 AGENTHUB_HOME="/opt/agenthub" AGENTHUB_REPO="https://forgejo.barodine.net/barodine/agenthub.git" AGENTHUB_BRANCH="${AGENTHUB_BRANCH:-main}" echo "╔════════════════════════════════════════════════════╗" echo "║ AgentHub Bootstrap — Phase 1 LAN Deployment ║" echo "╚════════════════════════════════════════════════════╝" echo "" # Require root or sudo if [[ $EUID -ne 0 ]]; then echo "❌ This script must be run as root (use sudo)" exit 1 fi # ───────────────────────────────────────────────────────── # Step 1 — System Update # ───────────────────────────────────────────────────────── echo "[1/10] Updating system packages..." export DEBIAN_FRONTEND=noninteractive apt-get update -qq apt-get upgrade -y -qq echo "✅ System updated" echo "" # ───────────────────────────────────────────────────────── # Step 2 — Unattended Upgrades # ───────────────────────────────────────────────────────── echo "[2/10] Enabling unattended-upgrades..." apt-get install -y -qq unattended-upgrades # Configure automatic security updates if [[ ! -f /etc/apt/apt.conf.d/20auto-upgrades ]]; then cat > /etc/apt/apt.conf.d/20auto-upgrades <<'EOF' APT::Periodic::Update-Package-Lists "1"; APT::Periodic::Download-Upgradeable-Packages "1"; APT::Periodic::AutocleanInterval "7"; APT::Periodic::Unattended-Upgrade "1"; EOF fi systemctl enable --now unattended-upgrades echo "✅ Unattended upgrades enabled" echo "" # ───────────────────────────────────────────────────────── # Step 3 — Create agenthub user (UID 1001) # ───────────────────────────────────────────────────────── echo "[3/10] Creating agenthub user (UID ${AGENTHUB_UID})..." if id "${AGENTHUB_USER}" &>/dev/null; then echo " User ${AGENTHUB_USER} already exists, skipping" else useradd --system --uid "${AGENTHUB_UID}" --shell /bin/bash --create-home "${AGENTHUB_USER}" echo "✅ User ${AGENTHUB_USER} created" fi echo "" # ───────────────────────────────────────────────────────── # Step 4 — Install Docker Engine + Compose v2 # ───────────────────────────────────────────────────────── echo "[4/10] Installing Docker Engine + Compose v2..." if command -v docker &>/dev/null; then echo " Docker already installed: $(docker --version)" else # Install prerequisites apt-get install -y -qq \ ca-certificates \ curl \ gnupg \ lsb-release # Add Docker's official GPG key install -m 0755 -d /etc/apt/keyrings if [[ ! -f /etc/apt/keyrings/docker.gpg ]]; then curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg chmod a+r /etc/apt/keyrings/docker.gpg fi # Add Docker repository echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null # Install Docker apt-get update -qq apt-get install -y -qq docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin echo "✅ Docker installed: $(docker --version)" fi echo "" # ───────────────────────────────────────────────────────── # Step 5 — Enable and start Docker # ───────────────────────────────────────────────────────── echo "[5/10] Enabling Docker service..." systemctl enable --now docker usermod -aG docker "${AGENTHUB_USER}" echo "✅ Docker enabled and running" echo "" # ───────────────────────────────────────────────────────── # Step 6 — Create /opt/agenthub directory # ───────────────────────────────────────────────────────── echo "[6/10] Creating ${AGENTHUB_HOME} directory..." mkdir -p "${AGENTHUB_HOME}" chown "${AGENTHUB_USER}:${AGENTHUB_USER}" "${AGENTHUB_HOME}" chmod 750 "${AGENTHUB_HOME}" echo "✅ Directory created: $(ls -ld ${AGENTHUB_HOME})" echo "" # ───────────────────────────────────────────────────────── # Step 7 — Clone agenthub repository # ───────────────────────────────────────────────────────── echo "[7/10] Cloning agenthub repository..." if [[ -d "${AGENTHUB_HOME}/.git" ]]; then echo " Repository already cloned, pulling latest..." su - "${AGENTHUB_USER}" -c "cd ${AGENTHUB_HOME} && git pull origin ${AGENTHUB_BRANCH}" else # Install git if not present if ! command -v git &>/dev/null; then apt-get install -y -qq git fi su - "${AGENTHUB_USER}" -c "git clone --branch ${AGENTHUB_BRANCH} ${AGENTHUB_REPO} ${AGENTHUB_HOME}" fi echo "✅ Repository cloned/updated" echo "" # ───────────────────────────────────────────────────────── # Step 8 — Load .env file (mode 600) # ───────────────────────────────────────────────────────── echo "[8/10] Configuring .env file..." ENV_FILE="${AGENTHUB_HOME}/.env" if [[ -f "${ENV_FILE}" ]]; then echo " .env already exists, preserving existing configuration" else # Create .env from template if it doesn't exist if [[ -f "${AGENTHUB_HOME}/.env.example" ]]; then cp "${AGENTHUB_HOME}/.env.example" "${ENV_FILE}" # Generate secure JWT secret JWT_SECRET=$(openssl rand -base64 32) POSTGRES_PASSWORD=$(openssl rand -base64 24) # Replace placeholders in .env sed -i "s|JWT_SECRET=.*|JWT_SECRET=${JWT_SECRET}|" "${ENV_FILE}" sed -i "s|POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=${POSTGRES_PASSWORD}|" "${ENV_FILE}" echo "✅ .env created with generated secrets" else echo "⚠️ Warning: .env.example not found, you must create .env manually" fi fi chown "${AGENTHUB_USER}:${AGENTHUB_USER}" "${ENV_FILE}" chmod 600 "${ENV_FILE}" echo "✅ .env configured: $(ls -l ${ENV_FILE})" echo "" # ───────────────────────────────────────────────────────── # Step 9 — Pull images and start stack # ───────────────────────────────────────────────────────── echo "[9/10] Starting AgentHub stack..." cd "${AGENTHUB_HOME}" # Pull latest images su - "${AGENTHUB_USER}" -c "cd ${AGENTHUB_HOME} && docker compose -f compose.lan.yml pull" # Start stack su - "${AGENTHUB_USER}" -c "cd ${AGENTHUB_HOME} && docker compose -f compose.lan.yml up -d" # Wait for services to be ready echo " Waiting for services to start..." sleep 10 echo "✅ Stack started" echo "" # ───────────────────────────────────────────────────────── # Step 10 — Smoke test # ───────────────────────────────────────────────────────── echo "[10/10] Running smoke test..." HEALTH_URL="http://127.0.0.1:3000/healthz" # Retry health check up to 30 seconds for i in {1..15}; do if curl -sf "${HEALTH_URL}" > /dev/null; then HEALTH_RESPONSE=$(curl -s "${HEALTH_URL}") echo "✅ Smoke test passed: ${HEALTH_RESPONSE}" echo "" break else if [[ $i -eq 15 ]]; then echo "❌ Smoke test failed: ${HEALTH_URL} not responding after 30s" echo "" echo "Logs:" su - "${AGENTHUB_USER}" -c "cd ${AGENTHUB_HOME} && docker compose -f compose.lan.yml logs --tail=20" exit 1 fi echo " Attempt $i/15: waiting for health check..." sleep 2 fi done # ───────────────────────────────────────────────────────── # Complete # ───────────────────────────────────────────────────────── echo "╔════════════════════════════════════════════════════╗" echo "║ ✅ AgentHub Bootstrap Complete! ║" echo "╚════════════════════════════════════════════════════╝" echo "" echo "📋 Next steps:" echo "" echo " 1. Configure ufw firewall (see docs/RUNBOOK-lan.md)" echo " 2. Test WebSocket connection from LAN client" echo " 3. Set up monitoring (Uptime Kuma)" echo "" echo "🌐 Endpoints:" echo " - Health: http://$(hostname -I | awk '{print $1}'):3000/healthz" echo " - WebSocket: ws://$(hostname -I | awk '{print $1}'):3000/agents" echo "" echo "📖 Documentation: ${AGENTHUB_HOME}/docs/RUNBOOK-lan.md" echo ""