Skip to content

ADR-0007 · Plaintext Secrets + OS Hardening

We chose to store API keys and tokens as plaintext in ~/.hermes/.env on the Agent Host VPS, hardened at the OS level, rather than using a secrets manager or encrypted-at-rest solution.

The Hermes Agent needs runtime access to multiple secrets: Telegram bot token, OpenRouter API key, Francois Personal Google Drive OAuth2 refresh token, GitHub fine-grained PATs scoped to specific fducat18 repos, and potentially more. These are stored in ~/.hermes/.env — a flat file that Hermes reads at startup. The day-one dashboard must not display or edit .env values. Djuly Google Drive, professional Google Drive, and professional GitHub tokens are explicitly out of day-one Agent Host scope.

Plaintext .env with OS-level hardening (day one). Upgrade path documented below.

Use separate fine-grained personal GitHub PATs:

TokenScopePermissionsPurpose
HERMES_GITHUB_CODE_PATSelected personal fducat18 repos onlycontents:write, pull_requests:writeLet Hermes edit personal code/wiki repos through branch-review delivery
HERMES_BACKUP_GITHUB_PATPrivate hermes-backups repo onlycontents:writePush daily encrypted Hermes backup archives

Avoid classic PATs, wildcard repo scope, professional org access, and long-lived tokens when a 90-day expiry is tolerable.

  1. Dedicated user — Hermes runs as hermes user (not root). The .env file is owned by hermes:hermes with chmod 600.
  2. SSH-key-only access — password and root login disabled on VPS. Only Francois’s ed25519 key can connect.
  3. UFW firewall — only port 22 (SSH) open inbound. All other traffic flows through Cloudflare Tunnel (outbound-only from VPS). Keeping SSH on 22 is acceptable because security comes from key-only auth, fail2ban, updates, and firewalling, not port obscurity.
  4. Dashboard binds to localhost — port 9119 listens on 127.0.0.1 only. External access is via Cloudflare Tunnel + Access (email OTP).
  5. No web secret editing day one — dashboard is read/operate only (sessions, logs, health, chat, non-secret operations). .env display/edit is done only over SSH from Bitwarden.
  6. No secrets in git — the .env file is never committed. The repo contains only .env.example with placeholder values.
  7. Telegram webhook via tunnel — not a public HTTP endpoint; delivered through the authenticated tunnel.
ThreatImpactMitigationResidual risk
VPS root compromiseAll secrets exposedSSH-key-only, UFW, unattended-upgrades, fail2banLow — attacker needs your private key
Cloudflare Tunnel breachDashboard access to sessions, logs, health, chat, and non-secret operationsCF Access email OTP + dashboard on localhost only + no web secret editing day oneLow — requires compromising Cloudflare AND your email
Backup leak (VPS snapshot with .env)Secrets in backupExclude ~/.hermes/.env from automated backups; re-provision secrets from Bitwarden if neededLow — manual backup process
Log/stdout leakToken appears in error logHermes redacts secrets in logs by defaultVery low
Hostinger employee accessTheoretical hypervisor accessAccept provider trust (same as any VPS/cloud)Accepted risk
  • If someone has root, they can read the decryption key (it must be available at boot for the service to start)
  • Adds complexity (systemd ExecStartPre decrypt step, key management)
  • The real protection is preventing unauthorized access (SSH keys, firewall, tunnel), not encrypting something that must be decrypted to be used
TriggerUpgrade to
Add Gmail/email access (highly sensitive)Bitwarden Secrets Manager ($6/mo) — secrets fetched at runtime, never on disk
Add family members with VPS accessPer-user secret scoping + encrypted at rest with age
Regulatory requirement (client data)Hashicorp Vault or Infisical (full audit trail, rotation, leases)
  • No encryption at rest — if someone images the VPS disk, secrets are readable
  • No audit trail — no log of “who accessed which secret when” (Bitwarden Secrets Manager would provide this)
  • Manual rotation — changing a key means editing .env and restarting the service

These tradeoffs are acceptable for a single-user personal estate with no client data and strong perimeter security.