← Developers
Level 0: resolver Agent runtime

Hermes Agent

Hermes Agent runs as a gateway service with a terminal backend, a browser tool and MCP servers. This guide assigns the gateway host one policy and the terminal backend a second, so every destination the agent reaches is inventoried, held when first seen, and logged.

Runs as
systemd service, Hermes Desktop, or the official Docker image
Configuration
~/.hermes/config.yaml, ~/.hermes/.env
Terminal backend
local, docker, ssh, singularity, modal, daytona, vercel_sandbox
Covered here
local, docker and ssh backends; the compose deployment

Configuration and reference code for Hermes Agent

Why

Hermes executes shell commands the model writes. The vendor egress guide for Docker routes HTTP through an allowlisting proxy and states that DNS resolution on the isolated network remains open. Agent DNS closes that gap and adds what a proxy allowlist cannot: an inventory per agent, a hold on first-seen destinations, and an event for every decision. The gateway and the terminal backend get separate policies because an approval for the model provider must not extend to whatever a shell command fetches.

Requirements

Two policies in the console, hermes-gateway and hermes-sandbox, each bound to its own site. The resolver pair and block page address of each site. Root on the host.

1. Assign the gateway host

The gateway, the local terminal backend and the browser tool all resolve through the operating system. No Hermes restart is needed.

/etc/systemd/resolved.conf.d/securd.conf
[Resolve]
DNS=<primary resolver IP> <secondary resolver IP>
FallbackDNS=
DNSOverTLS=no
Domains=~.

2. Restrict DNS egress

Only the assigned resolvers may be asked for names. The counters record bypass attempts.

/etc/nftables.d/securd-dns.nft
table inet securd {
  chain output {
    type filter hook output priority 0; policy accept;
    ip daddr { <primary resolver IP>, <secondary resolver IP> } udp dport 53 accept
    ip daddr { <primary resolver IP>, <secondary resolver IP> } tcp dport 53 accept
    udp dport 53 counter drop
    tcp dport 53 counter drop
    tcp dport 853 counter drop
  }
}

3. Assign the terminal backend

docker backend: Hermes starts a hardened container per task and does not pass a resolver, so the container takes the Docker daemon default. Set the default to the hermes-sandbox site. ssh backend: configure the worker VM with step 1 under the hermes-sandbox site and apply step 2 on it.

/etc/docker/daemon.json
{
  "dns": ["<sandbox primary resolver IP>", "<sandbox secondary resolver IP>"],
  "dns-search": []
}
~/.hermes/config.yaml
terminal:
  backend: docker
  docker_forward_env: []          # provider keys stay out of the sandbox
approvals:
  unattended_mode: deny           # cron, webhook and API sessions cannot self-approve
security:
  allow_lazy_installs: false      # no runtime pip installs from the gateway process

4. Compose deployment

The vendor compose file uses network_mode: host, so step 1 covers it. If you apply the vendor network isolation override, host networking is cleared; add dns to the gateway and proxy services.

docker-compose.override.yml
services:
  gateway:
    dns:
      - <hermes-gateway primary resolver IP>
      - <hermes-gateway secondary resolver IP>
  egress-proxy:
    dns:
      - <hermes-gateway primary resolver IP>
      - <hermes-gateway secondary resolver IP>

5. Learn, then enforce

On hermes-gateway, import the scope template for the model provider and add the messaging platform and update hosts. Run both policies in Learn Only for seven days. Review Traffic Logs filtered on Greywall Event: New Query, approve what the agent needs, then set Default Action to Deny and Greywall Mode to Enforce.

PolicyApprove
hermes-gatewayModel provider template; api.telegram.org, discord.com, gateway.discord.gg, slack.com, api.slack.com as configured; github.com and objects.githubusercontent.com for hermes update
hermes-sandboxOnly what the review shows. Package registries stay held unless the role installs software.

Verify

Run on the gateway host and inside a terminal task. Confirm the test name in Traffic Logs on the policy that answered it.

verify.sh
getent hosts first-seen-$(date +%s).example      # expected: <block page address>
dig +time=2 +tries=1 @8.8.8.8 example.com        # expected: connection timed out
getent hosts api.openai.com                      # expected: a public address

Limits

The modal, daytona and vercel_sandbox backends run in vendor-managed sandboxes with no resolver control and are not covered. Keep security.website_blocklist, SSRF protection and approvals.deny on; they govern the tools and command text inside the process. Connections to a raw IP are governed by the egress firewall.

Vendor documentation this page was verified against

Vendor settings change. Securd behaviour on this page (the block page answer, the per-policy baseline, the DoH base) is a property of the product and does not.

Evaluate Agent DNS with your own agent traffic

Deploy on a single policy in learning mode and review the recorded destinations with your team.