Ha
Artificial Intelligence (AI) Azure

Hermes Agent on Ubuntu 24.04 on Azure User Guide

| Product: Hermes Agent on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and operation of Hermes Agent on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Hermes Agent is an open source, MIT licensed AI agent runtime. It holds a conversation with you, uses tools (a terminal, file editing, web search and fetch, code execution and many more) to get work done on the machine it runs on, remembers what it learns across sessions, writes its own reusable skills, runs scheduled jobs, and can be reached from a browser, a terminal, chat apps or any OpenAI-compatible client.

This image gives you the whole thing ready to use on a VM you control:

  • The web dashboard, served over HTTPS by nginx, with Hermes' own sign in page and a per-VM admin password. It manages configuration, API keys, sessions, skills, MCP servers, cron jobs, messaging channels and logs, and its Chat tab runs the full Hermes terminal interface in your browser
  • The messaging gateway, running as a service, which carries the OpenAI-compatible API server at https://<vm-ip>/v1 protected by a per-VM bearer key, and connects Telegram, Discord, Slack and other channels when you configure them
  • The hermes command for SSH sessions, running as the dedicated hermes service account

No password, key or certificate is baked into the image. First boot generates the dashboard password, the session signing secret, the API key and a TLS certificate uniquely on each VM, and the services refuse to start until it has done so. First boot then proves that an anonymous caller and a wrong password are refused before it marks the VM ready. Backed by 24/7 cloudimg support.

You bring the model. Hermes Agent works with the provider of your choice: OpenRouter, Anthropic, OpenAI, Nous Portal, or your own OpenAI-compatible endpoint (vLLM, llama.cpp, Ollama) serving a model with at least a 64K context window. No model ships in the image and nothing is sent anywhere until you connect one.

Hermes Agent is developed by Nous Research and is licensed under the MIT licence. This image is produced by cloudimg and is not affiliated with, endorsed by, or sponsored by Nous Research. It ships the free and open source software from an upstream release. The names are used here solely to identify the software this image contains.

The firstboot, dashboard and nginx services active, the gateway user service running, and the Hermes dashboard and API server listening on loopback only behind nginx on ports 80 and 443

What is included:

  • Hermes Agent 0.22.2, installed by the upstream installer from the release/0.22.2 branch at commit d923a5eb, with everything that installer would otherwise download at run time baked in: a pinned Python 3.14, a pinned Node.js 26, the locked Python environment, the terminal UI and the web dashboard build
  • A dedicated hermes service account with a locked password and no SSH keys. The agent's terminal tool runs as this account, not as root
  • nginx terminating HTTPS on 443 with a per-VM certificate, redirecting 80 to HTTPS
  • The dashboard on 127.0.0.1:9119 and the API server on 127.0.0.1:8642, reachable only through nginx
  • Unattended security upgrades left on for the operating system

Prerequisites

  • An Azure subscription with permission to create VMs
  • An account with a model provider (for example an OpenRouter, Anthropic or OpenAI API key), or your own OpenAI-compatible model server
  • A Standard_B4ms VM (4 vCPU, 16 GiB) or larger is recommended. Standard_B2ms works for light use with a hosted provider
  • Inbound TCP 443 (and 80 for the redirect) open only to the networks you connect from, plus 22 for SSH administration. The dashboard can run commands on this VM through the agent, so treat access to it like SSH access
  • An SSH key pair for administrative access

Step 1: Deploy from the Azure Portal

  1. In the Azure Portal, search the Marketplace for Hermes Agent | Support by cloudimg and select Create.
  2. Choose your subscription, resource group and region.
  3. Set the VM size to Standard_B4ms or larger.
  4. Under Administrator account, select SSH public key and supply your own key.
  5. Under Inbound port rules, allow HTTPS (443), HTTP (80) and SSH (22), then restrict all three to your own address ranges on the networking blade.
  6. Review and create.

Step 2: Deploy from the Azure CLI

az vm image terms accept --urn cloudimg1647283583153:hermes-agent-ubuntu-24-04:default:latest

az vm create \
  --resource-group my-resource-group \
  --name my-hermes-agent \
  --image cloudimg1647283583153:hermes-agent-ubuntu-24-04:default:latest \
  --size Standard_B4ms \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_rsa.pub \
  --public-ip-sku Standard

