---
title: "Self-host Hermes Agent"
description: "Run Nous Research's Hermes Agent on its own exe.dev VM: a private dashboard, Claude with no API key, scheduled jobs, and Telegram if you like."
url: https://exe-staging.dev/deploy/hermes-agent
category: "AI agents"
updated: 2026-10-17
---

# Self-host Hermes Agent

An agent that remembers you, on a computer that never sleeps.

- **Software:** Hermes Agent (https://hermes-agent.nousresearch.com)
- **Source:** https://github.com/NousResearch/hermes-agent
- **License:** MIT
- **Time:** 10 minutes
- **Example VM name:** `my-hermes-agent` (yours will differ; on the VM, `hostname` prints it)
- **Machine-readable:** https://exe-staging.dev/deploy/hermes-agent/manifest.json

## What you get

- A private dashboard at `https://<vm>.exe.xyz/` with browser chat, behind your exe.dev login and a generated Hermes password.
- Claude through exe.dev's LLM integration, with no API key to paste, and GPT and open models a `/model` away.
- A gateway and dashboard that stay on when you disconnect and start again after a reboot, so scheduled jobs keep running.
- Nightly backups of memory, skills, sessions, and settings in `~/backups/hermes`.
- If you gave a bot token, a Telegram bot that answers only your account.

Running on the VM:

- **Hermes gateway**: Background service for chat apps and scheduled jobs, managed by systemd, data in `~/.hermes`
- **Hermes dashboard**: Browser chat and settings, behind its own password, port 9119
- **nginx**: Private dashboard proxy, port 8000
- **Claude**: Connected through exe.dev's LLM integration

How it is reached:

- https://my-hermes-agent.exe.xyz/ (private): The Hermes dashboard, behind your exe.dev login and a Hermes password

## Deploy with Shelley

Open https://exe-staging.dev/new?prompt=TELEGRAM_BOT_TOKEN%3D%3Cfill-this-in%3E%0ATELEGRAM_USER_ID%3D%3Cfill-this-in%3E%0A%0ASet%20up%20Hermes%20Agent%20on%20this%20VM%20by%20following%20the%20exe.dev%20recipe%20at%20https%3A%2F%2Fexe-staging.dev%2Fdeploy%2Fhermes-agent.md%20from%20top%20to%20bottom.%0A%0AThe%20values%20at%20the%20top%20of%20this%20message%20are%20mine%3A%0A-%20TELEGRAM_BOT_TOKEN%3A%20optional%3B%20from%20%40BotFather%27s%20%60%2Fnewbot%60%20in%20Telegram.%20Leave%20it%20as%20is%20to%20skip%20Telegram%0A-%20TELEGRAM_USER_ID%3A%20optional%3B%20your%20numeric%20Telegram%20user%20ID%20%28message%20%40userinfobot%29%2C%20so%20the%20bot%20answers%20only%20you%0AAsk%20me%20for%20any%20that%20still%20say%20%3Cfill-this-in%3E%20before%20you%20need%20them.%0A%0AThe%20recipe%27s%20example%20VM%20name%20is%20my-hermes-agent.%20This%20VM%27s%20name%20is%20the%20output%20of%20%60hostname%60%3A%20use%20it%20wherever%20the%20recipe%20writes%20my-hermes-agent.%20Skip%20the%20step%20that%20creates%20the%20VM%3B%20you%20are%20on%20it.%0A%0AYou%20are%20done%20when%20all%20of%20these%20are%20true.%20Check%20each%20one%20yourself%3A%0A-%20A%20private%20dashboard%20at%20%60https%3A%2F%2F%3Cvm%3E.exe.xyz%2F%60%20with%20browser%20chat%2C%20behind%20your%20exe.dev%20login%20and%20a%20generated%20Hermes%20password.%0A-%20Claude%20through%20exe.dev%27s%20LLM%20integration%2C%20with%20no%20API%20key%20to%20paste%2C%20and%20GPT%20and%20open%20models%20a%20%60%2Fmodel%60%20away.%0A-%20A%20gateway%20and%20dashboard%20that%20stay%20on%20when%20you%20disconnect%20and%20start%20again%20after%20a%20reboot%2C%20so%20scheduled%20jobs%20keep%20running.%0A-%20Nightly%20backups%20of%20memory%2C%20skills%2C%20sessions%2C%20and%20settings%20in%20%60~%2Fbackups%2Fhermes%60.%0A-%20If%20you%20gave%20a%20bot%20token%2C%20a%20Telegram%20bot%20that%20answers%20only%20your%20account.%0A%0ARead%20the%20whole%20recipe%2C%20including%20the%20closed%20details.%20For%20initial%20setup%2C%0Afollow%20%22Install%20by%20hand%22%20first%2C%20skipping%20VM%20creation%20and%20SSH.%20The%0Aopening%20walkthrough%20is%20for%20the%20owner.%20Do%20not%20run%20the%20restore%20or%20update%0Ainstructions.%0ATelegram%20is%20optional.%20If%20TELEGRAM_BOT_TOKEN%20is%20empty%20or%20still%20says%0A%3Cfill-this-in%3E%2C%20skip%20Telegram%20and%20don%27t%20ask%20for%20it.%20Otherwise%20follow%0A%22Connect%20Telegram%20by%20hand%22%20with%20the%20supplied%20token%20and%20user%20ID%20instead%0Aof%20interactive%20reads.%20Ask%20for%20the%20user%20ID%20only%20if%20a%20token%20was%20given.%0AIf%20the%20gateway%20log%20says%20the%20token%20was%20rejected%2C%20unset%20both%20Telegram%0Asettings%2C%20restart%20the%20gateway%2C%20and%20tell%20the%20owner.%20Never%20echo%20the%20bot%0Atoken%20back.%0AKeep%20the%20VM%20private.%20Never%20run%20share%20set-public%2C%20bind%20the%20dashboard%20to%20a%0Anon-loopback%20address%2C%20or%20remove%20its%20password.%20On%20an%20existing%20VM%2C%20ask%0Abefore%20replacing%20configuration%20or%20a%20service%20on%20port%208000.%0AVerify%20a%20model%20reply%2C%20both%20services%20enabled%20and%20active%2C%20Linger%3Dyes%2C%0A%60auth_required%60%20true%20with%20%60basic%60%20through%20nginx%2C%20the%20backup%20timer%2C%20and%20a%0Atested%20archive.%20The%20Chat%20page%20is%20a%20terminal%20over%20a%20WebSocket%3A%20a%20sign-in%0Athrough%20nginx%20is%20check%20enough%3B%20don%27t%20script%20typing%20into%20it.%20Do%20not%0Areboot.%0AFinish%20with%20the%20dashboard%20URL%20and%20the%20Hermes%20username%20and%20password%20from%0A%22Open%20the%20dashboard%22%3B%20this%20conversation%20is%20private%20to%20the%20owner.%0A%0AFinish%20with%20the%20URLs%20I%20should%20open.%0A to create a VM whose agent, Shelley, follows this recipe. From a terminal:

```sh
curl -fsSL https://exe-staging.dev/deploy/hermes-agent/prompt.txt | ssh exe.dev new --prompt=/dev/stdin
```

Or follow the steps below by hand.

Hermes Agent, from Nous Research, is an open-source agent that remembers
what you tell it, writes itself new skills as it works, and runs jobs on a
schedule. It can run commands, browse the web, and read and write files.
Give it a computer of its own, one that stays on, and talk to it from your
browser or your phone.

Model usage is billed to your exe.dev account through the
[LLM integration](/docs/integrations-llm). There's no API key to find.

## Say hello

Open `https://my-hermes-agent.exe.xyz/` and sign in to exe.dev. Then sign
in to Hermes with the username and password from Shelley's last message,
and click **Chat**. Try:

> Remember that I drink my coffee black and I'm learning Portuguese.
> Then give me three five-minute practice ideas.

Start a **New chat** and ask what it knows about you. It remembers across
conversations, and gets better at the things you ask for often. (Hermes
also asks, once, whether to share usage data with Nous Research. Your
call.)

Lost the password? On your computer:

```bash
ssh my-hermes-agent.exe.xyz "grep -E '^HERMES_DASHBOARD_BASIC_AUTH_(USERNAME|PASSWORD)=' ~/.hermes/.env"
```

> [!WARNING]
> **Keep this VM private.** Hermes runs commands on the VM, with sudo.
> It asks before risky ones; leave that on. Don't make the dashboard
> public or keep unrelated secrets on this VM, and keep bot tokens to
> yourself.

## Put it on a schedule

The VM keeps UTC time, so first give Hermes yours. Ask Shelley, or on the
VM (with your own [time zone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)):

```bash
hermes config set timezone Europe/Lisbon
systemctl --user restart hermes-gateway hermes-dashboard
```

Reload the dashboard, and ask for something regular:

> Every weekday at 8:00, send me the five top Hacker News stories, one
> line each.

Jobs run inside the gateway, so they carry on while your laptop sleeps.
Pause or delete them on the dashboard's **Cron** page. Results of jobs
set up in the browser wait under **Sessions**, on the **Automation** tab;
jobs you ask for from Telegram report back there.

## Take it to Telegram

Happy in the browser? Skip this bit.

The quickest way: on the dashboard, open **Channels**, choose **Create with
QR** under Telegram, and scan the code with your phone. Hermes creates the
bot and lets only you use it.

Prefer your own bot? Message **@BotFather** (check the handle), send
`/newbot`, and follow the prompts. Message **@userinfobot** for your
numeric user ID. Give both to **Shelley** in your private conversation and
ask it to connect Telegram.

Message your bot to check it replies.

## Keep the memories

Memory, skills, conversations, and settings live in `~/.hermes`. Nightly
backups go to `~/backups/hermes`, and the newest 14 are kept. Copy them
**off the VM**, too. On your computer:

```bash
rsync -av my-hermes-agent.exe.xyz:backups/hermes/ ./hermes-backups/
```

Keep those copies private: they hold bot tokens and conversations.

## Setup and upkeep

No need to read on unless you're curious—or doing it yourself.

<details id="create-the-vm" data-manual-setup class="dp-details">
<summary>Install by hand</summary>

On your computer (pick another name if `my-hermes-agent` is taken):

```bash
ssh exe.dev new --name=my-hermes-agent
ssh my-hermes-agent.exe.xyz
```

All remaining installation commands run **on the VM**, as `exedev`.

### Install Hermes

The [official installer](https://hermes-agent.nousresearch.com/docs/getting-started/installation)
brings its own Python, Node.js, and a headless browser, and follows
stable releases. A server has no desktop for the computer-use driver to
control, so skip that:

```bash
curl -fsSL https://hermes-agent.nousresearch.com/install.sh |
  bash -s -- --non-interactive --skip-computer-use
export PATH="$HOME/.local/bin:$PATH"
hermes --version
```

Expect `Hermes Agent v0.22` or later. It takes a couple of minutes.

### Connect Claude through exe.dev

The API key below is a placeholder; exe.dev supplies the real credentials
outside the VM. The `/anthropic` path tells Hermes to speak Claude's own
API. The `exe-dev` provider reaches the integration's other models:

```bash
hermes config set model.provider anthropic
hermes config set model.base_url https://llm.int.exe.xyz/anthropic
hermes config set model.default claude-sonnet-5-5
hermes config set ANTHROPIC_API_KEY exe-llm-integration
hermes config set providers.exe-dev.api https://llm.int.exe.xyz/v1
hermes config set providers.exe-dev.api_key exe-llm-integration
hermes config set providers.exe-dev.transport chat_completions
hermes -z "Reply with exactly: pong"
```

The agent should answer `pong`.

### Start the gateway

The gateway connects chat apps and runs scheduled jobs. Lingering keeps
your services running after you log out:

```bash
sudo loginctl enable-linger "$USER"
hermes gateway install
loginctl show-user "$USER" -p Linger
systemctl --user is-enabled hermes-gateway
systemctl --user is-active hermes-gateway
```

Expect `Linger=yes`, `enabled`, and `active`. With no chat app yet, its
log says `No messaging platforms enabled`; that's fine.

### Run the dashboard

The dashboard listens only on the VM. Told its public address, it
insists on a sign-in, so generate a password; it lands in `~/.hermes/.env`,
which only you can read:

```bash
hermes config set dashboard.public_url "https://$(hostname).exe.xyz"
hermes config set HERMES_DASHBOARD_BASIC_AUTH_USERNAME hermes
grep -q '^HERMES_DASHBOARD_BASIC_AUTH_PASSWORD=' ~/.hermes/.env ||
  hermes config set HERMES_DASHBOARD_BASIC_AUTH_PASSWORD "$(openssl rand -hex 12)"
grep -q '^HERMES_DASHBOARD_BASIC_AUTH_SECRET=' ~/.hermes/.env ||
  hermes config set HERMES_DASHBOARD_BASIC_AUTH_SECRET "$(openssl rand -base64 32)"
```

The secret signs sign-in sessions, so they survive restarts. Now run the
dashboard as a service:

```bash
mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/hermes-dashboard.service <<'EOF'
[Unit]
Description=Hermes Agent dashboard
After=network-online.target
Wants=network-online.target

[Service]
ExecStart=%h/.local/bin/hermes dashboard --host 127.0.0.1 --port 9119 --no-open
WorkingDirectory=%h
Restart=always
RestartSec=10
RestartPreventExitStatus=78

[Install]
WantedBy=default.target
EOF
systemctl --user daemon-reload
systemctl --user enable --now hermes-dashboard
sleep 5
curl -fsS --retry 20 --retry-connrefused --retry-delay 3 \
  http://127.0.0.1:9119/api/status | jq '.auth_required, .auth_providers'
```

Expect `true` and `["basic"]`.

### Set up the dashboard proxy

The [exe.dev proxy](/docs/proxy) handles HTTPS and login. nginx passes
requests to the dashboard, keeping the browser's hostname. This replaces
the image's default site:

```bash
sudo tee /etc/nginx/sites-available/hermes-agent >/dev/null <<'EOF'
map $http_upgrade $hermes_connection {
    default upgrade;
    ""      close;
}
server {
    listen 8000 default_server;
    listen [::]:8000 default_server;
    server_name _;
    location / {
        proxy_pass http://127.0.0.1:9119;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $hermes_connection;
        proxy_set_header Host $host;
        # Overwrite, never append, client attribution.
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Forwarded-Host $host;
        proxy_read_timeout 1d;
        proxy_send_timeout 1d;
        proxy_buffering off;
        client_max_body_size 50m;
    }
}
EOF
sudo rm -f /etc/nginx/sites-enabled/default
sudo ln -sf /etc/nginx/sites-available/hermes-agent /etc/nginx/sites-enabled/hermes-agent
sudo nginx -t && sudo systemctl enable --now nginx && sudo systemctl reload nginx
curl -fsS -H "Host: $(hostname).exe.xyz" http://127.0.0.1:8000/api/status |
  jq '.auth_required, .auth_providers'
```

Expect `true` and `["basic"]` through nginx, too.

### Set up nightly backups

Hermes's own backup copies everything but the code and caches. Keep two
weeks of private archives:

```bash
mkdir -p ~/.config/systemd/user ~/backups/hermes
chmod 700 ~/backups ~/backups/hermes
cat > ~/.config/systemd/user/hermes-backup.service <<'EOF'
[Unit]
Description=Hermes Agent backup

[Service]
Type=oneshot
UMask=0077
ExecStart=%h/.local/bin/hermes backup --output %h/backups/hermes/ --keep 14
EOF
cat > ~/.config/systemd/user/hermes-backup.timer <<'EOF'
[Unit]
Description=Nightly Hermes Agent backup

[Timer]
OnCalendar=*-*-* 03:30:00
RandomizedDelaySec=30m
Persistent=true

[Install]
WantedBy=timers.target
EOF
systemctl --user daemon-reload
systemctl --user enable --now hermes-backup.timer
systemctl --user start hermes-backup.service
unzip -tq "$(ls -t ~/backups/hermes/hermes-backup-*.zip | head -1)"
systemctl --user list-timers hermes-backup.timer
```

Look for `No errors detected` and a scheduled next run.

### Open the dashboard

Print your Hermes sign-in:

```bash
grep -E '^HERMES_DASHBOARD_BASIC_AUTH_(USERNAME|PASSWORD)=' ~/.hermes/.env
```

Open `https://my-hermes-agent.exe.xyz/`, sign in to exe.dev, then to
Hermes, and try the chat.

</details>

<details id="connect-telegram" class="dp-details">
<summary>Connect Telegram by hand (optional)</summary>

On the VM, paste the token from @BotFather, then your numeric user ID
from @userinfobot—not your @username:

```bash
read -rsp "Telegram bot token: " token; echo
hermes config set TELEGRAM_BOT_TOKEN "$token"
unset token
read -rp "Your Telegram user ID: " telegram_id
hermes config set TELEGRAM_ALLOWED_USERS "$telegram_id"
hermes config set TELEGRAM_HOME_CHANNEL "$telegram_id"
unset telegram_id
systemctl --user restart hermes-gateway
sleep 20
systemctl --user is-active hermes-gateway
grep -i telegram ~/.hermes/logs/gateway.log | tail -n 3
```

Expect `active` and `✓ telegram connected`. Only the allowed user gets
answers; the home channel is where scheduled jobs report. Message your
bot to check. Groups need more settings; see Hermes's
[Telegram guide](https://hermes-agent.nousresearch.com/docs/user-guide/messaging/telegram).

</details>

<details id="back-up-and-restore" class="dp-details">
<summary>Back up and restore</summary>

On the VM, take a fresh backup:

```bash
(umask 077; hermes backup --output ~/backups/hermes/ --keep 14)
```

To restore, replace `BACKUP.zip` with your chosen archive's filename.
The import overwrites the matching files in `~/.hermes`, so stop Hermes
first:

```bash
systemctl --user stop hermes-gateway hermes-dashboard &&
hermes import --force ~/backups/hermes/BACKUP.zip &&
hermes config set dashboard.public_url "https://$(hostname).exe.xyz" &&
systemctl --user start hermes-gateway hermes-dashboard &&
hermes -z "What do you remember about me?"
```

The archive brings back its own dashboard password and bot tokens.
Moving to a new VM? Set it up first, copy the archive over with `scp`,
then restore. Stop the old VM's gateway: a Telegram bot answers only one.

</details>

<details id="update" class="dp-details">
<summary>Update</summary>

On the VM, back up, then update to the latest stable release. Hermes
restarts the gateway and dashboard itself:

```bash
(umask 077; hermes backup --output ~/backups/hermes/ --keep 14) &&
hermes update --yes &&
hermes --version &&
systemctl --user is-active hermes-gateway hermes-dashboard
```

Expect the new version and `active` twice. Reload the dashboard and try a
chat. Your settings and memory stay put.

</details>

<details id="troubleshooting" class="dp-details">
<summary>Something stuck?</summary>

Ask Shelley, or check on the VM:

```bash
systemctl --user is-active hermes-gateway hermes-dashboard
journalctl --user -u hermes-gateway -u hermes-dashboard -n 40 --no-pager
hermes -z "Reply with exactly: pong"
```

- **`hermes: command not found`?** Run `source ~/.bashrc`, or log in again.
- **502 from the dashboard?** It takes a few seconds to start; reload.
  Still there? Look for errors in the log above.
- **`Invalid Host header` or a sign-in loop?** The dashboard's public address
  must match the VM's; rerun the `dashboard.public_url` line
  [above](#run-the-dashboard) and restart `hermes-dashboard`.
- **Gateway stopped after adding Telegram?** A rejected bot token stops
  it, and scheduled jobs with it. Set a fresh token from @BotFather, or
  `hermes config unset TELEGRAM_BOT_TOKEN`, then restart `hermes-gateway`.
- **Bot ignores you?** `TELEGRAM_ALLOWED_USERS` must hold your numeric ID.
- **No model reply?** Check `hermes config get model` against the
  [settings above](#connect-claude-through-exedev) and your
  [LLM integration](/docs/integrations-llm).
- **`hermes doctor` says the Anthropic key is invalid?** It tests the
  placeholder against Anthropic directly. If `pong` comes back, ignore it,
  and don't let `hermes setup` replace the model settings.

</details>

## Frequently asked questions

### What does it cost?

Your [VM plan](https://exe.dev/pricing) plus model usage, billed through the [LLM integration](/docs/integrations-llm). Scheduled jobs use tokens each time they run; the dashboard's **Cron** page lists them.

### Can I use GPT, Kimi, or my own API key?

Yes. In a chat, `/model claude-opus-5-5` switches Claude models and `/model gpt-5.5 --provider exe-dev` reaches the integration's other models; add `--global` to keep the choice. To bring your own key or subscription, change the [LLM integration](/docs/integrations-llm), or run `hermes model` on the VM to add any provider Hermes supports.

### Can I use Discord, Slack, or WhatsApp instead of Telegram?

Yes. The dashboard's **Channels** page sets up Hermes's [chat apps](https://hermes-agent.nousresearch.com/docs/user-guide/messaging/). Telegram, Discord, and Slack connect outward, so they need no public address; keep each one's allowed-users list to your own IDs.

### Why two logins?

exe.dev's login keeps everyone else away from the VM. Hermes also refuses to serve its dashboard beyond the VM itself without its own sign-in, so you get a second lock. Your browser remembers both.

### I already use OpenClaw. Can I bring my memories?

Yes. Copy your `~/.openclaw` folder to the VM with `scp -r`. On the VM, preview with `hermes claw migrate --preset user-data --dry-run`, then import with `hermes claw migrate --preset user-data --overwrite`. Your persona, memories, and skills come across, and Hermes takes a backup first. Check a chat afterwards.

### Does it keep working when my laptop is closed?

Yes. Hermes runs on the VM, not your laptop. Scheduled jobs, chat apps, and the dashboard all carry on, and come back after a reboot.


## Related

- [Host OpenClaw](https://exe-staging.dev/deploy/openclaw.md): An AI sidekick with its own computer. Your laptop can take a nap.
- [Run Claude Code on a remote server](https://exe-staging.dev/deploy/claude-code.md): A computer for Claude. A breather for your laptop.
- [Running Agents](https://exe-staging.dev/deploy/agents.md): Use exe.dev VMs as a sandbox
- [Self-host n8n](https://exe-staging.dev/deploy/n8n.md): Connect your apps. Let the boring bits run themselves.
- [Host a Pi Durable agent](https://exe-staging.dev/deploy/pi-durable.md): An agent that picks up where it left off, even after kill -9.
- [Flue](https://exe-staging.dev/deploy/flue.md): Run Flue agentic apps on exe.dev
