Secure Self-Hosted Hermes
A practical roadmap for running a private Hermes Agent on a hardened Ubuntu VPS with Tailscale, Docker-isolated tools, allowlisted Telegram access, and an Obsidian vault synced back to your laptop.
Most guides for installing an AI agent on a server focus on command execution but overlook security.
The goal is a private, secure, and functional Hermes Agent with Docker-isolated tools, allowlisted Telegram access, and an Obsidian vault that syncs to your laptop.
This configuration does not guarantee security. It is intended as a practical personal deployment. Assess it against your own threat model before handling sensitive data.
What and how to do it
A safer self-hosted Hermes Agent setup runs on Ubuntu VPS, exposes administration only via Tailscale, executes tools via Docker rather than the host shell, stores secrets outside the tool runtime, and restricts Telegram access to allowlisted users.
The target architecture
- Mac / Laptop
- Tailscale private network
- Ubuntu VPS
- Hermes Gateway
- Docker sandbox
- Tool execution + /output artifact area
- Obsidian vault synced by Syncthing
Mac / Laptop
│
▼
Tailscale private network
│
▼
Ubuntu VPS
│
┌────┴────┐
│ Hermes │
│ Gateway │
└────┬────┘
│
Docker sandbox
│
▼
Tool execution + /output artifact area
│
▼
Obsidian vault synced by SyncthingThe design principle ensures the agent operates independently, without inheriting full access to your server.
My current deployment:
Ubuntu 24.04 VPS on Hetzner
Tailscale for private access
Docker backend for tools
Telegram gateway
Hermes Desktop through an SSH tunnel
Dashboard bound to localhost
Admin surfaces behind Tailscale or localhost
Hermes runs as a non-root user
Obsidian vault synced with Syncthing
Restricted tool surfaceHermes can utilize tools, execute commands, write files, search the web, retain context, and communicate via messaging platforms. This functionality makes a private deployment more akin to a small operations system than a simple chatbot.
Intended audience
This configuration is a strong fit if you want Hermes for:
- research and deep-search style workflows;
- personal automation;
- Telegram or Discord assistant access;
- Obsidian-based knowledge management;
- artifact generation on a server that is always online.
This baseline alone is not suitable for:
- financial-system operations;
- production cloud administration;
- confidential client or patient data;
- critical infrastructure;
- unsupervised high-impact decisions.
For these workflows, implement approval layers, audit logs, secrets management, scoped credentials, monitoring, and a secondary human review process.
Step 1: Start with a boring VPS
Use a mainstream VPS provider and a current Ubuntu LTS image.
Recommended baseline:
| Component | Minimum |
|---|---|
| OS | Ubuntu 24.04 LTS |
| CPU | 4+ vCPU |
| RAM | 8+ GB |
| Disk | 100+ GB |
Reasonable providers include Hetzner, DigitalOcean, Vultr, and Linode. A Hetzner CPX31/CPX32-class instance is a practical starting point for personal agent workflows.
Avoid selecting the lowest-cost VPS. Hermes is not the only workload; you may also run Docker containers, Syncthing, logs, browsers, Python tools, and generated artifacts.
Step 2: Use SSH keys only
Create an SSH keypair on your laptop. Upload only the public key to the VPS provider.
Laptop/Mac
private key: stays local
public key: uploaded to VPS providerUse SSH keys from the start when possible. If the password SSH is used during bootstrap, disable it after confirming key-based admin access.
Step 3: Separate the admin user from the Hermes user
Create two users:
admin
sudo: yes
purpose: server maintenance
hermes
sudo: no
purpose: run Hermes and related servicesThis separation is important. If Hermes or a tool runtime is compromised, escalation to sudo privileges should not be possible.
The hermes user should own the Hermes install and its working directories. The admin user should handle package installation, firewall changes, system upgrades, and recovery tasks.
Step 4: Harden SSH before you install the fun stuff
At minimum:
- disable root login;
- disable password login;
- keep public-key auth enabled;
- keep a tested admin SSH session open while changing settings;
- only then reload or restart SSH.
SSH hardening can lock you out. Take a VPS snapshot before and after this phase if your provider supports it.
Step 5: Configure the firewall with a private-network end state
Start with UFW:
incoming: deny by default
outgoing: allow by default
initially allow: SSHThe final goal is stricter: SSH should only be reachable over Tailscale, not from the public internet.
That means there are two phases:
- Bootstrap phase: public SSH is temporarily allowed so you can set up the machine.
- Private phase: after Tailscale works, public SSH is closed and administration happens over the
100.x.x.xTailscale address.
Do not close public SSH until you have tested Tailscale SSH access from your laptop.
Step 6: Install Tailscale and move administration off the public internet
Tailscale gives you a private network without your own VPN server. For this setup, it keeps dashboards, admin ports, and SSH off the public internet.
After Tailscale is installed and the VPS appears in your tailnet:
- test SSH to the VPS Tailscale IP;
- confirm you can administer the server through that route;
- update UFW so public SSH is no longer open;
- keep Hermes dashboard/admin access private as well.
Use this mental model:
Public internet → should not see Hermes admin surfaces
Tailscale → can reach SSH / dashboard / internal servicesStep 7: Install Docker for tool isolation
Hermes can run terminal/file/code execution through different backends. For a security-conscious VPS, prefer:
terminal:
backend: dockerAvoid using a direct local shell backend for routine agent tasks on a server. While Docker is not a complete security solution, it does provide a boundary between agent tool execution and the host operating system.
This isolates common tool actions such as:
- shell commands;
- Python scripts;
- Node tooling;
- file writes;
- package experiments.
While compromise cannot be made impossible, you can prevent routine agent tasks from having the same level of access as the server operator.
Step 8: Install Hermes under /home/hermes, not as root
Install Hermes as the restricted hermes user.
Recommended location:
/home/hermesUseful verification commands after installation:
hermes version
hermes doctor
hermes config path
hermes config env-pathUse the public Hermes installer endpoint:
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bashThen run the setup wizard:
hermes setupFor provider authentication, use the current Hermes docs and the hermes setup, hermes model, and hermes auth flows. Do not hardcode stale model-provider assumptions.
Step 9: Configure the model provider, but do not confuse model choice with security
Model choice affects quality, cost, latency, and context. It will not fix a bad server architecture.
Hermes supports both OAuth/subscription-backed providers and API-key-backed providers. Some advanced tooling, external evaluation frameworks, and optimization systems may require direct API keys even if normal Hermes usage works through OAuth.
Use lighter daily models for normal operation and stronger models for deep work. Treat the model as one layer. Your security posture comes from:
- private networking;
- OS hardening;
- containerized tool execution;
- secrets isolation;
- Telegram allowlisting;
- approval policies;
- controlled filesystem mounts.
For operational resilience, configure fallback providers in config.yaml, not .env:
fallback_providers:
- provider: openrouter
model: <fallback-model-name>Choose a model currently supported by your provider. Use fallbacks for outages, rate limits, or cost control, and test them before you depend on them during a long research run.
Step 10: Put secrets in .env, not in tool-visible files
Hermes documentation separates configuration from secrets:
~/.hermes/config.yaml → normal settings
~/.hermes/.env → API keys, bot tokens, secretsThis separation is important. The tool container should not inherit your entire environment.
Use a tighter posture:
terminal:
backend: docker
env_passthrough: []
docker_forward_env: []Forward only the environment variables required for each workflow. If a tool needs a GitHub token, add it intentionally. Do not forward your entire shell environment into an AI-controlled runtime.
Step 11: Use restrictive Docker mounts
Do not mount the host root filesystem into the tool container.
Avoid mounting:
/
/home/hermes
/var/run/docker.sockIn particular, avoid mounting the Docker socket. Mounting /var/run/docker.sock typically allows the container to control Docker on the host, which can result in host-level access.
Prefer a small, intentional artifact mount:
terminal:
backend: docker
docker_mount_cwd_to_workspace: false
docker_forward_env: []
env_passthrough: []
docker_volumes:
- "/home/hermes/output:/output"Configure Hermes to write generated files to /output. Any dedicated folder is acceptable; mount only that folder, not the entire home directory. The specific host path is less important than ensuring only a dedicated artifacts directory is mounted to /output.
Step 12: Fix generated-file ownership before it becomes annoying
If Docker writes files as root, your sync tools and editor will complain.
Use Hermes Docker settings so generated files are owned by the host user where possible:
terminal:
docker_run_as_host_user: trueEnable docker_run_as_host_user: true when writing to a synced /output folder to ensure generated files are owned by the hermes user rather than root. This improves file synchronization and permissions but is not a standalone security measure. Continue to use narrow mounts and avoid secret passthrough. Root-owned markdown files increase maintenance without enhancing security.
Step 13: Configure Telegram with an allowlist
Create a bot through BotFather and keep the token secret. If it leaks, revoke it.
Hermes Telegram setup can be handled interactively:
hermes gateway setupFor manual .env configuration:
TELEGRAM_BOT_TOKEN=<your-bot-token>
TELEGRAM_ALLOWED_USERS=<your-numeric-telegram-id>Do not use an allow-all configuration for a private AI agent. Telegram serves as the primary access point; restrict it appropriately.
If the bot is added to groups, also pay attention to:
- group allowlists;
- privacy mode;
- whether the bot sees all messages or only mentions;
- whether group context is being observed without auto-replying.
The desired gateway posture is default-deny: only explicitly allowed users or paired users should be able to interact with the agent.
The default private deployment should begin with one user ID: yours. For groups, use group allowlists separately, and do not assume that a private-user allowlist automatically protects group chats.
Allowlisting controls who can reach the bot. It does not mean that every allowed user should have access to every command.
For shared bots, separate:
admin users
regular allowed users
allowed slash commandsLimit command exposure for non-admin users. Do not assume that allowlisting users is sufficient to grant full tool access safely.
For shared bots, configure allow_admin_from and user_allowed_commands so regular users only get specific slash commands. For groups, use the group equivalents: group_allow_admin_from and group_user_allowed_commands.
Step 14: Install the Hermes gateway as a persistent service
A Telegram assistant needs to survive logout and SSH disconnects.
Use Hermes gateway service commands:
hermes gateway install
hermes gateway start
hermes gateway statusIf you are using a user-level service on Linux, make sure the service can survive logout when required. On systemd systems that may involve enabling linger for the service user.
Then check the service and logs:
hermes gateway status
journalctl --user -u hermes-gateway -n 120 --no-pager
sudo systemctl status syncthing-hermes
sudo ufw status verboseIf the gateway is not installed as a systemd user service, check the Hermes log file instead:
tail -n 100 ~/.hermes/logs/gateway.logStep 15: Restrict tools by platform
Do not expose every Hermes tool to every interface by default. A Telegram bot, Discord bot, desktop app, and terminal session do not need the same tool surface.
Run hermes tools to configure individual tool availability per platform. Hermes persists those choices to config.yaml, so this is finer-grained than only enabling or disabling broad toolsets.
Start with a small surface:
- chat and research tools;
- file write access only to
/output; - browser and web tools only when a workflow needs them;
- no unnecessary messaging or admin integrations;
- no production cloud tools;
- no main email or GitHub write access at first.
Consider each new tool as an additional attack surface. While Docker isolation provides some protection, it does not guarantee that a powerful tool is safe on every platform.
Treat MCP servers and external tool integrations like privileged plugins. Do not add MCP servers casually. Review what tools they expose, what credentials they need, and whether they can access local files, network services, or secrets.
Step 16: Delay high-risk integrations
Delay sensitive integrations on day one:
- main Gmail or personal email;
- production GitHub write access;
- cloud admin keys;
- Home Assistant device control;
- webhook or API server exposure;
- shared Discord or Slack bots.
Start with Telegram allowlisted to one user, one web search backend, and /output file writing. Add stronger integrations only after the basic setup behaves safely.
Step 17: Make /output the only normal write target
A good artifact system gives generated files one obvious destination.
Use:
Host: /home/hermes/output
Docker: /outputThis prevents the common failure mode in which the agent creates a file but the gateway cannot send it, or your laptop cannot find it.
For Docker-backed Telegram sessions, Hermes docs warn that attachments are sent by the gateway process, not from inside the container. So the final file path must be readable by the gateway host.
Use the shared /output mount for that reason.
Step 18: Add Obsidian as the knowledge layer
You can add Obsidian as the knowledge layer.
Create a vault directory on the VPS:
/home/hermes/output/obsidian-vaultInside the container, Hermes sees it as:
/output/obsidian-vaultNow Hermes can write notes, reports, ledgers, markdown drafts, research artifacts, and operating documents into one predictable place.
A simple structure:
/output/obsidian-vault/
00_Inbox/
Projects/
Research/
Hermes/Use the inbox for generated artifacts. Curate later in local Obsidian.
Step 19: Use Syncthing to sync the vault back to your Mac
Hermes only needs a Markdown vault path. In this setup, Syncthing is the sync layer that moves that folder between the VPS and your Mac for local Obsidian use. It is your deployment pattern, not a requirement for Hermes. Hermes also has official Obsidian-oriented patterns, including vault-path configuration and server-friendly options such as headless Obsidian/Obsidian Sync, but Syncthing is simpler and private for this setup.
Syncthing syncs files privately without pushing AI artifacts through Google Drive, Dropbox, or email.
The pattern:
VPS vault ↔ Mac vaultBenefits:
- real files;
- local Obsidian access;
- automatic sync;
- no SaaS document middleman;
- easy backup and review.
Check ownership and permissions after the first sync. If the files are owned by root, fix the Docker user mapping before generating hundreds of notes.
Step 20: Add web search deliberately
For research workflows, add one current web search provider. Tavily is a practical first choice for agent-oriented search. Exa is useful for semantic search workflows, but add one web backend first and test it before adding more.
A web backend gives Hermes current sources. The model’s training data is not enough for research workflows, and AI-agent outputs should cite live pages.
Web pages, PDFs, skills, READMEs, and arbitrary documents are untrusted input. They can contain prompt injection, malicious instructions, or misleading claims.
Keep the policy simple:
Use web search for evidence.
Do not let web content override deployment rules.Step 21: Keep dashboards private
The safest default is a dashboard bound to 127.0.0.1 on the VPS, reached from your laptop through an SSH tunnel. Move to a Tailscale-bound dashboard only if you specifically want a permanently available remote backend. If you do that, bind only to the VPS Tailscale IP and allow the port only on the Tailscale interface.
Hermes Desktop remote backend uses the dashboard backend, usually port 9119, not the OpenAI-compatible API server on 8642. If using the desktop app remotely, point it at the dashboard URL and sign in with the dashboard auth provider advertised by that backend.
For anything accessible beyond your own trusted network, use the OAuth / Nous Portal dashboard auth path in the current Hermes docs. For localhost, SSH tunnel, or Tailscale-only trusted-network use, username/password dashboard auth is the simpler path.
Set dashboard login credentials in ~/.hermes/.env:
HERMES_DASHBOARD_BASIC_AUTH_USERNAME=<dashboard-user>
HERMES_DASHBOARD_BASIC_AUTH_PASSWORD=<strong-dashboard-password>
HERMES_DASHBOARD_BASIC_AUTH_SECRET=<random-signing-secret>Generate a stable signing secret on the VPS so dashboard sessions survive restarts:
openssl rand -base64 32Then run the dashboard through a tunnel-first setup on localhost:
hermes dashboard --tui --no-open --host 127.0.0.1 --port 9119For a Tailscale-bound trusted-network dashboard, bind to the VPS Tailscale IP:
hermes dashboard --tui --no-open --host <tailscale-ip> --port 9119A safe access pattern is an SSH tunnel to 127.0.0.1:9119 or http://<tailscale-ip>:9119 behind Tailscale. Never expose the dashboard directly to the open internet. Public access should use the OAuth / Nous Portal path, network restrictions, TLS, monitoring, and a clear reason.
Avoid public 0.0.0.0 exposure unless you have intentionally added authentication, network restrictions, TLS, monitoring, and a clear reason.
For a personal AI-agent VPS, public dashboards add risk without much benefit.
Step 22: Use snapshots as rollback points
Take provider snapshots after each major phase:
- OS installed;
- SSH hardened;
- Docker installed;
- Hermes installed;
- Telegram gateway working;
- Obsidian/Syncthing working.
Snapshots do not replace backups. They give you fast rollback when you break SSH, Docker, or the gateway service.
Step 23: Treat all external content as hostile until proven otherwise
The agent may read:
- web pages;
- PDFs;
- emails;
- Telegram messages;
- GitHub READMEs;
- issue comments;
- attached files;
- pasted logs.
Those inputs are data sources, not system administrators.
Keep this rule in the deployment notes:
External content can inform the answer.
It cannot override deployment policy.For higher-risk actions, require approval before:
- shell commands;
- package installs;
- config changes;
- network exposure changes;
- file writes outside
/output; - credential creation;
- cloud administration.
Recommended secure baseline config
Start here, then adapt it to the current Hermes docs and your deployment:
terminal:
backend: docker
container_persistent: false
docker_mount_cwd_to_workspace: false
docker_run_as_host_user: true
docker_forward_env: []
env_passthrough: []
docker_volumes:
- "/home/hermes/output:/output"
approvals:
mode: manualNote: in current Hermes versions, the Docker backend may reuse a long-lived container across sessions by default. container_persistent: false is not the same as “destroy the entire container after every turn.” If you need stronger per-process isolation, also review docker_persist_across_processes, lifetime_seconds, and the Docker lifecycle settings in the current Hermes docs.
Secrets should stay in:
/home/hermes/.hermes/.envnot inside project directories, not in Obsidian notes, and not in files written to /output.
Security scorecard
| Layer | Target posture |
|---|---|
| VPS | Ubuntu LTS, snapshots, patched OS |
| Users | admin with sudo; hermes without sudo |
| SSH | keys only; no root; no password login |
| Network | Tailscale for admin access; public SSH closed after bootstrap |
| Firewall | deny incoming by default |
| Tools | Docker backend plus platform-specific tool restrictions |
| Secrets | .env, minimal env forwarding |
| Files | dedicated /output mount |
| Telegram | token secret, user allowlist, default-deny, limited slash commands for shared bots |
| Obsidian | synced via Syncthing, not broad host mounts |
| Dashboard | localhost/Tailscale/tunnel only; Desktop remote points to dashboard port 9119, not API port 8642 |
| Recovery | snapshots after every major phase |
I would treat this as a strong personal baseline, not a production compliance architecture.
Common mistakes
Mistake 1: Running everything as root
Root feels convenient until it fails badly. Use a restricted hermes user.
Mistake 2: Using backend: local on a VPS
That gives the agent direct shell access to the host. Use Docker for normal tool execution.
Mistake 3: Forwarding all environment variables
If the tool container receives every secret your shell knows, the container boundary is much weaker.
Mistake 4: Mounting the whole home directory
It feels convenient and gives the tool runtime far more access than it needs.
Mistake 5: Making Telegram public
A Telegram bot is an access surface. Use TELEGRAM_ALLOWED_USERS.
Mistake 6: Exposing dashboards publicly
Use Tailscale or an SSH tunnel. Keep AI-agent admin panels off the public internet by default.
Mistake 7: Losing files because the gateway cannot see the container path
If Docker writes to /workspace/report.md and the gateway cannot read that path, attachments fail. Use a shared /output mount.
Mistake 8: Using --yolo
Do not use --yolo for a server-side agent. It bypasses dangerous-command approval prompts. Keep approvals in manual mode unless you have a strong reason and compensating controls in place.
Hermes docs describe approvals.mode: manual as the default for destructive-command prompts, and off as equivalent to --yolo.
Practical implementation checklist
FAQ
Is Docker enough to make Hermes safe?
No. Docker is one layer. You also need a restricted user, minimal mounts, minimal environment forwarding, private networking, gateway allowlists, and careful approval policies.
Should I expose Hermes publicly behind a password?
For a personal deployment, usually no. Use Tailscale or an SSH tunnel. Public exposure should be a deliberate, monitored production decision.
Can I use Telegram safely?
Yes, if you keep the bot token secret and restrict access to numeric allowlisted user IDs. Do not use an allow-all setting for a private agent.
Why use /output?
Because it creates one controlled write zone for generated files. It also solves Docker/gateway path-mismatch issues when sending files via Telegram or syncing with Obsidian.
Why Obsidian plus Syncthing?
It keeps the knowledge base as real local files, syncs privately, and avoids turning every AI artifact into a cloud-document workflow.
What port should Hermes Desktop use for a remote backend?
Use the Hermes dashboard backend, usually port 9119, not the OpenAI-compatible API server on 8642. Keep it private through Tailscale or an SSH tunnel, and sign in through the dashboard auth provider. Use OAuth / Nous Portal for public reachability; use username/password dashboard auth only for localhost or trusted-network access.
Can I store client confidential data in this setup?
Not by default. Add stronger controls first: encryption policies, access logging, explicit approvals, data retention rules, backups, monitoring, and professional compliance review.
Bottom line
A self-hosted Hermes Agent can be useful, but the safe version is not “install Hermes on a VPS.” It is a small private AI operations stack.
The secure pattern is:
VPS + hardened SSH + Tailscale + Docker backend + restricted tools + no broad mounts + no secret passthrough + Telegram allowlist + default-deny gateway + /output artifact mount + Obsidian/Syncthing + snapshotsThat gives you an always-on private AI agent without handing the model your whole server.
References
- Hermes configuration documentation: https://hermes-agent.nousresearch.com/docs/user-guide/configuration
- Hermes security documentation: https://hermes-agent.nousresearch.com/docs/user-guide/security
- Hermes Telegram documentation: https://hermes-agent.nousresearch.com/docs/user-guide/messaging/telegram
- Hermes tools documentation: https://hermes-agent.nousresearch.com/docs/user-guide/features/tools
- Hermes environment variables documentation: https://hermes-agent.nousresearch.com/docs/reference/environment-variables
- Hermes MCP documentation: https://hermes-agent.nousresearch.com/docs/user-guide/features/mcp
- Hermes installation documentation: https://hermes-agent.nousresearch.com/docs/getting-started/installation
- Hermes Desktop documentation: https://hermes-agent.nousresearch.com/docs/user-guide/desktop
- Hermes Web Dashboard documentation: https://hermes-agent.nousresearch.com/docs/user-guide/features/web-dashboard