Hermes Agent Installation Guide: Secure Deployment with Telegram Gateway, Dashboard, Nginx, and Caddy

This guide covers a production deployment of Hermes Agent on a Linux server, with security and operations in mind.

We will install Hermes Agent natively, run it under a dedicated non-root user, configure Telegram Gateway as a managed service, enable the local API and dashboard, and place public access behind Nginx or Caddy. The guide also includes operational checks, backup notes, troubleshooting steps, and a final checklist before going live.

The important part is not just whether Hermes Agent starts. A production setup should keep backend ports on localhost, protect dashboard access, keep secrets out of Git and proxy configs, and verify each stage before moving to the next.

Deployment assumptions

This workflow assumes:

  • Hermes Agent is installed natively on a Linux VPS or server.
  • Hermes runs under a dedicated non-root Linux user.
  • The Hermes API binds to 127.0.0.1 by default.
  • Public access goes through Nginx, Caddy, VPN, Cloudflare Access, or Cloudflare Tunnel.
  • Telegram Gateway runs as a managed service.
  • Secrets are stored in ~/.hermes/.env, not in Git, documentation, or reverse proxy config files.
  • The dashboard or Workspace UI is protected with additional authentication.

1. System Requirements

1.1 Minimum Server Specification

For light to medium usage:

  • OS: Ubuntu Server 22.04/24.04 LTS or Debian 12
  • CPU: 2 vCPU minimum
  • RAM: 2 GB minimum, 4 GB+ recommended
  • Disk: 20 GB minimum, 40 GB+ recommended
  • Network:
    • Public IP, VPN access, or Cloudflare Tunnel
    • Domain/subdomain if HTTPS reverse proxy is required
  • User:
    • Non-root user with sudo access
    • Do not run Hermes daily workloads as root

1.2 Required Software

Base packages:

  • curl
  • git
  • python3
  • python3-venv
  • python3-pip
  • pipx or a Python virtual environment
  • systemd
  • nginx or caddy
  • ufw or another firewall
  • fail2ban for basic SSH hardening

Optional packages:

  • nodejs and npm if running a separate frontend/dashboard stack
  • docker and Docker Compose if using containerized UI components
  • cloudflared if using Cloudflare Tunnel

1.3 External Accounts and API Access

You need at least one supported LLM provider, for example:

  • OpenRouter
  • Anthropic
  • OpenAI
  • Gemini
  • DeepSeek
  • Kimi/Moonshot
  • Blackbox.ai or another OpenAI-compatible provider
  • Any other provider supported by Hermes Agent

For Telegram Gateway:

  • Telegram Bot Token from @BotFather
  • Telegram user/chat authorization through Hermes pairing flow

2. System Preparation

2.1 Create a Dedicated Linux User

Create a dedicated user, for example hermes:

sudo adduser hermes
sudo usermod -aG sudo hermes

Switch to the user:

su - hermes

Or log in directly via SSH as the hermes user.


2.2 Update System Packages

sudo apt update
sudo apt upgrade -y

Install base dependencies:

sudo apt install -y \
  curl git ca-certificates gnupg lsb-release \
  python3 python3-venv python3-pip pipx \
  ufw fail2ban

Enable pipx path support:

pipx ensurepath

Log out and log back in if the shell path does not update immediately.


2.3 Basic Firewall Hardening

For a public server:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

If the server is reachable only through VPN/private access, restrict ports 80/443 to trusted IP ranges where possible.


2.4 SSH Hardening

Recommended SSH posture:

  • Use SSH keys instead of password login.
  • Disable root login.
  • Disable password authentication if all admins have working SSH keys.
  • Enable fail2ban.
  • Consider changing the SSH port only if it fits your operational policy.

Edit SSH config:

sudo nano /etc/ssh/sshd_config

Recommended values:

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes

Restart SSH:

sudo systemctl restart ssh

Keep one active SSH session open while testing the new login settings.


2.5 Directory and Permission Planning

