
Every few months a new AI agent framework shows up promising to “run itself” on your infrastructure, and most of them fall apart the second you try to put them on a real server instead of a laptop. Hermes Agent, the open-source autonomous agent framework from Nous Research, is one of the rare exceptions that actually behaves like production software once you know where the sharp edges are.
If you’ve landed here, you’re probably trying to get Hermes running on a fresh Ubuntu 26.04 LTS “Resolute Raccoon” box, either for personal automation, a client project, or as a persistent assistant reachable from Telegram or Slack around the clock. That’s a reasonable goal. Hermes is designed exactly for that: a long-running process with persistent memory that grows its own skill set over time, rather than a stateless chatbot you open and close.
The problem is that most install guides floating around treat this like a five-minute hobbyist task. Pipe a curl script into bash, run hermes setup, done. That works fine on a personal machine you reboot every night. It does not work fine when you’re the person on-call at 3 a.m. because the agent process died silently, or when a client asks why an unauthenticated port is open on their VPS, or when a compliance audit flags a root-owned Python environment nobody can explain.
This guide walks through installing Hermes Agent on Ubuntu 26.04 LTS the way you’d actually want it configured on a server you’re responsible for: proper user isolation, systemd supervision with automatic restarts, Docker-based sandboxing for tool execution, firewall rules, and a troubleshooting section built from the kinds of errors that actually show up in the wild. Ubuntu 26.04 shipped with Linux kernel 7.0, GNOME 50 on the desktop side, a Wayland-only session, and the new sudo-rs implementation replacing the classic sudo binary, all of which have small but real implications for how you should set this up.
What Hermes Agent Actually Is (and Why That Matters for Installation)
Before touching a terminal, it’s worth being precise about what you’re installing, because the architecture dictates the install decisions later.
Hermes Agent is not a single binary or a Docker image you just pull. It’s a self-hosted runtime, MIT-licensed, built around a Python 3.11 environment, that combines an LLM of your choosing with persistent memory, a skill-creation loop, and roughly 70 built-in tools ranging from terminal access to browser automation. It was released in February 2026 and picked up traction fast, crossing 140,000 GitHub stars within about twelve weeks, largely because of that self-improving skill system nobody else shipped at the time.
Two architectural facts matter immediately for a sysadmin:
The agent runs continuously as a background process, not on-demand. That means it needs proper process supervision (systemd, not a screen session someone forgot about), log rotation, and restart policies, exactly like you’d treat any long-running daemon such as nginx or postgresql.
The agent executes arbitrary commands and tools on whatever “terminal backend” you point it at. Hermes supports six of these: local execution, Docker, SSH, Daytona, Modal, and Singularity. Running an autonomous agent with local terminal access directly on a production host, with no sandbox, is asking for trouble. This is the single most important decision in the entire setup, and we’ll come back to it in the security section.
Pre-Installation Checklist for Ubuntu 26.04 LTS
Don’t skip this part just because the installer looks simple. A five-minute checklist here saves an hour of debugging later.
Minimum System Requirements
For a lightweight setup using cloud model providers (OpenRouter, Anthropic, OpenAI, or the Nous Portal), a 2 GB RAM VPS is technically sufficient. In practice, treat 2 GB as the absolute floor and only acceptable if Hermes is the only meaningful workload on that box. If you plan to run local models through Ollama, budget at least 8 GB of RAM, and more if you’re loading anything beyond small quantized models. Disk-wise, allow at least 10 GB free beyond your base OS footprint; the installer pulls its own Python runtime, Node.js, and supporting tools, and memory/skill logs accumulate over time.
Access and Account Setup
You’ll need SSH access with sudo privileges, and ideally a dedicated non-root user rather than deploying everything under root. Ubuntu 26.04’s move to sudo-rs doesn’t change command syntax for everyday use, but if you’ve written automation scripts that parse legacy sudo’s stderr output for specific error strings, test those against the new implementation before relying on them in production.
You’ll also need an API key from your chosen model provider, or a plan to run fully local inference through Ollama if data residency or cost is a concern.
Update the Base System First
Never install a new service stack on top of a stale system. Run this before anything else:
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl git build-essential
On a freshly provisioned 26.04 image this usually pulls in kernel and security patches Canonical has shipped since the ISO was baked. Reboot afterward if the kernel was updated:
sudo reboot
Skipping the reboot after a kernel upgrade is a classic shortcut that comes back to bite you during troubleshooting three weeks later when you’re chasing a bug that was already fixed upstream.
Step-by-Step: Installing Hermes Agent
Step 1: Create a Dedicated Service User
Resist the urge to install Hermes under your personal admin account or, worse, root. A dedicated user with limited privileges is standard practice for any long-running service and keeps the agent’s file access scoped to its own home directory.
sudo adduser --disabled-password --gecos "" hermes
sudo su - hermes
Everything from this point until the systemd step happens as the hermes user.
Step 2: Run the Installer
Hermes ships a single-command installer that works identically across Linux distributions:
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash
An older mirror of the same script also works if the primary domain is unreachable from your network:
curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash
A quick professional habit worth mentioning: piping curl straight into bash is convenient, but on anything touching production, download and read the script first.
curl -fsSLO https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh
less install.sh
bash install.sh
This isn’t paranoia for its own sake. It takes thirty seconds and it’s the difference between knowingly running a script and blindly trusting a domain you don’t control the DNS for.
The installer sets up its own isolated Python 3.11 environment using uv, along with Node.js, ripgrep, and ffmpeg, and stores everything under ~/.hermes/ without requiring root access. That isolation is a genuinely good design decision; it means a broken system Python or a distro-managed package conflict won’t take Hermes down with it, and vice versa.
Step 3: Reload Your Shell
source ~/.bashrc
If you’re on zsh instead of bash, source the equivalent file:
source ~/.zshrc
Step 4: Confirm the Installation
hermes --version
If this returns a version string, the binary is on your PATH and the install completed. If it doesn’t, jump ahead to the troubleshooting section, this is the single most common failure point.
Step 5: Run the Setup Wizard
hermes setup
This interactive wizard walks through:
- Choosing a model provider: Nous Portal, OpenRouter, Anthropic, OpenAI, local Ollama, or any OpenAI-compatible endpoint
- Entering an API key (Nous Portal’s Quick Setup skips this using a device-code login flow instead)
- Selecting a default model
- Choosing which of the built-in tools to enable
- Picking a terminal backend (local, Docker, SSH, and others)
- Optionally connecting a messaging platform
For anything beyond a personal sandbox, choose Docker as the terminal backend here. We’ll set that up properly in the next section.
Step 6: First Interactive Run
hermes
This drops you into an interactive chat session so you can confirm the model responds and tools execute correctly before wiring anything into systemd. Test a low-stakes command, something like asking it to list files in a scratch directory, before trusting it with anything real.
Sandboxing with Docker: The Step Most Guides Skip
Here’s a scenario worth sitting with. You give Hermes local terminal access on your production web server because it’s faster to set up, and it works fine for weeks. Then, during a routine skill-creation cycle, the agent writes and executes a script that assumes it has write access to /var/www, because nothing told it otherwise. Nothing malicious happened; the agent just didn’t know the boundary existed. That’s the actual risk profile of autonomous agents with local execution, not science-fiction rogue AI, but ordinary permission scope creep.
Docker-based sandboxing solves this cleanly by giving the agent an isolated container to operate in in place of your host filesystem.
Install Docker:
sudo apt install -y docker.io docker-compose-plugin
sudo systemctl enable --now docker
sudo usermod -aG docker hermes
Log the hermes user out and back in, or apply the group change immediately without a full logout:
newgrp docker
Verify Docker is usable without sudo:
docker run hello-world
Then point Hermes at Docker as its terminal backend, either during hermes setup or by reconfiguring afterward:
hermes config set terminal-backend docker
Ubuntu 26.04 ships Docker Engine 29 in its repositories by default, which brings meaningfully better container startup times and improved cgroup v2 handling compared to what shipped alongside 24.04, something worth knowing if you’re benchmarking agent response latency.
Running Hermes as a systemd Service
An interactive hermes session dies the moment your SSH connection drops unless you’re running it inside tmux or screen, which is a fragile way to run anything you actually depend on. systemd is the correct tool here, and it’s the difference between “usually running” and “always running.”
Create the unit file:
sudo nano /etc/systemd/system/hermes.service
Paste the following, adjusting the path to match your installation:
[Unit]
Description=Hermes Agent Gateway
After=network-online.target docker.service
Wants=network-online.target
Requires=docker.service
[Service]
Type=simple
User=hermes
Group=hermes
WorkingDirectory=/home/hermes
ExecStart=/home/hermes/.local/bin/hermes gateway
Restart=on-failure
RestartSec=10
LimitNOFILE=65536
# Hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=/home/hermes/.hermes
PrivateTmp=true
[Install]
WantedBy=multi-user.target
Confirm the actual path to the hermes binary before saving, since installer versions have varied this slightly:
which hermes
Then enable and start the service:
sudo systemctl daemon-reload
sudo systemctl enable --now hermes
sudo systemctl status hermes
The hardening directives in that unit file (ProtectSystem=strict, ProtectHome=read-only, NoNewPrivileges=true) aren’t decoration. They tell the kernel to deny the Hermes process write access to most of the filesystem except the paths you explicitly allow, which is a meaningful second layer of defense on top of Docker sandboxing, not a replacement for it.
Watch the logs in real time the same way you’d watch any other systemd-managed service:
sudo journalctl -u hermes -f
Connecting a Messaging Gateway
If the goal is reaching Hermes from Telegram, Discord, Slack, WhatsApp, or Signal instead of a bare terminal, enable the gateway:
hermes gateway
This is what the systemd unit above actually launches as its ExecStart command, so once the service is running under systemd, the gateway comes up automatically on every boot without manual intervention.
Security Hardening Beyond the Basics
Firewall Configuration
Hermes doesn’t need any inbound ports open by default for the messaging-gateway model, since it’s making outbound connections to Telegram, Slack, or your model provider’s API rather than listening for inbound traffic. Lock the firewall down accordingly:
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw enable
sudo ufw status verbose
If you’re also running a local web dashboard or exposing an API for custom integrations, only open that specific port and restrict it to trusted IP ranges rather than opening it to the world.
API Key Storage
Never commit API keys to a git repo, and don’t rely on shell history for them either. Hermes stores provider credentials in its configuration under ~/.hermes/; lock that directory down:
chmod 700 ~/.hermes
chmod 600 ~/.hermes/config.yaml
Rotate keys periodically, and if you’re running Hermes for a client, use separate API keys per deployment so a compromised key on one server doesn’t expose usage across every environment you manage.
Keep the System Patched
Autonomous agents that execute code are a bigger blast radius than most services if the underlying OS has an unpatched privilege escalation bug. Set up unattended security upgrades:
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
Review Hermes updates too. New skill-execution features occasionally ship with expanded default permissions, so read release notes before blindly upgrading a production deployment.
Performance Tuning Notes
For CPU-bound workloads, particularly if you’re running local models via Ollama alongside Hermes, check whether the CPU governor is set to performance rather than powersave, since many cloud VPS images default to the latter:
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
sudo cpupower frequency-set -g performance
For memory, Hermes’s persistent memory store grows over time as it accumulates skills and conversation history. Monitor it:
du -sh ~/.hermes/memory
If it balloons unexpectedly, that’s usually a sign the agent is logging excessive tool output rather than summarizing it, worth checking in the config.
For disk I/O, if you’re running multiple isolated agents via Docker on the same host, put the Docker data root on a separate volume from your OS disk where possible, since container image layers and volumes can generate surprising I/O contention under concurrent agent workloads.
On the network side, if the agent is calling out to a cloud LLM provider on every message, latency is dominated by that round trip, not your local infrastructure. Running a local model through Ollama trades network latency for CPU/GPU load, which is the right tradeoff on data-sensitive workloads but the wrong one if raw response speed matters more.
Troubleshooting Common Installation Errors
hermes: command not found after installation. This almost always means your shell’s PATH wasn’t updated. Confirm the binary exists and manually add it:
ls -la ~/.local/bin/hermes
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
Installer fails partway through with a Python or uv error. This is typically a stale or conflicting Python installation interfering with the isolated environment the installer tries to build. Clear the partial install and retry:
rm -rf ~/.hermes ~/.local/share/hermes
bash install.sh
hermes setup hangs on the Nous Portal device-code login. This is a network egress issue nine times out of ten. Confirm outbound HTTPS isn’t blocked:
curl -I https://portal.nousresearch.com
If that times out, check your ufw outbound rules or, on a cloud VPS, the provider’s security group settings.
Docker terminal backend fails with a permission denied error. This means the group membership change from usermod -aG docker hasn’t taken effect in the current session. Log out completely and back in rather than relying on newgrp inside a script, since some shells don’t propagate the group change to subprocesses correctly.
systemd service starts then immediately exits. Check the exit code and logs together:
sudo systemctl status hermes
sudo journalctl -u hermes -n 50 --no-pager
The most common cause is an incorrect WorkingDirectory or ExecStart path in the unit file after an update changed where the binary lives. Re-run which hermes as the hermes user and update the unit file accordingly.
Agent runs but ignores messaging gateway input. Double check the gateway process is actually the one systemd launched and not a leftover manual session competing for the same webhook or polling connection. Kill any stray manual hermes gateway processes:
ps aux | grep hermes