# Open HTTPS (and the HTTP redirect) to YOUR network only.
MY_CIDR="203.0.113.0/24"   # replace with your own range
az network nsg rule create \
  --resource-group my-resource-group \
  --nsg-name my-hermes-agentNSG \
  --name allow-https-from-office --priority 1010 \
  --source-address-prefixes "${MY_CIDR}" \
  --destination-port-ranges 80 443 --protocol Tcp --access Allow

Step 3: Connect to your VM

ssh azureuser@<vm-ip>

Step 4: Confirm the services are running

First boot takes about a minute. It generates this VM's secrets and certificate, starts the services and proves the sign in gate before it finishes.

# All three report "active". The firstboot unit is a oneshot that stays active (exited).
systemctl is-active hermes-agent-firstboot.service hermes-dashboard.service nginx.service

# The messaging gateway (which also serves the API) runs as a systemd user service
# of the hermes account, so it starts at boot without anyone logging in.
sudo hermes gateway status 2>&1 | grep -E 'running|linger'

# Hermes listens on loopback only; nginx is the only public listener.
sudo ss -lntp | grep -E ':(80|443|9119|8642)\b'

Expected output, with Hermes on 127.0.0.1 and nginx on 0.0.0.0:

active
active
active
✓ User gateway service is running
✓ Systemd linger is enabled (service survives logout)
LISTEN 0 511     0.0.0.0:80     0.0.0.0:*  users:(("nginx",...))
LISTEN 0 511     0.0.0.0:443    0.0.0.0:*  users:(("nginx",...))
LISTEN 0 2048  127.0.0.1:8642   0.0.0.0:*  users:(("hermes",...))
LISTEN 0 2048  127.0.0.1:9119   0.0.0.0:*  users:(("hermes",...))

Step 5: Read this VM's credentials

Everything in this file was generated on this VM at first boot.

sudo cat /root/hermes-agent-credentials.txt
# Hermes Agent - per-VM credentials generated on first boot (...).
# Keep this file private. Change the dashboard password with: sudo hermes-dashboard-password
DASHBOARD_URL=https://<vm-ip>/
DASHBOARD_USERNAME=admin
DASHBOARD_PASSWORD=<DASHBOARD_PASSWORD>
API_BASE_URL=https://<vm-ip>/v1
API_SERVER_KEY=<API_SERVER_KEY>

Step 6: Sign in to the dashboard

  1. Open DASHBOARD_URL from the credentials file in your browser. The certificate is self-signed and generated for this VM, so your browser will warn you the first time. Accept it for this address, or follow Step 12 to use your own domain and a trusted certificate.
  2. Sign in as admin with DASHBOARD_PASSWORD.

The Hermes Agent sign in page served over HTTPS by the appliance, with the admin username entered and the password masked

After signing in you land on the dashboard. The sidebar shows the gateway running, and the pages for chat, sessions, files, models, logs, cron, skills, plugins, MCP servers, channels, webhooks, pairing, profiles, configuration, keys and system administration.

The Hermes Agent dashboard after signing in as admin, with the full navigation and the gateway status reported as running

The first time you sign in, Hermes asks whether you want to share anonymous usage metrics with Nous Research. Collection and sending are off until you choose, and you can answer No thanks.

Step 7: Understand the access model

  • Dashboard. Hermes runs its web server on 127.0.0.1:9119 only. Hermes enables its own sign in gate when it is told the external address it is published at, so first boot declares https://<vm-ip> together with a per-VM admin password hash and session secret in /etc/hermes-agent/dashboard.env (readable by root only). Every page and API route except the public status endpoint needs a signed in session, and requests addressed to any other host name are rejected.
  • API. The OpenAI-compatible API server listens on 127.0.0.1:8642 and nginx publishes it at /v1/. Every request needs the per-VM bearer key, API_SERVER_KEY.
  • TLS. nginx serves both on port 443 with a certificate generated for this VM. Port 80 only redirects to HTTPS.
  • Brute force. Hermes limits password sign ins to ten a minute per client, and nginx applies its own limit to the sign in endpoint.

