cd /news/ai-agents/show-hn-hermzner-provisioning-an-har… · home topics ai-agents article
[ARTICLE · art-33343] src=github.com ↗ pub= topic=ai-agents verified=true sentiment=· neutral

Show HN: Hermzner – Provisioning an Hardened Hermes Agent on Hetzner VPS

A developer released Hermzner, an open-source tool that provisions a hardened Hermes AI agent on a Hetzner VPS using rootless Podman and Tailscale. The setup includes Terraform and Ansible scripts for deployment, with security features like image digest pinning and firewall rules. It aims to provide a secure, disposable test environment for the Hermes agent before production use.

read4 min views1 publishedJun 18, 2026

Provision a hardened Hermes Agent on Hetzner with rootless Podman and Tailscale.

Terraform>= 1.5Ansible>= 2.15Hetzner Cloud API tokenTailscale pre-auth key(reusable or ephemeral)

cp terraform/terraform.tfvars.example terraform/terraform.tfvars
vim terraform/terraform.tfvars

vim ansible/inventory/group_vars/all.yml

HCLOUD_TOKEN=your_token TAILSCALE_AUTH_KEY=tskey-auth-... ./deploy.sh

deploy.sh

runs Terraform (provisions VPS) then Ansible (configures it). Ansible connects via the server's public IPv4 — Tailscale isn't available until the Tailscale role runs. Running terraform plan

shows the diff between Terraform state and real infrastructure; this is normal behavior, not an error. apply

reconciles them.

Use this procedure for a first disposable test deployment. The goal is to validate Terraform, Ansible, Tailscale access, rootless Podman, and the Hermes runtime wiring before using a pinned production image.

Important:Run this only against a disposable Hetzner VPS. The smoke test may useALLOW_UNPINNED_IMAGE=true

for convenience. Do not use this override for production.

Create and edit the Terraform variables file:

cp terraform/terraform.tfvars.example terraform/terraform.tfvars
vim terraform/terraform.tfvars
Component Detail
VPS Hetzner cx23, Ubuntu 24.04
Container Runtime Rootless Podman (Quadlet default, Compose fallback)
Network Tailscale SSH + subnet access
Service Hermes Agent (gateway, API, optional dashboard)
Mnemosyne Memory SQLite-vec memory backend (optional, toggle via hermes_mnemosyne_enabled )
Backups Daily local backups to /home/hermes/backups/; optionally encrypted with age
  • Rootless container, all capabilities dropped, no-new-privileges
  • All ports bound to 127.0.0.1 (access via Tailscale SSH tunnel)
  • UFW default deny, only tailscale0 allowed
  • Read-only root filesystem, tmpfs for /tmp and /run
  • API key auto-generated, .env at 0600
  • Image digest pinning required (fail-closed if missing)

See SECURITY.md for the full security model, threat model, and design rationale.

ssh -L 9119:127.0.0.1:9119 hermes@<tailscale-ip>

Mnemosyne provides persistent memory (SQLite-vec) for the Hermes Agent, enabling long-term recall across conversations.

hermes_mnemosyne_enabled: true

When enabled, two dedicated Ansible roles handle the integration:

— builds a custom container image extending the pinned Hermes base withmnemosyne_build

mnemosyne-memory[all]

, tags it aslocalhost/hermes-mnemosyne:latest

— runs after the container starts: waits for the health endpoint, runsmnemosyne_runtime

mnemosyne.install

inside the container (plugin symlink + config.yaml update), and restarts the service only if changes were made

The Quadlet/Compose template uses the custom image and sets MNEMOSYNE_DATA_DIR=/opt/data/mnemosyne

for SQLite persistence.

The runtime install is automated by Ansible. The only manual step is selecting mnemosyne

as the active memory provider:

ssh hermes@<tailscale-ip>
podman exec -it hermes /opt/hermes/.venv/bin/hermes memory setup

Verify with /opt/hermes/.venv/bin/hermes memory status

(inside container) — should show Provider: mnemosyne

.

ssh root@<tailscale-ip>
sudo -u hermes XDG_RUNTIME_DIR=/run/user/$(id -u hermes) podman exec hermes python3 -m mnemosyne.install
sudo -u hermes XDG_RUNTIME_DIR=/run/user/$(id -u hermes) systemctl --user restart hermes.service
ssh hermes@<tailscale-ip>
podman exec -it hermes /opt/hermes/.venv/bin/hermes memory setup

Memory data lives at /home/hermes/.hermes/mnemosyne/

and is included in daily backups.

Daily backups run via cron at 2am (user hermes

). They archive /home/hermes/.hermes/

(data + auto-generated .env

) to /home/hermes/backups/

with 30-day retention. When Mnemosyne is enabled, memory data at /home/hermes/.hermes/mnemosyne/

is included automatically.

/home/hermes/backups/hermes-backup-20260521-020000.tar.gz

/home/hermes/backups/hermes-backup-20260521-020000.tar.gz.age

Enable encryption by setting backup_encryption_enabled: true

and backup_age_recipient

(your age public key) in group_vars/all.yml

.

Restore from any backup archive to a running server:

./scripts/restore.sh /path/to/hermes-backup-20260521-020000.tar.gz

./scripts/restore.sh /path/to/hermes-backup-20260521-020000.tar.gz.age --age-key ~/.age/key.txt

The script auto-detects the Tailscale IP (falls back to --tailscale-ip

if Terraform state is missing), copies the archive, stops the runtime, extracts, fixes permissions, restarts, and runs verify.yml

.

terraform/       # Hetzner VPS provisioning
ansible/         # Server configuration (5 roles)
  inventory/
    group_vars/        # Ansible group variables (all.yml)
deploy.sh        # One-command deploy (auto-generates hosts.yml)
teardown.sh      # Destroy everything

scripts/repo_check.sh

runs local security and consistency checks against the repo. It scans for:

  • Secret leakage (API keys, tokens in committed files)
  • Dangerous container flags ( --privileged

, host networking, etc.) - Image pinning and port binding enforcement

  • Shell / YAML / Ansible syntax errors
  • Optional Terraform validation
./scripts/repo_check.sh

Output is written to hermzner-local-check-report.txt

(gitignored).

See ansible/inventory/group_vars/all.yml

for all configurable options, including feature toggles (hermes_dashboard_enabled

, hermes_mnemosyne_enabled

, hermes_start_runtime

), resource limits, backup settings, and security policies.

── more in #ai-agents 4 stories · sorted by recency
── more on @hetzner 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/show-hn-hermzner-pro…] indexed:0 read:4min 2026-06-18 ·