Hermes Agent bisa jalan di VPS pribadi — bukan sekadar chatbot, tapi orchestration layer yang menerima instruksi dari Telegram, memanggil tool, menyimpan output ke Obsidian vault, dan mendelegasikan eksekusi ke n8n. Dengan 9router sebagai LLM router di tengahnya, Anda bisa ganti model kapan saja tanpa menyentuh konfigurasi Hermes. Panduan ini dari nol sampai jalan.

Arsitektur Stack Sebelum Mulai

Penting untuk paham bagaimana komponen berinteraksi sebelum install satu per satu:

Internet
    |
  Caddy (reverse proxy + SSL)
    |--- hermes.domain.com → Hermes Dashboard
    |--- 9router.domain.com → 9router Dashboard
    |--- n8n.domain.com → n8n Automation

Hermes (container)
    |--- Telegram Bot (gateway input)
    |--- Calls ke 9router untuk LLM routing
    |--- Skills dari Obsidian vault
    |--- MCP n8n (tool bridge)

9router (container)
    |--- Routing ke OpenRouter / model lain
    |--- Logging semua API call

Obsidian Vault (folder di VPS)
    |--- Dibaca Hermes sebagai skill source
    |--- Ditulis Hermes untuk output/memory

Semua container jalan di satu Docker internal network (apps_internal). Tidak ada port yang di-publish langsung ke internet kecuali Caddy di port 80 dan 443. Caddy menjangkau Hermes via IP container internal — bukan lewat port yang di-expose ke host.

Prasyarat

VPS Ubuntu 24.04 LTS dengan minimal 2 vCPU dan 4 GB RAM. Di Sumopod, spesifikasi ini ada di kisaran Rp 150–250 ribu per bulan. Untuk penggunaan satu pengguna tanpa workflow berat, 2 GB RAM bisa jalan meski lebih terbatas.

Yang Anda butuhkan sebelum mulai:

  • Domain dengan akses DNS panel (Cloudflare, name.com, dll.)
  • Akun OpenRouter untuk API key LLM
  • Bot Telegram — buat via @BotFather, simpan tokennya
  • Telegram User ID — minta ke @userinfobot

Firewall Sumopod: di panel Sumopod, pastikan hanya port 22, 80, dan 443 yang diizinkan. Hapus rule "Allow All" jika ada. Docker bypass UFW dengan menulis langsung ke iptables — firewall cloud provider adalah satu-satunya lapisan perlindungan yang reliable untuk port Docker.

Instalasi: Langkah per Langkah

Langkah 1 — Update sistem dan install dependencies

ssh ubuntu@IP_VPS_ANDA
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget git unzip htop jq ca-certificates gnupg lsb-release ufw fail2ban tmux

Langkah 2 — Setup firewall UFW

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

Langkah 3 — Install Docker

sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker ubuntu
newgrp docker

Langkah 4 — Buat struktur folder

mkdir -p ~/apps/{caddy,n8n,9router,hermes,obsidian}
mkdir -p ~/apps/caddy/{data,config}
mkdir -p ~/apps/n8n/data
mkdir -p ~/apps/9router/data
mkdir -p ~/apps/hermes/data
mkdir -p ~/apps/obsidian/vault

Langkah 5 — docker-compose.yml untuk Caddy, n8n, dan 9router

Hermes dijalankan via docker run terpisah karena butuh flag khusus.

nano ~/apps/docker-compose.yml
services:
  caddy:
    image: caddy:2
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./caddy/Caddyfile:/etc/caddy/Caddyfile
      - ./caddy/data:/data
      - ./caddy/config:/config
    networks:
      - internal

  n8n:
    image: n8nio/n8n:latest
    container_name: n8n
    restart: unless-stopped
    expose:
      - "5678"
    environment:
      - N8N_HOST=n8n.domain-anda.com
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - WEBHOOK_URL=https://n8n.domain-anda.com/
      - TZ=Asia/Jakarta
    volumes:
      - ./n8n/data:/home/node/.n8n
    networks:
      - internal

  9router:
    image: decolua/9router:latest
    container_name: router9
    restart: unless-stopped
    expose:
      - "20128"
    env_file:
      - ./9router/.env
    volumes:
      - ./9router/data:/app/data
    networks:
      - internal

networks:
  internal:
    name: apps_internal
    driver: bridge

Langkah 6 — Caddyfile

nano ~/apps/caddy/Caddyfile
n8n.domain-anda.com {
    reverse_proxy n8n:5678
}

9router.domain-anda.com {
    reverse_proxy router9:20128
}

hermes.domain-anda.com {
    reverse_proxy :
}

IP dan port container Hermes diisi setelah container jalan di langkah berikutnya.

Langkah 7 — Konfigurasi 9router

nano ~/apps/9router/.env
TZ=Asia/Jakarta
PORT=20128
API_KEY=buat-api-key-untuk-akses-9router
NODE_ENV=production
JWT_SECRET=isi-dengan-random-string-panjang
INITIAL_PASSWORD=password-untuk-login-dashboard
AUTH_COOKIE_SECURE=true

