195 lines
6.7 KiB
Bash
Executable File
195 lines
6.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# ------------------------------------------------------------------
|
|
# provision.sh — Packer bake-time provisioner for Hermes Agent
|
|
#
|
|
# Runs as root on a fresh Ubuntu 24.04 instance.
|
|
# Installs everything that does NOT depend on per-instance secrets:
|
|
# • system deps (incl. zsh, python3-venv)
|
|
# • Hermes Agent (from GitHub)
|
|
# • Docker (hermes user added to docker group)
|
|
# • Oh My Zsh + Homebrew (as hermes user)
|
|
# • code-server
|
|
# • ttyd
|
|
# • Caddy (stable)
|
|
# • ufw defaults
|
|
# ------------------------------------------------------------------
|
|
set -euo pipefail
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
|
|
HERMES_VERSION="${HERMES_VERSION:-v0.7.0}"
|
|
|
|
echo "▶ System packages"
|
|
apt-get update
|
|
apt-get upgrade -y
|
|
apt-get install -y --no-install-recommends \
|
|
build-essential procps curl file git ca-certificates \
|
|
gnupg software-properties-common ufw jq python3 python3-venv \
|
|
zsh systemd-container ttyd ri ffmpeg
|
|
|
|
# ── Docker ──
|
|
echo "▶ Docker"
|
|
install -m 0755 -d /etc/apt/keyrings
|
|
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
|
|
chmod a+r /etc/apt/keyrings/docker.asc
|
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
|
|
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
|
|
| tee /etc/apt/sources.list.d/docker.list > /dev/null
|
|
apt-get update
|
|
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
|
systemctl enable docker
|
|
systemctl start docker
|
|
|
|
# ── Caddy (stable) ──
|
|
echo "▶ Caddy"
|
|
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
|
|
| gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
|
|
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
|
|
| tee /etc/apt/sources.list.d/caddy-stable.list
|
|
chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg
|
|
chmod o+r /etc/apt/sources.list.d/caddy-stable.list
|
|
apt-get update
|
|
apt-get install -y caddy
|
|
systemctl disable caddy # don't start until cloud-init configures it
|
|
|
|
# ── Firewall defaults ──
|
|
echo "▶ UFW"
|
|
ufw default deny incoming
|
|
ufw default allow outgoing
|
|
ufw allow ssh
|
|
ufw allow http
|
|
ufw allow https
|
|
ufw allow 7681/tcp comment "ttyd"
|
|
ufw allow 8080/tcp comment "code-server"
|
|
ufw --force enable
|
|
|
|
# ── Create hermes user (regular user, zsh as default shell) ──
|
|
echo "▶ hermes user"
|
|
if ! id hermes &>/dev/null; then
|
|
useradd -m -s /usr/bin/zsh hermes
|
|
else
|
|
chsh -s /usr/bin/zsh hermes
|
|
fi
|
|
|
|
# Create ttyd group and add hermes to it
|
|
groupadd ttyd 2>/dev/null || true
|
|
usermod -aG ttyd hermes
|
|
usermod -aG docker hermes
|
|
|
|
# Allow hermes user's systemd services to run without an active session
|
|
loginctl enable-linger hermes
|
|
|
|
# Pre-create directories
|
|
mkdir -p /home/hermes/.hermes/{cron,sessions,logs,pairing,hooks,image_cache,audio_cache,memories,skills}
|
|
mkdir -p /home/hermes/.local/bin
|
|
mkdir -p /home/hermes/.config/code-server
|
|
chown -R hermes:hermes /home/hermes
|
|
|
|
# ── Oh My Zsh (as hermes user) ──
|
|
echo "▶ Oh My Zsh"
|
|
su - hermes -c 'sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended'
|
|
|
|
# ── Homebrew (installed as hermes user) ──
|
|
echo "▶ Homebrew"
|
|
echo 'hermes ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/hermes
|
|
su - hermes -c 'NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"'
|
|
|
|
# Persist Homebrew in all shells
|
|
cat >> /home/hermes/.bashrc <<'BREWEOF'
|
|
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
|
|
BREWEOF
|
|
cat >> /home/hermes/.profile <<'BREWEOF'
|
|
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
|
|
BREWEOF
|
|
cat >> /home/hermes/.zshrc <<'BREWEOF'
|
|
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
|
|
BREWEOF
|
|
|
|
# Add Homebrew to system-wide PATH
|
|
cat > /etc/profile.d/homebrew.sh <<'BREWPROFILE'
|
|
# Homebrew
|
|
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
|
|
BREWPROFILE
|
|
chmod +x /etc/profile.d/homebrew.sh
|
|
|
|
chown hermes:hermes /home/hermes/.zshrc /home/hermes/.bashrc /home/hermes/.profile
|
|
|
|
su - hermes -c 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" && brew --version && brew analytics off'
|
|
|
|
# ── code-server ──
|
|
echo "▶ code-server"
|
|
# Wait for any background apt/dpkg processes to finish
|
|
while fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1; do
|
|
echo " Waiting for dpkg lock..."
|
|
sleep 5
|
|
done
|
|
curl -fsSL https://code-server.dev/install.sh | sh
|
|
|
|
chown -R hermes:hermes /home/hermes/.config
|
|
|
|
# ── Install Hermes Agent ──
|
|
echo "▶ Hermes Agent ${HERMES_VERSION}"
|
|
su - hermes -c "git clone --branch ${HERMES_VERSION} --depth 1 https://github.com/NousResearch/hermes-agent.git /home/hermes/.hermes/hermes-agent"
|
|
su - hermes -c "cd /home/hermes/.hermes/hermes-agent && python3 -m venv venv && ./venv/bin/pip install --upgrade pip --quiet && ./venv/bin/pip install -e '.[all]' --quiet"
|
|
su - hermes -c "ln -sf /home/hermes/.hermes/hermes-agent/venv/bin/hermes /home/hermes/.local/bin/hermes"
|
|
|
|
# Add hermes binary to PATH in shells
|
|
grep -q 'export PATH.*.local/bin' /home/hermes/.bashrc 2>/dev/null || \
|
|
echo 'export PATH="$HOME/.local/bin:$PATH"' >> /home/hermes/.bashrc
|
|
grep -q 'export PATH.*.local/bin' /home/hermes/.zshrc 2>/dev/null || \
|
|
echo 'export PATH="$HOME/.local/bin:$PATH"' >> /home/hermes/.zshrc
|
|
|
|
chown -R hermes:hermes /home/hermes
|
|
|
|
# ── Create ttyd systemd service ──
|
|
echo "▶ ttyd service"
|
|
HERMES_UID=$(id -u hermes)
|
|
HERMES_GID=$(id -g hermes)
|
|
|
|
cat > /etc/systemd/system/ttyd-hermes.service << EOF
|
|
[Unit]
|
|
Description=ttyd terminal for Hermes Agent
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
Environment="HOME=/home/hermes"
|
|
Environment="PATH=/home/linuxbrew/.linuxbrew/bin:/home/hermes/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
ExecStart=/usr/bin/ttyd -p 7681 -u $HERMES_UID -g $HERMES_GID -W -t fontSize=14 -t theme='{"background":"#1a1a2e","foreground":"#eee"}' /home/hermes/.local/bin/hermes
|
|
Restart=always
|
|
RestartSec=3
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
|
|
# ── Create code-server systemd service ──
|
|
echo "▶ code-server service"
|
|
cat > /etc/systemd/system/code-server-hermes.service << 'EOF'
|
|
[Unit]
|
|
Description=code-server for Hermes
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=hermes
|
|
Environment="HOME=/home/hermes"
|
|
Environment="PATH=/home/linuxbrew/.linuxbrew/bin:/home/hermes/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
WorkingDirectory=/home/hermes
|
|
ExecStart=/usr/bin/code-server --config /home/hermes/.config/code-server/config.yaml
|
|
Restart=always
|
|
RestartSec=3
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
|
|
systemctl daemon-reload
|
|
|
|
# ── Cleanup ──
|
|
echo "▶ Cleanup"
|
|
apt-get autoremove -y
|
|
apt-get clean
|
|
rm -rf /var/lib/apt/lists/*
|
|
|
|
echo "✅ Packer provisioning complete"
|