Multi-Homed Agents
A single Hermes agent can report to more than one Athena server at the same time. Each machine keeps a Servers list — one entry per server it should connect to — and the agent opens an independent, fully isolated connection to every enabled entry. Each server sees the machine as its own enrolled agent, with its own certificate and identity, while the machine is only scanned once and its inventory is shared with every connected server. This is what makes warm-standby disaster recovery, dual-region visibility, and side-by-side server cut-overs possible without touching the endpoint twice.
Multi-homing is about one agent talking to several servers continuously. If instead you want to move an already-enrolled agent from one server to another (or add a second server centrally, from the console), see Agent Server Migration — its Paste mode is simply the console-driven way to add an entry to the Servers list described here.
Why multi-home an agent#
Because every connection is independent, multi-homing solves several operational problems that would otherwise require re-imaging or re-enrolling endpoints:
| Pattern | How multi-homing helps |
|---|---|
| Disaster recovery / warm standby | List both the primary and a standby server. If the primary goes offline the agent keeps reporting to the standby, and the standby already holds live inventory — no cold rebuild. |
| Server replacement / cut-over | Add the new server alongside the old one, confirm the fleet has registered on the new server, then disable or remove the old entry — a zero-downtime migration you can validate before committing. |
| Dual-region / delegated visibility | A workstation can appear in a regional server and a central server at once, so a local team and a global team each see it in their own console. |
| Lab / staging validation | Point a pilot group at both a production and a staging server to exercise a new server build against real inventory without affecting production reporting. |
The Servers list#
Each agent's appsettings.json holds an Agent:Servers array. Every entry
is one server the agent should connect to:
{
"Agent": {
"Servers": [
{
"Name": "primary",
"Url": "https://athena-a.example.com:8444",
"RegistrationToken": "<token-from-athena-a>",
"Enabled": true
},
{
"Name": "standby",
"Url": "https://athena-b.example.com:8444",
"RegistrationToken": "<token-from-athena-b>",
"Enabled": true
}
]
}
}
| Field | Meaning |
|---|---|
Name | A unique label for this connection. It also becomes the name of the per-server data folder on disk, so it must be a valid folder name (see the rules below). Uniqueness is case-insensitive. |
Url | The server's gRPC endpoint, including scheme and port — for example https://host:8444. Must be an absolute URI. |
RegistrationToken | A registration token minted on that server. It is only used the first time the agent registers with the server; once the agent holds a certificate it is no longer needed and can be cleared. |
Enabled | Whether the agent should connect to this entry. Set false to keep the entry but stop connecting to it. Defaults to true when omitted. |
At least one valid, enabled entry is required — an agent with no usable server has nothing to connect to and will log a startup error. Each server you list needs its own token, because a token is always scoped to the server that issued it.
Per-server identity isolation#
Multi-homing is safe because the agent never shares identity material between servers. On first contact with a server it registers, is issued its own certificate by that server's certificate authority, and stores everything for that connection in its own directory named after the entry:
| Path | Contents |
|---|---|
%ProgramData%\Hermes\servers\<name>\ | The per-server identity directory (one per Servers entry). |
…\<name>\agent.pfx | The certificate and private key issued by that server. |
…\<name>\ca.crt | That server's CA certificate, used to validate it. |
…\<name>\server-state.json | The agent's registration state and ID for that server. |
…\<name>\connection-*.log | A per-server connection log (daily rotation, last 7 files kept) — the first place to look when one connection misbehaves. |
Because identity is isolated per entry, each server issues, renews, and can independently revoke
the certificate it gave the agent. Revoking or removing the agent on one server has no effect on
any other server it reports to. The agent's own general activity log stays in the shared
%ProgramData%\Hermes\Logs\ directory; the per-server connection-*.log
files isolate the connection story for each server.
The entry Name is used verbatim as a folder name, so keep it simple and stable
(for example primary, standby, central). Renaming an
entry starts a brand-new identity directory and forces a fresh registration on that server, so
choose names you will not need to change.
How inventory & commands behave#
Multi-homing is designed so that adding a server adds cost on the network, not on the endpoint:
- Inventory is collected once. The agent scans the machine on its normal schedule and stores the result locally, then shares it with each connected server. It tracks what it has already sent to each server, so a server that has fallen behind simply receives the current state on the next cycle — you do not pay for a separate scan per server.
- Heartbeats and status are per connection. The lightweight heartbeat and status updates flow to every enabled server independently, so each console shows the machine as online on its own timeline.
- Commands are per server. A remote command, deployment, or scan you start on one server runs on the endpoint and reports back to that server. The other servers are unaffected. When the agent is already busy running work for one server, work arriving from another server is handled in turn rather than run simultaneously.
- Reconnection is per connection. If one server becomes unreachable the agent keeps retrying that connection (by default forever) while its other connections carry on normally. One server being down never stops the agent reporting to the others.
Managing servers with HermesCLI#
You can edit appsettings.json directly, but the agent's own command-line tool
manages the Servers list safely — it validates input and rewrites only the entry you touch,
leaving the rest of the file untouched. See Agent CLI (HermesCLI)
for how to run it.
# List configured servers, and whether each has registered yet
HermesCLI config server list
# Add a second server (token optional; needed only for first registration)
HermesCLI config server add --name standby --url https://athena-b.example.com:8444 --token <token-from-athena-b>
# Temporarily stop / resume connecting to a server without losing its entry
HermesCLI config server disable standby
HermesCLI config server enable standby
# Remove a server entry (its data directory is left in place)
HermesCLI config server remove standby --force
# Test connectivity to every enabled server at once
HermesCLI test
config server list shows each entry's Name, URL,
whether it is Enabled, and whether it has Registered (that is,
whether its per-server identity directory exists yet); add --json for a
machine-readable form. Adding a server rejects a duplicate name and an invalid URL. Removing a
server takes the name as an argument and prompts for confirmation unless you pass
--force; the on-disk data directory is deliberately preserved so you can re-enable
the entry later without a fresh registration.
The Servers list is read when the agent starts. After any config server change
— add, remove, enable, or disable — restart the Hermes Agent service for it to take effect. On
Windows: HermesCLI service restart (Administrator); on Linux, restart the agent's
systemd unit.
Server-entry rules#
At startup the agent validates every entry and connects only to the ones that pass. Entries that fail a rule are skipped with a warning in the log; disabled entries are skipped quietly. The rules are:
Namemust be present and not blank.Namemust be a valid folder name — no characters that are illegal in a file name, not.or.., and no path separators (/or\).Namemust be 50 characters or fewer.Namemust be unique (case-insensitive); if two entries share a name the first one wins and the later duplicate is skipped.Urlmust be a valid absolute URI.- An entry with
Enabled: falseis skipped — kept in the file, but not connected.
If no entry survives validation the agent has nothing to connect to and logs a critical startup error naming the config file, so a typo in one entry never silently takes the agent offline against the others.
A warm-standby setup, step by step#
- On the standby server, create a registration token with enough uses for the machines you are adding.
- On each machine, add the standby entry:
HermesCLI config server add --name standby --url https://athena-b:8444 --token <token>. For a whole fleet at once, prefer the console-driven Paste-mode migration, which does exactly this over the connection the agent already holds. - Restart the agent (or let the migration handle registration) and confirm each machine now appears in the standby server's fleet view as well as the primary's.
- Leave both entries enabled. If the primary ever fails, the standby already carries live inventory and can drive commands and deployments immediately.
To later retire the old server, disable then remove its entry once every machine is confirmed on the replacement — the reverse of the steps above. See Retiring & Removing Agents for cleaning up an agent's record on a server you are decommissioning.
Every server in an agent's list is one of your servers, reached over your own network on the URL you supply. Multi-homing never introduces an outbound internet dependency — it just fans the agent's existing on-network reporting out to more than one destination. See Air-Gapped Operation.