How to self-host Hermes Agent on a VPS
Hermes, by Nous Research, is an MIT-licensed autonomous AI agent that runs locally or on your own server. Self-hosting gives you full data ownership, no vendor lock-in, and the freedom to choose any LLM backend. This guide walks you through provisioning a VPS, installing Hermes, configuring a provider, wiring up Telegram, and running it as a resilient systemd service.
Prerequisites
- A VPS running Ubuntu 22.04+ or Debian 12
- Minimum 2 GB RAM and 10 GB disk (4 GB RAM / 2 vCPU recommended for comfortable headroom)
- Root or sudo SSH access
- An API key from one of: Nous Portal, OpenRouter, or OpenAI
- A Telegram bot token (optional but recommended for easy mobile access)
Why self-host?
When you run Hermes on your own VPS, your conversations and tool outputs never touch a third-party platform. You own the process, the logs, and the storage. You can also pin a specific Hermes version and update on your schedule — no surprise breaking changes.
Step 1 — System dependencies
Hermes requires Python 3.11+, Node.js, ripgrep, ffmpeg, and git. Run the following on your VPS:
sudo apt update && sudo apt upgrade -y
sudo apt install -y git ripgrep ffmpeg python3.11 python3.11-venv python3-pip curl
# Install Node.js 20 LTS via NodeSource
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
# Verify
python3.11 --version # Python 3.11.x
node --version # v20.x.x
rg --version # ripgrep x.y.zStep 2 — Install Hermes
Nous Research provides an official install script that clones the repo, sets up a Python virtual environment, and installs all Node and Python dependencies:
curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bashThe script installs Hermes into ~/.hermes by default and adds the hermes command to your PATH. If you prefer a manual install, clone directly:
git clone https://github.com/NousResearch/hermes-agent.git ~/hermes-agent
cd ~/hermes-agent
python3.11 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
npm installStep 3 — Configure your LLM provider
Hermes is BYOK (Bring Your Own Key). It supports Nous Portal, OpenRouter, and OpenAI-compatible APIs. Copy the example config and add your key:
# ~/.hermes/config.env (or the path shown by the installer)
LLM_PROVIDER=nous
NOUS_API_KEY=your_nous_portal_key_here
# Model: hermes-3-70b (or latest Hermes model on the portal)Step 4 — Connect Telegram (recommended)
Telegram gives you a mobile-friendly interface to interact with Hermes from anywhere. Create a bot via @BotFather in Telegram, then add the token to your config:
# In ~/.hermes/config.env
TELEGRAM_BOT_TOKEN=123456789:ABCdef...
# Optional: restrict to your Telegram user ID
TELEGRAM_ALLOWED_USER_IDS=987654321Once configured, Hermes will register the webhook automatically on first start. Send your bot a message and it will respond through the same agent loop.
Step 5 — Run as a systemd service
Running Hermes as a systemd unit means it starts on boot, restarts on crash, and writes logs to journald:
sudo tee /etc/systemd/system/hermes.service > /dev/null <<'EOF'
[Unit]
Description=Hermes AI Agent (Nous Research)
After=network.target
[Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu/.hermes
EnvironmentFile=/home/ubuntu/.hermes/config.env
ExecStart=/home/ubuntu/.hermes/.venv/bin/python -m hermes
Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable hermes
sudo systemctl start hermes
sudo systemctl status hermesTail the logs with journalctl -u hermes -f. You should see the agent report it is connected and waiting for input.
“Connected and waiting” does not mean it can answer
That message means the process started and its channels are wired up. It says nothing about whether your LLM provider will accept a request — that is a separate system, and it fails separately. We provision this stack repeatedly for testing and have seen installs finish completely clean, systemd report the service healthy, and the agent still be unable to answer a single prompt.
Send one real message through Telegram with the log open. A reply is the only thing that proves the install, the key, the model name and the provider account are all correct at the same time.
Step 6 — Backups and updates
Back up your config and data
Hermes stores conversation history and agent memory in its data directory (typically ~/.hermes/data). Schedule a daily backup:
# Add to crontab: crontab -e
0 3 * * * tar -czf /var/backups/hermes-$(date +%F).tar.gz ~/.hermes/data ~/.hermes/config.envUpdate Hermes
cd ~/.hermes
git pull origin main
source .venv/bin/activate && pip install -r requirements.txt
npm install
sudo systemctl restart hermesTroubleshooting — what actually goes wrong
We install Hermes on fresh, disposable VPS instances continuously to test our own provisioning. Almost none of the failures are the install — they cluster at the boundary between the agent and the model provider, which is the one part an install script cannot verify for you.
Service healthy, every prompt fails
The install completes, systemctl status hermes is green, and nothing answers. Provider errors appear when a request is made, not when the service starts, and they are usually about the account rather than the config — an exhausted balance, a spend cap, a key scoped to the wrong model. Verbatim from one of our runs, where the OpenRouter key had hit its limit:
HTTP 502 {"error":{"message":"Upstream provider error","type":"upstream_error",
"details":{"error":{"message":"Key limit exceeded (total limit). Manage it using
https://openrouter.ai/workspaces/default/keys/..."}}}}Nothing was wrong with the machine, the install or the config — the fix was a billing page. Because Hermes is BYOK, always confirm the key works on its own before debugging the agent. Test it directly, outside Hermes entirely, using whichever provider you configured in Step 3:
# OpenRouter (also shows your remaining credit / limits)
curl -s https://openrouter.ai/api/v1/auth/key \
-H "Authorization: Bearer $OPENROUTER_API_KEY"
# Any OpenAI-compatible endpoint — a minimal, near-free completion
curl -s https://openrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "content-type: application/json" \
-d '{"model":"nousresearch/hermes-3-llama-3.1-70b","max_tokens":16,
"messages":[{"role":"user","content":"say ready"}]}'If that fails, no Hermes configuration will fix it. If it succeeds and the agent still cannot answer, the problem is the key, model string or base URL as Hermes has them — check that the running service actually loaded the config you edited, since a systemd unit reads its environment once at start:
sudo systemctl restart hermes # after ANY config.env change
journalctl -u hermes -n 50 --no-pager # the provider error lands hereModel names are provider-specific
The same model carries different identifiers on different platforms — hermes-3-70b on Nous Portal is nousresearch/hermes-3-llama-3.1-70b on OpenRouter. Switching provider without switching the model string produces an authentication-looking error that has nothing to do with your key. Copy the identifier from the provider's own model list rather than from another guide.
If you add anything in Docker, UFW will not protect it
Hermes itself runs natively here, but agents accumulate side-cars — a vector store, a database, a dashboard. Docker writes iptables rules that are evaluated before UFW's, so a published container port is reachable from the internet even when ufw status reports it denied. We measured a database container going from unreachable to publicly open the moment it started, with no firewall rule changed. Publish on 127.0.0.1 and reach it over an SSH tunnel — the VPS security guide has the measurement and the fix.
Prefer not to manage it yourself?
AgentOcean deploys a fully managed Hermes instance on a dedicated VPS in about 30 seconds — HTTPS, backups, and monitoring included.