You can check all of it from the VM itself:

code() { curl -sk -o /dev/null -w '%{http_code}' "$@"; }
# Anonymous callers are refused (401), the public status says the gate is on.
curl -sk https://127.0.0.1/api/status | python3 -c 'import sys,json;d=json.load(sys.stdin);print("auth_required:",d["auth_required"],"providers:",d["auth_providers"])'
echo "anonymous /api/config : $(code https://127.0.0.1/api/config)"
# A wrong password is refused (401), this VM's password is accepted (200).
echo "wrong password        : $(code -H 'Content-Type: application/json' -d '{"provider":"basic","username":"admin","password":"wrong-password-123"}' https://127.0.0.1/auth/password-login)"
echo "per-VM password       : $(code -H 'Content-Type: application/json' -d '{"provider":"basic","username":"admin","password":"<DASHBOARD_PASSWORD>"}' https://127.0.0.1/auth/password-login)"
# The API refuses a missing key (401) and accepts this VM's key (200).
echo "API without key       : $(code https://127.0.0.1/v1/models)"
echo "API with key          : $(code -H 'Authorization: Bearer <API_SERVER_KEY>' https://127.0.0.1/v1/models)"

Anonymous dashboard requests and a wrong password refused with 401, this VM's password accepted with 200, a foreign host name rejected with 400, and the API refusing a missing or wrong key while accepting the per-VM key

Step 8: Connect a model provider

Hermes needs a model before it can answer. Until you add one, the chat and the API reply that Hermes is not connected to an AI provider yet.

From the dashboard. Open Keys, find your provider (for example OPENROUTER_API_KEY or ANTHROPIC_API_KEY), paste the key and save. Then open Models, choose Change next to the main model and pick a model from that provider. Restart the gateway from the sidebar so the API and messaging channels pick up the change.

The Keys page of the dashboard, where provider sign ins and model provider API keys are managed, stored in the agent's private environment file, with every provider shown as not yet connected

From SSH. sudo hermes model runs the interactive provider and model picker. To point Hermes at your own OpenAI-compatible server instead, set the endpoint directly:

sudo hermes config set model.provider custom
sudo hermes config set model.base_url http://10.0.0.5:8000/v1
sudo hermes config set model.default YOUR_MODEL_NAME
sudo hermes gateway restart

Keys you add are written to /var/lib/hermes/.hermes/.env, which only the hermes account can read.

Step 9: Chat with the agent

In the browser. The Chat tab runs the real Hermes terminal interface in the page, with a session list and model picker beside it. Sessions are saved and can be resumed from Sessions.

The dashboard Chat tab running the Hermes terminal interface in the browser, showing the agent banner, its tools and the workspace directory; before a provider is connected it explains how to add one

Over SSH. The hermes command runs as the hermes account whoever calls it, so sudo hermes opens the same agent with the same configuration, sessions and memory:

# Version and install details of the agent on this VM.
sudo hermes --version
Hermes Agent v0.22.2 (2026.9.24) · stable · local d923a5eb487a
Install directory: /var/lib/hermes/.hermes/hermes-agent
Install method: git
Python: 3.14.7

Start an interactive chat with sudo hermes, or ask a single question with sudo hermes -z "summarise the files in this directory". The agent's working directory is /var/lib/hermes/workspace.

The installed Hermes Agent version, the upstream branch, commit and MIT licence this image was built from, and the pinned Python, Node.js and dashboard build baked into the image

What the agent can do. By default the agent's tools act on this VM as the hermes account: it can read and write files in its home and workspace and run commands without root. Dangerous commands ask for approval. Review Config → approvals before you give it more access.

Step 10: Use the OpenAI-compatible API

Any OpenAI-compatible client can talk to the agent. Point it at API_BASE_URL with API_SERVER_KEY as the API key and hermes-agent as the model.

# List the model the API serves.
curl -skf https://127.0.0.1/v1/models -H "Authorization: Bearer <API_SERVER_KEY>"

The API server listing the hermes-agent model and the features it supports, including chat completions, streaming, the Responses API and runs

Once a provider is connected, send a chat completion from your workstation:

