AI Agents

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.

Updated 1 October 2026: the installer changed under us, twice

On 29 September 2026 new Hermes installs on a raw Ubuntu 22.04 server failed, with nothing changed on our side. Three things had moved upstream: the installer’s bundled Node now needs libatomic1, the hermes command now lands in ~/.local/bin, and hermes gateway install run as root writes only a user systemd unit. A day later the hosted install.sh moved again and no longer matched the release we had pinned. The steps below install Hermes Agent v0.21.5 from a fixed commit, which passed our real-server test on 30 September 2026 (run 20260930-000354). The full story: pin your agent versions.

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

# The installer's bundled Node links libatomic.so.1. DigitalOcean's Ubuntu 22.04 image
# does not ship it, and without it the install dies with "pm install failed".
sudo apt install -y libatomic1

# 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.z

Step 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. The one-liner you will see everywhere installs whatever is on main today:

curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash

We do not run that any more. The installer has no version flag or environment variable; it takes --commit SHA, and that is the pin. But pinning the commit while fetching today’s hosted script is not enough: on 29 September 2026 that combination failed with No module named 'pm' because the hosted script already expected a newer repository layout. Fetch the installer from the same commit, check its hash, and refuse to continue on anything else:

# Hermes Agent v0.21.5 (release tag v2026.9.24), validated 2026-09-30
HERMES_COMMIT=f97608f178d1ffeca59860195ab7da295f7c8e5f
HERMES_INSTALLER_SHA256=2017ddf0cc7bc6cfb70d40dc9fba1d916f47dbcccf5fe73bdee2cf93a11262af

curl -fsSL "https://raw.githubusercontent.com/NousResearch/hermes-agent/$HERMES_COMMIT/scripts/install.sh" \
  -o /tmp/hermes-install.sh
echo "$HERMES_INSTALLER_SHA256  /tmp/hermes-install.sh" | sha256sum -c - || exit 1
bash /tmp/hermes-install.sh --skip-browser --commit "$HERMES_COMMIT"

hermes --version   # must mention 0.21.5

Two naming traps. Release tags are CalVer (v2026.9.24) while the version Hermes reports is semver (0.21.5), so compare the right one. And upstream publishes no checksum, so the full 40-character commit id is the content pin.

As root, the current installer puts the code under ~/.hermes/hermes-agent and a hermes shim in ~/.local/bin, not /usr/local/bin. Scripts and systemd units that expect it on the system PATH fail with “hermes binary not found”; a symlink fixes that: ln -sfn ~/.local/bin/hermes /usr/local/bin/hermes. 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 install

Step 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=987654321

Once 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. Current releases can write the system unit themselves:

# --system writes /etc/systemd/system/hermes-gateway.service.
# Without it, run as root, Hermes writes only a USER unit and nothing starts on boot.
sudo hermes gateway install --system

sudo systemctl status hermes-gateway   # it must still be active 20 seconds later

Check the unit yourself rather than trusting the installer’s message. On 29 September 2026 it logged installed (gateway service enabled and started) with no system unit present at all. If your version lacks --system, write a unit by hand:

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 hermes

Tail 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.env

Update Hermes

Updating means moving the pin: choose the next release’s commit, take the installer from that commit, record its new hash, and run the Step 2 block again on a throwaway server before the one you depend on. Version, commit and installer hash move together. We have not tested hermes update against a pin; expect it to take you off the commit you chose.

# After a pin bump, prove the running agent is the one you meant
hermes --version
sudo systemctl restart hermes-gateway
journalctl -u hermes-gateway -n 30 --no-pager

Troubleshooting — 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 here

“Context length exceeded” that is really a billing cap

Verbatim from Hermes on 16 September 2026:

Context length exceeded (43 tokens). Cannot compress further.

The context was fine. Hermes sends max_tokens: 65536 for Sonnet 4.6, and OpenRouter reserves the full max_tokens up front. Our account had $6.92 left, so the provider answered 402 “requested up to 65536 tokens, but can only afford 6849” and Hermes reported it as a context error. Short calls kept passing and health checks stayed green, which is what makes this one slow to find. Check the provider’s HTTP status in the log before you touch the context settings.

What one turn costs

We measured about 15,000 input tokens for one tool-using Hermes turn on Sonnet 4.6 (17 September 2026), and paid about $0.05 for it; a three-call tool run cost $0.115. Most of those tokens are Hermes’s own system prompt and tool definitions, so a short question costs nearly as much as a long one. The worked numbers are in what an AI agent turn costs.

Model 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.

Related