feat: add Hermes Agent LXC
Adds container scripts for Hermes Agent (Nous Research), a self-improving AI agent with LLM provider integration, terminal execution, web browsing, and multi-platform messaging support. Files: - ct/hermes-agent.sh - install/hermes-agent-install.sh - json/hermes-agent.json - ct/headers/hermes-agent Deviations from standard patterns (justified): 1. Uses upstream installer (curl-pipe) instead of fetch_and_deploy_gh_release: Hermes is a uv-managed Python application with complex dependency resolution, virtualenv management, and binary placement—not a single binary or tarball from GitHub Releases. 2. Dedicated 'hermes' service user (not running as root): The agent executes arbitrary terminal commands on behalf of the user. Running as root would give the AI unrestricted system access. This follows the protonmail-bridge service-user pattern for isolation. 3. Dashboard (port 9119) bound to localhost only, requiring SSH tunnel: The web UI provides admin access to an AI that can execute commands. SSH tunnel provides an authentication/authorization boundary. 4. /usr/bin/hermes shim script: The hermes CLI validates cwd permissions; running 'hermes' as root from /root fails. The shim cd's to /home/hermes and exec's as the hermes user via runuser. 5. setsid --wait wrapping of upstream installer: The upstream installer probes /dev/tty for interactive prompts even with --skip-setup; setsid detaches the controlling terminal.
This commit is contained in:
6
ct/headers/hermes-agent
Normal file
6
ct/headers/hermes-agent
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
__ __ ___ __
|
||||||
|
/ / / /__ _________ ___ ___ _____ / | ____ ____ ____ / /_
|
||||||
|
/ /_/ / _ \/ ___/ __ `__ \/ _ \/ ___/ / /| |/ __ `/ _ \/ __ \/ __/
|
||||||
|
/ __ / __/ / / / / / / / __(__ ) / ___ / /_/ / __/ / / / /_
|
||||||
|
/_/ /_/\___/_/ /_/ /_/ /_/\___/____/ /_/ |_\__, /\___/_/ /_/\__/
|
||||||
|
/____/
|
||||||
68
ct/hermes-agent.sh
Normal file
68
ct/hermes-agent.sh
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)
|
||||||
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
|
# Author: Stephen Chin (steveonjava)
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
||||||
|
# Source: https://hermes-agent.nousresearch.com/
|
||||||
|
|
||||||
|
APP="Hermes Agent"
|
||||||
|
var_tags="${var_tags:-ai;automation;agent}"
|
||||||
|
var_cpu="${var_cpu:-2}"
|
||||||
|
var_ram="${var_ram:-4096}"
|
||||||
|
var_disk="${var_disk:-20}"
|
||||||
|
var_os="${var_os:-debian}"
|
||||||
|
var_version="${var_version:-13}"
|
||||||
|
var_unprivileged="${var_unprivileged:-1}"
|
||||||
|
|
||||||
|
header_info "$APP"
|
||||||
|
variables
|
||||||
|
color
|
||||||
|
catch_errors
|
||||||
|
|
||||||
|
function update_script() {
|
||||||
|
header_info
|
||||||
|
check_container_storage
|
||||||
|
check_container_resources
|
||||||
|
|
||||||
|
if [[ ! -x /home/hermes/.local/bin/hermes ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg_info "Stopping Services"
|
||||||
|
systemctl stop hermes-dashboard
|
||||||
|
systemctl stop hermes-gateway
|
||||||
|
msg_ok "Stopped Services"
|
||||||
|
|
||||||
|
msg_info "Updating ${APP}"
|
||||||
|
$STD env \
|
||||||
|
HOME=/home/hermes \
|
||||||
|
HERMES_HOME=/home/hermes/.hermes \
|
||||||
|
/home/hermes/.local/bin/hermes update
|
||||||
|
chown -R hermes:hermes /home/hermes
|
||||||
|
msg_ok "Updated ${APP}"
|
||||||
|
|
||||||
|
msg_info "Starting Services"
|
||||||
|
systemctl start hermes-gateway
|
||||||
|
systemctl start hermes-dashboard
|
||||||
|
msg_ok "Started Services"
|
||||||
|
msg_ok "Updated successfully!"
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
start
|
||||||
|
build_container
|
||||||
|
description
|
||||||
|
|
||||||
|
msg_ok "Completed successfully!\n"
|
||||||
|
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||||
|
echo -e "${INFO}${YW} Connect via SSH and configure your LLM provider:${CL}"
|
||||||
|
echo -e "${TAB}${GATEWAY}${BGN}ssh hermes@${IP}${CL}"
|
||||||
|
echo -e "${TAB}${BGN}hermes setup${CL}"
|
||||||
|
echo -e "${INFO}${YW} API Server (OpenAI-compatible):${CL}"
|
||||||
|
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8642/v1${CL}"
|
||||||
|
echo -e "${INFO}${YW} API key stored at:${CL}"
|
||||||
|
echo -e "${TAB}${BGN}/home/hermes/.hermes/.env${CL}"
|
||||||
|
echo -e "${INFO}${YW} Web Dashboard (via SSH tunnel):${CL}"
|
||||||
|
echo -e "${TAB}${BGN}ssh -L 9119:localhost:9119 hermes@${IP}${CL}"
|
||||||
|
echo -e "${TAB}${BGN}Then open: http://localhost:9119${CL}"
|
||||||
121
install/hermes-agent-install.sh
Normal file
121
install/hermes-agent-install.sh
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
|
# Author: Stephen Chin (steveonjava)
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
||||||
|
# Source: https://hermes-agent.nousresearch.com/
|
||||||
|
|
||||||
|
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||||
|
color
|
||||||
|
verb_ip6
|
||||||
|
catch_errors
|
||||||
|
setting_up_container
|
||||||
|
network_check
|
||||||
|
update_os
|
||||||
|
|
||||||
|
msg_info "Installing Dependencies"
|
||||||
|
$STD apt install -y \
|
||||||
|
git
|
||||||
|
msg_ok "Installed Dependencies"
|
||||||
|
|
||||||
|
NODE_VERSION="22" setup_nodejs
|
||||||
|
|
||||||
|
msg_info "Creating Hermes User"
|
||||||
|
useradd -m -s /bin/bash hermes
|
||||||
|
msg_ok "Created Hermes User"
|
||||||
|
|
||||||
|
msg_info "Installing Hermes Agent"
|
||||||
|
$STD setsid --wait env \
|
||||||
|
HOME=/home/hermes \
|
||||||
|
PATH=/home/hermes/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
|
||||||
|
bash <(curl -fsSL https://hermes-agent.nousresearch.com/install.sh) --skip-setup --hermes-home /home/hermes/.hermes --dir /home/hermes/.hermes/hermes-agent
|
||||||
|
|
||||||
|
if [[ ! -x /home/hermes/.local/bin/hermes ]]; then
|
||||||
|
msg_error "Hermes binary not found after installation"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
chown -R hermes:hermes /home/hermes
|
||||||
|
git config --system --add safe.directory /home/hermes/.hermes/hermes-agent 2>/dev/null || true
|
||||||
|
msg_ok "Installed Hermes Agent"
|
||||||
|
|
||||||
|
msg_info "Installing Web Dashboard"
|
||||||
|
$STD runuser -u hermes -- \
|
||||||
|
env HOME=/home/hermes VIRTUAL_ENV=/home/hermes/.hermes/hermes-agent/venv \
|
||||||
|
/home/hermes/.local/bin/uv pip install 'hermes-agent[web,pty]'
|
||||||
|
msg_ok "Installed Web Dashboard"
|
||||||
|
|
||||||
|
msg_info "Configuring API Server"
|
||||||
|
API_SERVER_KEY=$(openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | cut -c1-32)
|
||||||
|
cat <<EOF >/home/hermes/.hermes/.env
|
||||||
|
API_SERVER_ENABLED=true
|
||||||
|
API_SERVER_HOST=0.0.0.0
|
||||||
|
API_SERVER_PORT=8642
|
||||||
|
API_SERVER_KEY=${API_SERVER_KEY}
|
||||||
|
EOF
|
||||||
|
chmod 600 /home/hermes/.hermes/.env
|
||||||
|
chown hermes:hermes /home/hermes/.hermes/.env
|
||||||
|
msg_ok "Configured API Server"
|
||||||
|
|
||||||
|
msg_info "Creating Service"
|
||||||
|
cat <<EOF >/etc/systemd/system/hermes-gateway.service
|
||||||
|
[Unit]
|
||||||
|
Description=Hermes Agent Gateway
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=hermes
|
||||||
|
Group=hermes
|
||||||
|
WorkingDirectory=/home/hermes
|
||||||
|
ExecStart=/home/hermes/.local/bin/hermes gateway run --replace
|
||||||
|
Environment="HERMES_HOME=/home/hermes/.hermes"
|
||||||
|
Environment="HOME=/home/hermes"
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl enable -q --now hermes-gateway
|
||||||
|
msg_ok "Created Service"
|
||||||
|
|
||||||
|
msg_info "Creating Dashboard Service"
|
||||||
|
cat <<EOF >/etc/systemd/system/hermes-dashboard.service
|
||||||
|
[Unit]
|
||||||
|
Description=Hermes Agent Web Dashboard
|
||||||
|
After=network-online.target hermes-gateway.service
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=hermes
|
||||||
|
Group=hermes
|
||||||
|
WorkingDirectory=/home/hermes
|
||||||
|
ExecStart=/home/hermes/.local/bin/hermes dashboard --host 127.0.0.1 --port 9119 --no-open
|
||||||
|
Environment="HERMES_HOME=/home/hermes/.hermes"
|
||||||
|
Environment="HOME=/home/hermes"
|
||||||
|
Environment="PATH=/home/hermes/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||||
|
Environment="NODE_OPTIONS=--max-old-space-size=3072"
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl enable -q --now hermes-dashboard
|
||||||
|
msg_ok "Created Dashboard Service"
|
||||||
|
|
||||||
|
msg_info "Creating Hermes Shim"
|
||||||
|
cat <<'EOF' >/usr/bin/hermes
|
||||||
|
#!/bin/bash
|
||||||
|
cd /home/hermes
|
||||||
|
exec runuser -u hermes -- /home/hermes/.local/bin/hermes "$@"
|
||||||
|
EOF
|
||||||
|
chmod +x /usr/bin/hermes
|
||||||
|
msg_ok "Created Hermes Shim"
|
||||||
|
|
||||||
|
motd_ssh
|
||||||
|
customize
|
||||||
|
cleanup_lxc
|
||||||
52
json/hermes-agent.json
Normal file
52
json/hermes-agent.json
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
{
|
||||||
|
"name": "Hermes Agent",
|
||||||
|
"slug": "hermes-agent",
|
||||||
|
"categories": [
|
||||||
|
20
|
||||||
|
],
|
||||||
|
"date_created": "2026-05-02",
|
||||||
|
"type": "ct",
|
||||||
|
"updateable": true,
|
||||||
|
"privileged": false,
|
||||||
|
"interface_port": 8642,
|
||||||
|
"documentation": "https://hermes-agent.nousresearch.com/docs",
|
||||||
|
"website": "https://hermes-agent.nousresearch.com",
|
||||||
|
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/hermes.webp",
|
||||||
|
"description": "Self-improving AI agent by Nous Research. Connects to 15+ LLM providers, executes terminal commands, browses the web, and learns from experience. Supports 16 messaging platforms (Telegram, Discord, Slack, WhatsApp, Signal, Matrix, and more) with persistent memory and autonomous skill creation.",
|
||||||
|
"install_methods": [
|
||||||
|
{
|
||||||
|
"type": "default",
|
||||||
|
"script": "ct/hermes-agent.sh",
|
||||||
|
"config_path": "/home/hermes/.hermes/",
|
||||||
|
"resources": {
|
||||||
|
"cpu": 2,
|
||||||
|
"ram": 4096,
|
||||||
|
"hdd": 20,
|
||||||
|
"os": "debian",
|
||||||
|
"version": "13"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"default_credentials": {
|
||||||
|
"username": "hermes",
|
||||||
|
"password": null
|
||||||
|
},
|
||||||
|
"notes": [
|
||||||
|
{
|
||||||
|
"text": "Warning: Hermes can execute terminal commands. The agent runs as a dedicated 'hermes' service user for isolation.",
|
||||||
|
"type": "warning"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "After container startup, SSH in as the 'hermes' user and run 'hermes setup' to configure your LLM provider (OpenRouter, Anthropic, OpenAI, Nous Portal, or custom endpoint).",
|
||||||
|
"type": "info"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "OpenAI-compatible API server available at http://<container-ip>:8642/v1. API key is stored in /home/hermes/.hermes/.env.",
|
||||||
|
"type": "info"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Access the web dashboard via SSH tunnel: ssh -L 9119:localhost:9119 hermes@<container-ip>, then open http://localhost:9119",
|
||||||
|
"type": "info"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user