Default Hermes home directory:

/home/hermes/.hermes/

Important paths:

~/.hermes/config.yaml
~/.hermes/.env
~/.hermes/logs/
~/.hermes/sessions/
~/.hermes/skills/
~/.hermes/plugins/
~/.hermes/auth.json

Recommended permissions:

chmod 700 ~/.hermes
chmod 600 ~/.hermes/.env
chmod 600 ~/.hermes/config.yaml

3. Step-by-Step Installation

3.1 Install Hermes Agent

Install using the official installer:

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

Reload the shell:

exec $SHELL -l

Verify installation:

hermes --version
hermes doctor

3.2 Run Initial Setup Wizard

hermes setup

Configure the following areas:

  • Model provider
  • API key or provider authentication
  • Terminal backend
  • Gateway
  • Tools
  • Agent behavior

You can also use the model picker directly:

hermes model

3.3 Configure Model Provider

Security principles:

  • Store API keys in ~/.hermes/.env.
  • Do not store secrets in documentation, Git, Nginx config, or Caddy config.
  • Use a stable model for agentic workflows.
  • Test low-cost or free models before using them for heavy tool-calling workloads.

Find the environment file path:

hermes config env-path

Edit the environment file:

nano ~/.hermes/.env

Example:

OPENROUTER_API_KEY=replace_with_your_key

Select provider/model:

hermes model

Validate the backend:

hermes chat -q "Respond with exactly OK." --quiet

Expected output:

OK

3.4 Recommended Security-Related Hermes Config

Initial secure defaults:

hermes config set security.redact_secrets true
hermes config set privacy.redact_pii true
hermes config set approvals.mode manual

Notes:

  • security.redact_secrets true helps mask API keys and tokens in tool output.
  • privacy.redact_pii true helps redact user identifiers in gateway contexts.
  • approvals.mode manual is safest for risky commands.
  • Avoid --yolo on production servers.

Balanced mode if you want more convenience:

hermes config set approvals.mode smart

After important config changes, restart the gateway or start a new Hermes session.


4. Minimum Telegram Gateway Configuration

4.1 Create a Telegram Bot

In Telegram:

  1. Open @BotFather.
  2. Run:
/newbot
  1. Follow the prompts.
  2. Save the bot token securely.

Example token format:

123456789:ABCDEF_xxxxx

Do not share this token.


4.2 Configure Telegram Gateway

Run the gateway setup wizard:

hermes gateway setup

Choose Telegram and enter the bot token.

Alternatively, store the token in ~/.hermes/.env:

TELEGRAM_BOT_TOKEN=replace_with_your_telegram_bot_token

4.3 Install Gateway as a Service

Install the gateway service:

hermes gateway install

Start the gateway:

hermes gateway start

Check gateway status:

hermes gateway status

If installed as a system service:

systemctl status hermes-gateway.service --no-pager

If installed as a user service:

systemctl --user status hermes-gateway.service --no-pager

4.4 First Telegram Authorization

Send a message to your Telegram bot.

Hermes usually requires pairing/approval before a new chat can control the agent. On the server, run:

hermes pairing list
hermes pairing approve <request_id>

After approval, test from Telegram:

/status
/help

4.5 Telegram Security Best Practices

Recommended practices:

  • Never expose the bot token.
  • Use pairing/approval; do not allow all users by default.
  • Limit Telegram toolsets if the bot is used in shared groups.
  • Do not enable destructive auto-approval.
  • Enable secret redaction.
  • Review logs after setup.
  • Run Hermes under a dedicated non-root user.

Useful checks:

hermes status --all
hermes tools list
tail -n 100 ~/.hermes/logs/gateway.log

5. Post-Install: API, Dashboard, and Workspace

Hermes components should be understood separately:

  1. Hermes Agent CLI: local command-line agent.
  2. Hermes Gateway/API: backend service for platforms and OpenAI-compatible access.
  3. Telegram Gateway: messaging adapter.
  4. Dashboard/Workspace UI: web UI, monitoring, or client layer.