curl https://<vm-ip>/v1/chat/completions \
  --cacert hermes-agent.crt \
  -H "Authorization: Bearer YOUR_API_SERVER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"hermes-agent","messages":[{"role":"user","content":"What can you do?"}]}'

Copy the VM's certificate to your workstation from /etc/hermes-agent/tls/hermes-agent.crt for --cacert, or use your own certificate (Step 12). The API also offers streaming, the Responses API (/v1/responses) with server-side conversation state, and a runs API; see the upstream API server documentation.

Step 11: Connect messaging channels

Open Channels in the dashboard to connect Telegram, Discord, Slack, Matrix, Mattermost, WhatsApp, Signal, email and others. Each form asks for exactly what that platform needs (a bot token, an allow list) and links to the platform's setup guide. Save, enable the channel and choose Restart gateway. Approve new users under Pairing.

Step 12: Use your own domain and certificate

Hermes only answers requests addressed to the external URL it was given, which first boot set to https://<vm-ip>. To serve the dashboard under a DNS name:

  1. Create a DNS record for your name pointing at the VM's public IP.
  2. Declare the new URL (this restarts the dashboard):
sudo hermes-dashboard-url https://agent.example.com
  1. Replace the self-signed certificate with a trusted one, for example from Let's Encrypt with port 80 open to the internet while it issues:
sudo apt-get install -y certbot
sudo certbot certonly --webroot -w /var/www/html -d agent.example.com
sudo ln -sf /etc/letsencrypt/live/agent.example.com/fullchain.pem /etc/hermes-agent/tls/hermes-agent.crt
sudo ln -sf /etc/letsencrypt/live/agent.example.com/privkey.pem /etc/hermes-agent/tls/hermes-agent.key
sudo systemctl reload nginx

Step 13: Day-2 operations

Change the dashboard password. The new password is prompted for, never typed on the command line, and only its hash is stored:

sudo hermes-dashboard-password

Service control.

# The dashboard and nginx are system services.
sudo systemctl status hermes-dashboard.service --no-pager | head -5
# The gateway (API server and channels) is restarted through hermes itself.
sudo hermes gateway status 2>&1 | grep -E 'running|stopped'

Logs. The Logs page shows the agent, gateway and error logs, or read them over SSH:

sudo ls /var/lib/hermes/.hermes/logs/
sudo journalctl -u hermes-dashboard.service -n 20 --no-pager

Updates. The operating system patches itself through unattended upgrades. Hermes Agent updates from the dashboard (System → Update now) or with sudo hermes update, which also restarts the gateway.

Backups. Everything the agent owns (configuration, keys, sessions, memories, skills) lives under /var/lib/hermes/.hermes. sudo hermes backup writes an archive you can copy off the VM, and Azure disk snapshots capture the whole VM.

Files and locations.

Path Purpose
/root/hermes-agent-credentials.txt This VM's dashboard password and API key
/etc/hermes-agent/dashboard.env Dashboard URL, admin password hash and session secret (root only)
/etc/hermes-agent/tls/ The VM's TLS certificate and key
/var/lib/hermes/.hermes/config.yaml Hermes configuration
/var/lib/hermes/.hermes/.env Provider keys and API server settings
/var/lib/hermes/workspace The agent's default working directory
/etc/nginx/sites-available/hermes-agent The HTTPS front door

Troubleshooting

  • The browser shows "400 Bad Request" or "Invalid host". You reached the VM by a name or address other than the one Hermes was told about. Use DASHBOARD_URL, or declare the new one with sudo hermes-dashboard-url (Step 12).
  • "Too many login attempts". Wait a minute; sign ins are limited per client.
  • Chat or API replies that Hermes is not connected to an AI provider. Add a provider key and pick a model (Step 8), then restart the gateway.
  • A local model is rejected for its context window. Hermes needs a model served with at least a 64K context. CPU-only VMs are too slow for a useful local model; use a hosted provider or a GPU server.
  • Nothing answers on 443. Check systemctl status hermes-agent-firstboot.service and /var/log/hermes-agent-firstboot.log.

Support

cloudimg provides 24/7 support for this image. Contact support@cloudimg.co.uk with your VM's region and the output of sudo hermes --version. For Hermes Agent itself, see the upstream documentation at hermes-agent.nousresearch.com.