Generate nilai random untuk JWT_SECRET dan INITIAL_PASSWORD:

# Linux
openssl rand -base64 32

# Windows PowerShell
$r=[byte[]]::new(32); $g=[System.Security.Cryptography.RandomNumberGenerator]::Create(); $g.GetBytes($r); [Convert]::ToBase64String($r)

Jalankan dua kali untuk mendapat dua nilai berbeda. Jangan tambahkan BASE_PATH di env ini — 9router mengabaikan variabel tersebut.

Langkah 8 — File .env Hermes

nano ~/apps/hermes/.env
TZ=Asia/Jakarta
OPENROUTER_API_KEY=isi-dengan-openrouter-api-key-anda
HERMES_AUTH_TOKEN=buat-token-rahasia-untuk-hermes
TELEGRAM_BOT_TOKEN=isi-dengan-token-dari-botfather
TELEGRAM_ALLOWED_USERS=isi-dengan-telegram-user-id-anda
TELEGRAM_HOME_CHANNEL=isi-dengan-telegram-user-id-anda

Variabel Telegram wajib ada di file ini — container hanya membaca env dari file yang dipass via --env-file.

Langkah 9 — Jalankan Caddy, n8n, dan 9router

cd ~/apps
docker compose up -d
docker compose ps

Langkah 10 — Register Hermes di Nous Portal

  1. Buka https://portal.nousresearch.com dan login
  2. Pergi ke Local Dashboards → klik + Register Dashboard
  3. Isi redirect URI: https://hermes.domain-anda.com
  4. Simpan, catat OAuth Client ID yang muncul (format: agent:xxxx...)

Langkah 11 — Jalankan Hermes

Setup wizard sekali:

tmux new -s hermes-setup
docker run -it --rm \
  -v ~/apps/hermes/data:/opt/data \
  --env-file ~/apps/hermes/.env \
  nousresearch/hermes-agent:latest \
  setup

Ikuti wizard sampai selesai, lalu:

tmux kill-session -t hermes-setup

Jalankan container utama (ganti agent:xxxx dengan OAuth Client ID dari langkah 10):

docker run -d \
  --name hermes \
  --restart unless-stopped \
  --network apps_internal \
  -v ~/apps/hermes/data:/opt/data \
  -v ~/apps/obsidian/vault:/opt/vault \
  -e HERMES_DASHBOARD=1 \
  -e HERMES_DASHBOARD_OAUTH_CLIENT_ID=agent:xxxx \
  -e HERMES_DASHBOARD_PUBLIC_URL=https://hermes.domain-anda.com \
  --env-file ~/apps/hermes/.env \
  nousresearch/hermes-agent:latest \
  gateway run

Tidak ada flag -p <PORT>:<PORT> di sini — ini disengaja. Docker bypass UFW via iptables, sehingga jika port di-publish, ia bisa diakses dari internet meski UFW dikonfigurasi menutupnya. Caddy menjangkau Hermes lewat Docker internal network menggunakan IP container langsung.

Langkah 12 — Update Caddyfile dengan IP Hermes

docker inspect hermes --format '{{range .NetworkSettings.Networks}}{{.IPAddress}} {{end}}'

Catat IP dan port dashboard Hermes yang muncul, lalu update Caddyfile:

hermes.domain-anda.com {
    reverse_proxy 172.18.0.x:
}

Reload Caddy:

docker exec caddy caddy reload --config /etc/caddy/Caddyfile

Buka https://hermes.domain-anda.com — harus muncul halaman login Nous Portal.

Setup 9router sebagai LLM Router

Tanpa router, ganti model = edit config Hermes + restart container. Dengan 9router, Anda mendefinisikan model di dashboard-nya, dan Hermes cukup memanggil endpoint 9router. 9router yang memutuskan model mana yang dipanggil.

Buka https://9router.domain-anda.com, login dengan INITIAL_PASSWORD. Tambahkan model di dashboard:

  • Endpoint: https://openrouter.ai/api/v1
  • API Key: API key OpenRouter Anda
  • Model: pilih model yang ingin digunakan

Hubungkan Hermes ke 9router via config.yaml:

nano ~/apps/hermes/data/config.yaml
providers:
  custom:
    base_url: http://router9:20128/v1
    api_key: API_KEY_YANG_ANDA_SET_DI_ENV_9ROUTER
model:
  default: nama-model-yang-dikonfigurasi-di-9router
  provider: custom
docker restart hermes

Hermes sekarang memanggil semua LLM request melalui 9router. Semua API call tercatat di dashboard 9router — berguna untuk monitoring penggunaan dan debugging.

Obsidian sebagai Vault Memory

Obsidian vault sudah di-mount ke container Hermes via -v ~/apps/obsidian/vault:/opt/vault di langkah 11. Hermes membaca file SKILL.md dari subdirektori vault untuk menentukan kapan sebuah skill dieksekusi.

