Autonomous, self-hosted AI agents have become a compelling alternative to traditional SaaS assistants: full data control, no recurring fees, and deep integration into existing infrastructure. I wanted to test this under real production conditions with Hermes Agent, an open-source (MIT) project by Nous Research running as a persistent daemon with long-term memory, cron tasks, and a multi-platform gateway (Telegram, Discord, Slack, WhatsApp, etc.).
Why This Project
The goal wasn't just running a five-minute curl | bash script — anyone can do that. The goal was deploying it production-style: proper user isolation, reduced attack surface, credential encryption, and a backup strategy resilient to server failures.
This guide documents every step, including real-world troubleshooting encounters — because real deployments never go strictly according to initial docs.
Final Architecture
Internet
│
▼
┌─────────────┐ HTTPS (Let's Encrypt)
│ Nginx │──────────────────────────┐
└─────────────┘ │
│ reverse proxy (127.0.0.1) │
▼ ▼
┌─────────────────┐ ┌──────────────────┐
│ Hermes Gateway │ │ Hermes WebUI │
│ (Telegram) │ │ (dashboard chat) │
│ restricted tools │ │ password auth │
└─────────────────┘ └──────────────────┘
│ │
└──────────────┬──────────────────────┘
▼
┌───────────────────┐
│ Hermes Agent Core │
│ (dedicated user, │
│ no sudo access) │
└───────────────────┘
│
▼
┌────────────────────────┐
│ Daily Cron at 03:00 │
│ hermes backup → zip │
│ rclone → Google Drive │
│ (encrypted config) │
└────────────────────────┘Two separate systemd services (hermes-gateway.service and hermes-webui.service), a dedicated non-sudo system user, and an automated backup pipeline replicating to encrypted remote storage.
1. Core Installation
Hermes provides a one-liner installer managing runtime dependencies (Python 3.11, Node.js, ripgrep, ffmpeg) automatically:
curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash
source ~/.bashrc
hermes setupThe interactive wizard configures LLM providers (Anthropic Claude, OpenRouter, Nous Portal, or any OpenAI-compatible endpoint). At this stage everything runs — but under root, without firewall policies, and with unrestricted tools.
2. Agent Isolation: Root → Dedicated User Migration
Running an agent with terminal access, code execution, and network access as rootis a shortcut that feels fine right up until it isn't. Step one: creating a dedicated unprivileged user.
adduser hermesMigrating data directories (~/.hermes and ~/.local/state/hermes), fixing ownership, and updating the systemd unit:
[Unit]
Description=Hermes Agent Gateway Service
After=network.target
[Service]
Type=simple
User=hermes
Group=hermes
ExecStart=/usr/local/lib/hermes-agent/venv/bin/python -m hermes_cli.main gateway run
WorkingDirectory=/home/hermes/.hermes
Environment="HERMES_HOME=/home/hermes/.hermes"
Restart=always
[Install]
WantedBy=multi-user.targethermes config show as root printed empty configuration — expected, as the CLI inspects the active user's $HOME. Always verify with sudo -u hermes -i.3. Hardening Telegram Bot Attack Surface
This is the single most critical security hardening step: by default, messaging platforms share the full CLI toolset. Anyone paired via Telegram could execute arbitrary shell commands, code, and browse your network.
config.yaml snippet before hardening:
platform_toolsets:
telegram:
- terminal
- code_execution
- computer_use
- browser
- delegation
- file
- memory
- web
# ...After hardening (retaining only essential messaging tools):
platform_toolsets:
telegram:
- clarify
- cronjob
- file
- image_gen
- memory
- session_search
- skills
- todo
- tts
- vision
- webterminal, code_execution, computer_use, browser, and delegation were stripped. delegation was explicitly removed because delegated sub-agents could otherwise invoke blocked tools.
In addition, security guardrails were explicitly enabled:
security:
redact_secrets: true # Redacts API keys / tokens from logs & responses
tirith_enabled: true # Pre-execution command inspector
tirith_fail_open: false # Blocks (instead of allowing) if inspector failsSetting fail_open: false is intentional: default permissive fallbacks on public facing bots are unsafe. Pairing controls (hermes pairing approve telegram <code>) ensure only explicitly approved user IDs interact with the agent.
4. Web Dashboard: Official vs Community WebUI
Hermes includes an internal dashboard (hermes dashboard, port 9119), but I deployed Hermes WebUI (community MIT project) for rich chat features, session tracking, streaming, and file browsing.
Using third-party tooling requires risk trade-offs offset here by: loopback binding only, strict password authentication, and HTTPS reverse proxy encapsulation.
Screenshot: Hermes WebUI running in active production on hermes.samensteeve.comwith multi-channel sessions (WebUI & Telegram).
git clone https://github.com/nesquena/hermes-webui.git
cd hermes-webui
python3 bootstrap.pyHERMES_WEBUI_HOST=127.0.0.1
HERMES_WEBUI_PASSWORD=<strong-generated-password>
HERMES_WEBUI_SECURE=1
HERMES_WEBUI_ALLOWED_ORIGINS=https://hermes.yourdomain.comThree Troubleshooting Lessons:
- Python Interpreter Mismatch: The service initially used system Python (
/usr/bin/python3) missing agent dependencies (httpx,dotenv). Solution: pointExecStartto the agent virtualenv directly. - Orphaned Zombie Processes: A failed restart left port 8787 locked (
FATAL: Another server is already responding on 127.0.0.1:8787). Resolved viass -tlnpPID identification and cleanup. - Malformed YAML Syntax: Manual edit left an unindented commented key header (
# security:) breaking the YAML parser. Always validate viapython3 -c "import yaml; yaml.safe_load(...)"before restarting services.
Nginx Reverse Proxy + Let's Encrypt SSL:
server {
listen 80;
server_name hermes.yourdomain.com;
location / {
proxy_pass http://127.0.0.1:8787;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}sudo certbot --nginx -d hermes.yourdomain.com5. Encrypted, Automated Remote Backups
An autonomous agent accumulates long-term state, memory, and custom skills over time. Strategy: daily local snapshot + Google Drive remote sync with 14-day retention.
#!/bin/bash
set -euo pipefail
cd /home/hermes
export RCLONE_CONFIG_PASS="********" # Encrypted rclone config password
BACKUP_DIR="/home/hermes/backups"
DATE=$(date +%Y%m%d-%H%M%S)
KEEP_DAYS=14
GDRIVE_REMOTE="gdrive:hermes-backups"
hermes backup -o "$BACKUP_DIR/hermes-backup-$DATE.zip" -l "daily-cron"
rclone copy "$BACKUP_DIR/hermes-backup-$DATE.zip" "$GDRIVE_REMOTE" --quiet
find "$BACKUP_DIR" -name "hermes-backup-*.zip" -mtime +$KEEP_DAYS -delete
rclone delete "$GDRIVE_REMOTE" --min-age ${KEEP_DAYS}d --quiet0 3 * * * /home/hermes/scripts/backup-hermes.sh >> /home/hermes/backups/backup.log 2>&1Key Takeaways & Technical Proof
- System Hardening: Privilege separation, permission enforcement, process isolation
- Network Architecture: Reverse proxying, TLS termination, loopback interface bounds
- Secrets Management: At-rest encryption, environment injection, automatic log redaction
- Reliable Automation:
systemdunits, cron scheduling, idempotent shell scripting (set -euo pipefail) - Methodical Debugging:
journalctlinvestigation, root cause isolation

