Security & Licensing

MultiAgent holds the sensitive data of your whole infrastructure: servers’ SSH keys, agent passwords, registry tokens and API keys. This page explains how all of it is protected, how backups are set up, and how licensing works.

Secret encryption

Every secret is encrypted at rest with AES-256-GCM symmetric encryption. The 32-byte key lives in /data/keys/management-secret.key — inside the MultiAgent volume, outside the database. What is protected:

  • servers’ SSH passwords and private keys (including proxy jump credentials);
  • Postgres and Forgejo passwords on servers;
  • image registry tokens (Registry Auth);
  • agent managers’ passwords and the secret variables of models and tools;
  • API keys and server service passwords (Postgres, Forgejo, central login, backup).

User sign-ins are checked with JWT tokens valid for 90 days, signed by a separate key from /data/keys. Every API action requires a key check; only the login page is anonymous, and the machine interface /api/agent/* opens with its own X-API-Key.

Agent API — the machine interface

The /api/agent/* interface is meant for automatic calls — from agents and external systems. Every request is checked against the X-API-Key header: the MULTIAGENT_HASH environment variable stores only the key’s fingerprint (a SHA-256 hash), and the key itself is set once at install. Without the variable, the interface answers 503 and does not work at all.

Security details: GET /api/agent returns a catalog of every operation with descriptions; secrets can only be written — they are never given back, only “has a value” hints; there is no remote code execution — only pre-defined operations; long operations follow the “start it, then poll” pattern at operations/{id}. Details — Agent API.

Publicness of ports

Agents, apps and tools are invisible from the internet by default: their ports are published only on the server itself (at the 127.0.0.1 address) and reachable by its apps and nginx. Opening a port to the world is your choice — the “Public port” switch on the binding you need. It is there both in the creation wizard and later on the “Ports” tab of an agent or app: every binding has its own switch, and new rows appear closed. The change takes effect on the next recreation, while changing the main port updates the route right away. That way deployments on one machine never see each other: a foreign container cannot reach a closed port.

Only nginx itself (the front door) and the backup service stay public always — they are the ones meant to be reachable from outside. Everything else is closed, and closed ports are managed over a protected tunnel, so a closed port never stops MultiAgent from checking an agent’s health and controlling it.

Backups

On every server MultiAgent runs a backup service — rsync with seven read-only sections: the docker, home page, data, projects and tools folders, plus two dump folders (Postgres and Forgejo). Your backup machines pull the data by rsync on a schedule — a typical nightly task:

# nightly backup of all server data
rsync -avz rsync://backup@server-host:873/data/    /backups/server-host/data/
rsync -avz rsync://backup@server-host:873/projects/ /backups/server-host/projects/

MultiAgent itself is backed up together with its /data volume: the database, the encryption keys and the license live there. More about the data layout — in the installation guide.

Agent licenses

The “Licenses” section is the central store for Xedant Agent family license keys. A key is verified when added, encrypted at rest, and never returned by the API — the interface shows only the parsed metadata (type, owner, term, covered products) and never the key itself. The licenses page and the details dialog show a “Products” field: the list of products from the key, or “Universal” for a universal key. A correctly signed key that does not cover the product you need returns a coverage error instead of a term — the status tells you exactly what is wrong. One key can be assigned to any number of agents and lands automatically in their AGENT_LICENSE variable at deployment. A license assigned to at least one agent, or chosen as a server’s default license, cannot be deleted until you detach it.

A key can not only be pasted — it can be issued right in the interface: when the signing key sits on the host, the license dialog gains a “Generate license” item. There you fill in the type, who it is issued to, the email, a description and the term; the finished key goes straight into the encrypted store and becomes the server’s default license — the key itself is never shown, just like a pasted one. Without the signing key on the host, the item does not appear and nothing changes.

Where a license went is visible too: its details dialog lists the servers and agents that use it — by name, with links, not just a count. That way you can detach a license before deleting it without walking every server by hand. A license is also picked on the server page — it becomes the default for all new agents on it.

MultiAgent licensing

MultiAgent itself ships with a 30-day trial baked into the image. The license is a self-contained signed string: you load it through the AGENT_LICENSE variable (the same one every product in the family reads) or as an activation file in the data folder, and it is verified offline against a built-in key. A universal key (no product list) covers every product; an invalid license blocks only creating new things and sending messages. License types and prices — on the Licensing page.

The license status loads right after sign-in: the license line in the interface shows its state as soon as you are signed in — including the first time you open the panel in a new browser, where the sign-in happens after the page has already loaded. No manual refresh is needed.

Interface language

Each user picks the interface language in the “Appearance” window: English or Russian. English is simply the default of the English build; on the Russian build the interface opens in Russian — but everyone can switch it for themselves, and the choice is saved with the account. Dates and numbers keep the build’s format either way.

← Back to documentation