Hermes Agent on Ubuntu 24.04 on Azure User Guide
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>/v1protected by a per-VM bearer key, and connects Telegram, Discord, Slack and other channels when you configure them - The
hermescommand for SSH sessions, running as the dedicatedhermesservice 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.

What is included:
- Hermes Agent 0.22.2, installed by the upstream installer from the
release/0.22.2branch at commitd923a5eb, 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
hermesservice 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
443with a per-VM certificate, redirecting80to HTTPS - The dashboard on
127.0.0.1:9119and the API server on127.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_B4msVM (4 vCPU, 16 GiB) or larger is recommended.Standard_B2msworks for light use with a hosted provider - Inbound TCP
443(and80for the redirect) open only to the networks you connect from, plus22for 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
- In the Azure Portal, search the Marketplace for Hermes Agent | Support by cloudimg and select Create.
- Choose your subscription, resource group and region.
- Set the VM size to Standard_B4ms or larger.
- Under Administrator account, select SSH public key and supply your own key.
- 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.
- 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
- Open
DASHBOARD_URLfrom 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. - Sign in as
adminwithDASHBOARD_PASSWORD.

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 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:9119only. Hermes enables its own sign in gate when it is told the external address it is published at, so first boot declareshttps://<vm-ip>together with a per-VMadminpassword 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:8642and nginx publishes it at/v1/. Every request needs the per-VM bearer key,API_SERVER_KEY. - TLS. nginx serves both on port
443with a certificate generated for this VM. Port80only 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)"

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.

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.

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.

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>"

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:
- Create a DNS record for your name pointing at the VM's public IP.
- Declare the new URL (this restarts the dashboard):
sudo hermes-dashboard-url https://agent.example.com
- 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 withsudo 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.serviceand/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.