Keep these layers separate when troubleshooting.


5.1 Enable Local API Server

Enable API server for local backend access, reverse proxy, Workspace, or Open WebUI:

hermes config set API_SERVER_ENABLED true

Generate a strong API key:

openssl rand -hex 32

Set the API key:

hermes config set API_SERVER_KEY "<generated_key>"

Recommended local-only binding:

hermes config set API_SERVER_HOST 127.0.0.1

Do not bind directly to 0.0.0.0 unless you have strong authentication, HTTPS, and a clear reason.

Restart the gateway:

hermes gateway restart

Verify health:

curl -fsS http://127.0.0.1:8642/health

Example expected response:

{"status":"ok","platform":"hermes-agent"}

Verify the models endpoint:

curl -fsS \
  -H "Authorization: Bearer <API_SERVER_KEY>" \
  http://127.0.0.1:8642/v1/models

5.2 Running the Dashboard

If the dashboard command is available in your Hermes installation:

hermes dashboard

Recommended dashboard deployment design:

  • Bind dashboard to 127.0.0.1.
  • Expose it through Nginx, Caddy, VPN, or Cloudflare Access.
  • Add Basic Auth, SSO, VPN-only access, or Cloudflare Access.
  • Do not expose the dashboard publicly without authentication.

Typical local dashboard target:

127.0.0.1:9119

Health check:

curl -fsS http://127.0.0.1:9119/api/status

5.3 Optional Workspace or Open WebUI

If using Workspace or Open WebUI:

  • Treat the UI as a client.
  • Keep Hermes Gateway/API as the backend agent service.
  • Use internal API URL:
http://127.0.0.1:8642/v1
  • Use the same value as API_SERVER_KEY for the client API token/key.
  • Do not expose Hermes API directly without HTTPS and authentication.

For Docker-based UI that must access the host:

http://host.docker.internal:8642/v1

On Linux Docker, you may need:

--add-host=host.docker.internal:host-gateway

5.4 Post-Install Verification Checklist

Run:

hermes doctor
hermes config check
hermes status --all
hermes chat -q "Respond with exactly OK." --quiet
curl -fsS http://127.0.0.1:8642/health

If gateway runs under systemd:

systemctl status hermes-gateway.service --no-pager
journalctl -u hermes-gateway.service --since "10 minutes ago" --no-pager

Port check:

sudo ss -tlnp | grep -E ':(8642|9119|3000|3001)\b'

Expected secure posture:

127.0.0.1:8642    Hermes API
127.0.0.1:9119    Dashboard
0.0.0.0:80/443    Nginx or Caddy only

6. Reverse Proxy Deployment Using Nginx or Caddy

6.1 Recommended Domain Layout

Example:

agent.example.com       -> Hermes API, optional and protected
dashboard.example.com   -> Hermes Dashboard or Workspace UI

Safer option:

dashboard.example.com   -> UI only, protected
agent.example.com       -> not public; VPN/private access only

Best practices:

  • Do not expose /v1 publicly unless required.
  • If the API is exposed, require HTTPS, bearer token, rate limiting, and IP allowlist where possible.
  • Dashboard must have additional authentication.
  • Use Cloudflare Access, VPN, Basic Auth, or SSO.

Option A: Nginx Reverse Proxy

6.2 Install Nginx and Certbot

sudo apt install -y nginx certbot python3-certbot-nginx

Allow firewall access:

sudo ufw allow 'Nginx Full'

6.3 Nginx Reverse Proxy for Dashboard

Create config file:

sudo nano /etc/nginx/sites-available/hermes-dashboard.conf

Example:

server {
    listen 80;
    server_name dashboard.example.com;

    location / {
        proxy_pass http://127.0.0.1:9119;
        proxy_http_version 1.1;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Enable the site:

sudo ln -s /etc/nginx/sites-available/hermes-dashboard.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Enable HTTPS:

sudo certbot --nginx -d dashboard.example.com

6.4 Add Basic Auth for Dashboard in Nginx

Install password utility:

sudo apt install -y apache2-utils

Create password file:

sudo htpasswd -c /etc/nginx/.htpasswd-hermes-dashboard wawan

Update the location / block:

location / {
    auth_basic "Restricted Hermes Dashboard";
    auth_basic_user_file /etc/nginx/.htpasswd-hermes-dashboard;

    proxy_pass http://127.0.0.1:9119;
    proxy_http_version 1.1;

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

Validate and reload:

sudo nginx -t
sudo systemctl reload nginx

6.5 Optional Nginx Reverse Proxy for Hermes API

If the API must be published, use a separate protected subdomain:

agent.example.com

Example:

server {
    listen 80;
    server_name agent.example.com;

    location / {
        proxy_pass http://127.0.0.1:8642;
        proxy_http_version 1.1;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        client_max_body_size 20M;
    }
}

Enable HTTPS:

sudo certbot --nginx -d agent.example.com

Recommended additional protection:

  • IP allowlist
  • Basic Auth if compatible with the client
  • Rate limiting
  • Cloudflare Access or VPN
  • Keep API_SERVER_KEY enabled

Example IP allowlist:

allow 203.0.113.10;
deny all;

Option B: Caddy Reverse Proxy

6.6 Install Caddy

Debian/Ubuntu:

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
  | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
  | sudo tee /etc/apt/sources.list.d/caddy-stable.list

sudo apt update
sudo apt install -y caddy

6.7 Caddy Reverse Proxy for Dashboard

Edit Caddyfile:

sudo nano /etc/caddy/Caddyfile

Example:

dashboard.example.com {
    encode gzip

    basicauth {
        wawan <hashed_password>
    }

    reverse_proxy 127.0.0.1:9119
}

Generate password hash:

caddy hash-password

Validate and reload:

sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy

Caddy automatically handles HTTPS through Let's Encrypt when DNS is correct.


6.8 Optional Caddy Reverse Proxy for Hermes API

Basic API reverse proxy:

agent.example.com {
    encode gzip

    reverse_proxy 127.0.0.1:8642
}

Safer API reverse proxy with IP restriction:

agent.example.com {
    encode gzip

    @allowed remote_ip 203.0.113.10
    handle @allowed {
        reverse_proxy 127.0.0.1:8642
    }

    respond "Forbidden" 403
}

Or with Basic Auth if compatible with your client:

agent.example.com {
    encode gzip

    basicauth {
        wawan <hashed_password>
    }

    reverse_proxy 127.0.0.1:8642
}

7. Security Best Practices Summary

7.1 Binding and Exposure

Recommended:

Hermes API       127.0.0.1:8642
Dashboard        127.0.0.1:9119
Reverse Proxy    0.0.0.0:80/443

Avoid:

Hermes API       0.0.0.0:8642 without strong auth
Dashboard        public without auth
Running Hermes as root
Putting API keys in docs, Git, Nginx config, or Caddy config

7.2 Secrets Management

Rules:

  • API keys go to ~/.hermes/.env.
  • config.yaml should store non-secret config where possible.
  • Restrict file permissions:
chmod 700 ~/.hermes
chmod 600 ~/.hermes/.env
chmod 600 ~/.hermes/config.yaml
  • Never paste .env into support chats or GitHub issues.
  • Enable redaction:
hermes config set security.redact_secrets true

7.3 Gateway Safety

Recommended:

hermes config set approvals.mode manual
hermes config set privacy.redact_pii true

Optional balanced mode:

hermes config set approvals.mode smart

Avoid in production:

hermes --yolo
hermes config set approvals.mode off

7.4 Reverse Proxy Security

Minimum requirements:

  • HTTPS
  • Strong password/authentication for dashboard
  • API key for Hermes API
  • No direct public access to internal ports
  • Logs enabled
  • Rate limiting if API is exposed

Better options:

  • Cloudflare Access
  • VPN-only access
  • IP allowlist
  • Separate subdomains
  • Separate Linux user
  • Automated backup for ~/.hermes

8. Backup and Restore

8.1 Important Paths to Back Up

Back up:

~/.hermes/config.yaml
~/.hermes/.env
~/.hermes/auth.json
~/.hermes/skills/
~/.hermes/plugins/
~/.hermes/sessions/
~/.hermes/memory/
~/.hermes/cron/

Simple backup command:

tar -czf hermes-backup-$(date +%F).tar.gz ~/.hermes

Important: this backup contains secrets.

Recommended backup controls:

  • Encrypt backups.
  • Store backups off-server.
  • Restrict access.
  • Rotate old backups.
  • Test restore regularly.

8.2 Restore Procedure

On a new server:

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

Restore the backup:

cd ~
tar -xzf hermes-backup-YYYY-MM-DD.tar.gz
sudo chown -R $(whoami):$(whoami) ~/.hermes
chmod 700 ~/.hermes
chmod 600 ~/.hermes/.env ~/.hermes/config.yaml

Verify:

hermes doctor
hermes status --all
hermes skills list
hermes cron list
hermes chat -q "Respond with exactly OK." --quiet

Restart gateway if needed:

hermes gateway restart

9. Operations and Maintenance

9.1 Daily Checks

hermes status --all
hermes doctor
systemctl status hermes-gateway.service --no-pager

9.2 Logs

tail -n 100 ~/.hermes/logs/gateway.log
journalctl -u hermes-gateway.service --since "1 hour ago" --no-pager

9.3 Restart Gateway

hermes gateway restart

Or with systemd:

sudo systemctl restart hermes-gateway.service

9.4 Update Hermes

hermes update
hermes doctor
hermes chat -q "Respond with exactly OK." --quiet

10. Troubleshooting

10.1 Gateway Does Not Start

Check status and logs:

hermes gateway status
tail -n 100 ~/.hermes/logs/gateway.log
journalctl -u hermes-gateway.service --since "30 minutes ago" --no-pager

Common causes:

  • Missing API key or provider credential
  • Invalid Telegram bot token
  • Permission issue in ~/.hermes
  • Port already in use
  • Broken config after manual edit

Run:

hermes doctor
hermes config check

10.2 Telegram Bot Does Not Reply

Check:

hermes status --all
hermes gateway status
hermes pairing list
tail -n 100 ~/.hermes/logs/gateway.log

Possible causes:

  • Chat/user has not been approved.
  • Bot token is wrong.
  • Gateway service is stopped.
  • Telegram platform is not enabled.
  • Model provider is failing.

Run a backend smoke test:

hermes chat -q "Respond with exactly OK." --quiet

10.3 Reverse Proxy Shows 502 Bad Gateway

Check local target first:

curl -fsS http://127.0.0.1:8642/health
curl -fsS http://127.0.0.1:9119/api/status

Check ports:

sudo ss -tlnp | grep -E ':(8642|9119|3000|3001|80|443)\b'

Check reverse proxy config:

sudo nginx -t
sudo systemctl status nginx --no-pager

For Caddy:

sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl status caddy --no-pager

10.4 Model Provider Fails

Check config and credentials:

hermes config check
hermes doctor
hermes model
hermes chat -q "Respond with exactly OK." --quiet

Check .env permissions:

ls -la ~/.hermes/.env ~/.hermes/config.yaml

Common causes:

  • Wrong API key
  • Wrong model ID
  • Provider quota exhausted
  • Provider endpoint not OpenAI-compatible
  • Gateway not restarted after config changes

10.5 Config Changes Do Not Apply

After changing config:

hermes gateway restart

Or restart systemd service:

sudo systemctl restart hermes-gateway.service

For CLI sessions, exit and start a new session.

For Telegram, you can also use:

/restart

if the gateway slash command is available and authorized.


Previous Post