Complete implementation ready for Coolify: - Node.js 22 + Fastify + socket.io backend - PostgreSQL 16 + Redis 7 services - Docker Compose configuration - Deployment scripts and documentation Co-Authored-By: Paperclip <noreply@paperclip.ing>
232 lines
11 KiB
Bash
Executable file
232 lines
11 KiB
Bash
Executable file
#!/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 ""
|