Struktur vault yang direkomendasikan:

~/apps/obsidian/vault/
├── Hermes/
│   ├── Projects/     # Catatan per proyek aktif
│   ├── Decisions/    # Log keputusan penting
│   └── Daily/        # Catatan harian
├── Content/
│   └── Drafts/       # Draft konten
└── skills/           # Custom skills yang dibaca Hermes

Buat atau update MEMORY.md di dalam Hermes data directory:

nano ~/apps/hermes/data/MEMORY.md
## Vault Memory

Vault Obsidian ada di /opt/vault di dalam container.
Konvensi penulisan:
- Catatan proyek: /opt/vault/Hermes/Projects/[nama-proyek].md
- Log keputusan: /opt/vault/Hermes/Decisions/[tanggal]-[topik].md
- Draft konten: /opt/vault/Content/Drafts/[judul].md

Sinkronisasi Vault ke Laptop via GitHub

cd ~/apps/obsidian/vault
git init
git remote add origin [email protected]:username-anda/vault.git
git add . && git commit -m "Initial vault"
git push -u origin main

Tambahkan cron job untuk push otomatis setiap 15 menit:

crontab -e
*/15 * * * * cd ~/apps/obsidian/vault && git add -A && git commit -m "auto: $(date '+%Y-%m-%d %H:%M')" && git push origin main 2>/dev/null

Di laptop, install plugin Obsidian Git dan konfigurasi pull-only dari repo yang sama. Setiap catatan yang ditulis Hermes ke vault tersedia di Obsidian laptop dalam 15 menit.

Verifikasi Akhir

Jalankan checklist ini setelah semua langkah selesai:

# Semua container harus Up
docker compose ps
docker ps --filter "name=hermes"

# Hermes tidak restart-loop
docker inspect hermes --format '{{.RestartCount}}'
# Harus: 0

# Port Hermes tidak di-expose ke host (harus kosong)
docker inspect hermes --format '{{json .NetworkSettings.Ports}}'
# Harus: {}

# Telegram terhubung
docker exec hermes env | grep TELEGRAM

Jika Hermes tidak merespons di Telegram, cek log:

docker exec hermes cat /opt/data/logs/gateways/default/current 2>/dev/null | tail -30

Jika 9router password tidak diterima, kemungkinan ada hash lama di database. Reset:

docker exec router9 sh -c "sqlite3 /app/data/db/data.sqlite \"UPDATE settings SET value='' WHERE key='passwordHash';\""
docker restart router9

Setelah Stack Jalan

Setelah Hermes terhubung ke Telegram, Anda bisa berinteraksi langsung:

  • Simpan catatan ke vault: "simpan ke vault: pertemuan hari ini dengan klien X membahas scope proyek Y"
  • Gunakan skill tertentu: "gunakan skill [nama-skill], [instruksi]"
  • Generate konten: "tulis draft posting LinkedIn tentang [topik]"

Semua container dikonfigurasi dengan --restart unless-stopped sehingga otomatis nyala setelah VPS reboot. Satu hal yang perlu dicek setelah reboot adalah IP container Hermes — Docker bisa mengassign IP baru. Jika IP berubah, update Caddyfile dan reload.

Menambahkan skill baru tidak butuh restart container — buat file SKILL.md di direktori skill Hermes, dan Hermes membacanya di sesi berikutnya.

Pertanyaan Umum

VPS dengan 2 vCPU dan 4 GB RAM sudah cukup untuk Hermes, 9router, n8n, dan Caddy. Di Sumopod, spesifikasi ini tersedia di kisaran Rp 150–250 ribu per bulan. Untuk penggunaan satu pengguna tanpa workflow berat, VPS 2 GB RAM bisa jalan meski lebih terbatas.

Tanpa 9router, ganti model berarti edit config Hermes dan restart container. Dengan 9router, Anda mendefinisikan dan mengelola multiple model di dashboard-nya, bisa mengatur fallback otomatis, dan memantau semua API call — semua tanpa menyentuh konfigurasi Hermes.

Vault tidak wajib untuk membuat Hermes jalan. Hermes bisa beroperasi hanya dengan data directory bawaannya. Obsidian vault menambahkan layer memory persisten dan akses dari laptop, tapi bisa ditambahkan belakangan setelah stack dasar sudah stabil.

Semua container dikonfigurasi dengan --restart unless-stopped sehingga otomatis nyala setelah reboot. Satu hal yang perlu dicek adalah IP container Hermes — Docker bisa mengassign IP baru setelah reboot. Jika IP berubah, update Caddyfile dan reload Caddy.

Buat file SKILL.md di direktori skill Hermes (dalam data directory atau di vault jika sudah di-mount). Format SKILL.md menggunakan YAML frontmatter dengan field name dan description. Hermes membaca skill tersebut di sesi berikutnya tanpa perlu restart container.

Butuh Bantuan Implementasi?

Saya membantu founder dan tim membangun sistem operasi yang bisa jalan tanpa pengawasan konstan.

Hubungi Saya