Don’t want to read all this?
Just drop a link to https://xedant.com/agents/multiagent/docker.md or to https://xedant.com/llms.txt into any AI chat (Claude, ChatGPT, etc.) and ask it to generate the config files and commands. It will read the docs, ask you a few questions about your setup, and hand you a ready-to-use configuration. Save time — let the model do the reading for you.
You can also reach me on Telegram — I’m always glad to help. And that’s not just politeness — I genuinely enjoy talking to like-minded people, especially if you love coding as much as I do.
Xedant MultiAgent is the central control panel for a fleet of AI workers. It runs as a single Docker container, and the servers it manages connect over SSH: MultiAgent installs Docker and everything else on them by itself. Nothing needs to be configured on those servers by hand. Each server’s apps are served from subfolders of one domain — for example, https://your-domain/agent1/, https://your-domain/research/ — thanks to an Nginx container (agents-nginx) on the server itself: no separate domains, certificates or web servers per app (see Nginx Routing).
Minimum Requirements
The MultiAgent container itself is light: by default it uses the built-in SQLite, and PostgreSQL can be attached optionally through an environment variable. Any Docker host with 1 GB of RAM is enough.
Each managed server needs:
- Linux (Ubuntu/Debian) with SSH access;
- root or sudo access — MultiAgent installs Docker and the dependencies itself;
- password or private PEM key authentication.
Docker Compose
Create a compose.yml file and run docker compose up -d:
services:
multiagent:
image: xedant/multiagent:min-latest
container_name: agents-multiagent
ports:
- "3990:80"
volumes:
- multiagent-data:/data
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://+:80
- MULTIAGENT_DATA=/data
# optional: own agent (Own Agent) and the machine API
# - AGENT_API_URL=https://agents.example.com/my-agent
# - AGENT_API_KEY=your-agent-key
# - MULTIAGENT_HASH=<sha256 hex of the same key>
# optional: analytics archive in ClickHouse
# - MULTIAGENT_CLICKHOUSE_URL=http://clickhouse:8123
restart: unless-stopped
volumes:
multiagent-data:
After the start, the interface is available on port 3990: http://localhost:3990.
Environment Variables
- MULTIAGENT_DATABASE — path to the SQLite file, or a PostgreSQL connection string. Default
/data/data.db. If the string starts withHost=orServer=, PostgreSQL is used. - MULTIAGENT_DATA — root of the persistent data (default
/data): the database, encryption keys, license, tool templates. - MULTIAGENT_BRAND — interface branding:
xedantfor the English version (the default in the image). - MULTIAGENT_BASE_PATH — the subfolder MultiAgent lives in (for example,
/multiagent) when the proxy above passes the path through unchanged. Only needed for subfolder hosting; leave empty to serve from the domain root. The second way is theX-Forwarded-Prefixheader from the proxy, when the proxy manages the subfolder itself (see Nginx Routing). - AGENT_LICENSE — the license key (the same variable the agents read). A 30-day trial key is already built into the image, and your own license can be entered right away or later — in the app’s license dialog.
- AGENT_API_URL / AGENT_API_KEY — wiring up the own assistant (Own Agent): the base address of an external Xedant Agent and the key the agent accepts as
X-API-Key. - MULTIAGENT_HASH — the fingerprint of the machine API key
/api/agent/*(Agent API): the SHA-256 sum of the key in lowercase. The key itself is not stored on the server — the server compares fingerprints. - AGENT_TOOLS — folder of the tool template library. Default
/project/tools; use/data/toolsso the library survives container recreation. - AGENT_PRODUCTS — folder of the product catalog (default
/project/products): eleven ready-made templates, from MultiAgent itself to the Portal Agent. The list with ports is on the Products page. - MULTIAGENT_ERROR_REPORTING — sending error reports to the Errex error-collection service. Set
0to disable: then nothing is sent from the server or from the browser. - ASPNETCORE_URLS — the port inside the container (default
http://+:80). - MULTIAGENT_CLICKHOUSE_URL — optional ClickHouse address for the analytics archive (see Analytics). When set, chat stats are appended to the archive once a minute, and a “Backfill ClickHouse Stats” button appears at the bottom of the report.
MultiAgent can live not only in the domain root but also in a subfolder — for example, https://your-domain/multiagent/. To do that, set MULTIAGENT_BASE_PATH=/multiagent (a leading slash, no trailing one): page addresses and API commands recalculate themselves, and old links without the subfolder redirect to the new location once. When an upper proxy manages the subfolder, the variable is not needed — the proxy announces it in the X-Forwarded-Prefix header. Details are on the Nginx Routing page.
The .env File at the Project Root
Settings can be changed without touching the deployment file: put a .env file with KEY=value lines next to the application. MultiAgent reads it itself — in the image that is the project root, the /app folder (its address is set by the MULTIAGENT_PROJECT_PATH variable). It is handy when you do not want to edit compose.yml or a long docker run command, for example to add the own assistant’s address and key.
- the file is read at startup and re-read on the fly: edits are picked up without a restart. The exception is what is read once at start (for example the database connection string): such values need a restart;
- values from the file win over variables set at deployment;
- keep the file out of the repository: on first sight MultiAgent adds
.envto.gitignoreitself, because it usually holds secrets; MULTIAGENT_PROJECT_PATHmust not be set in the file: that variable decides where the file itself is looked for. Such a value is ignored and a warning is written to the log.
The format is simple: KEY=value lines, comments with #, blank lines; a value may be quoted. This is not the .env passed to docker run‘s --env-file flag (see below): that file is read by Docker on your machine, while this one is read by MultiAgent itself.
Own Agent
MultiAgent can keep its own assistant — an external Xedant Agent attached with a pair of environment variables. Its interface is built into every page: a block in the sidebar, a global chat panel, a prompt queue and voice input. The setup is only the variables — no settings screen in the interface and nothing in the database:
- AGENT_API_URL / AGENT_API_KEY — the outbound direction (MultiAgent → agent): the built-in chat works through them (MultiAgent forwards requests to the agent and relays chat events). The key is attached only on the server and never reaches the browser;
- MULTIAGENT_HASH — the inbound direction (agent → MultiAgent): the fingerprint of the machine API key
/api/agent/*, through which the assistant manages servers, agents and tools. On the agent’s own side, the MultiAgent address arrives in theMULTIAGENT_URLvariable and the key itself inMULTIAGENT_KEY.
The two directions work independently. When MultiAgent itself is deployed as a product, both variable pairs are filled in automatically (see Products). Details are on the Own Agent page.
Data Storage
All persistent data lives in the /data volume and survives container recreation. The volume is mandatory — without it you lose the database, the encryption keys and the activated license on the first docker compose down.
/data/data.db— the SQLite database (when PostgreSQL is not used);/data/keys/— the JWT signing key and the management key that encrypts the stored license keys and agent credentials;/data/auth/— ASP.NET Data Protection keys;/data/tools/— tool templates (withAGENT_TOOLS=/data/tools);/data/ssl/— certificates: the self-signed one (withMULTIAGENT_SSL=auto) and the Let’s Encrypt service key;/data/<brand>/license.txt— the activated license.
First Login
The first user registers right in the web interface: open http://localhost:3990 and click “Register” on the login page. Further accounts are created the same way — in the interface. The same can be done with the MULTIAGENT_LOGIN and MULTIAGENT_PASSWORD variables (the password is a SHA256 hash): at startup, MultiAgent creates that user or updates their password. Sign-in works through JWT tokens that last 90 days, so you will rarely need to sign in again.
Adding the First Server
After logging in, add the first server: name, host, SSH port, user, and a password or private key. MultiAgent will check the connection, offer to install Docker and walk the server through the onboarding checks. Details are in the Servers section.
Windows Installation
The setup wizard installs MultiAgent on Windows as a Windows service: it starts with the system boot, keeps managing your servers even when nobody is logged in, and serves the web interface at http://localhost:3990. Administrator rights are required; the .NET runtime is not. Details are on the Windows Installation page.
Docker CLI with the –env-file Flag
You can also run MultiAgent without compose — with a docker run command, keeping the environment variables in a file that is passed to the --env-file flag:
# .env
ASPNETCORE_ENVIRONMENT=Production
ASPNETCORE_URLS=http://+:80
MULTIAGENT_DATA=/data
# optional: own agent (Own Agent) and the machine API
# AGENT_API_URL=https://agents.example.com/my-agent
# AGENT_API_KEY=your-agent-key
# MULTIAGENT_HASH=<sha256 hex of the same key>
# optional: product catalog
# AGENT_PRODUCTS=/data/products
# optional: subfolder hosting (when the proxy passes the path through unchanged)
# MULTIAGENT_BASE_PATH=/multiagent
# optional: PostgreSQL instead of the built-in SQLite
# MULTIAGENT_DATABASE=Host=postgres;Port=5432;User Id=multiagent;Password=secret;Database=multiagent;
# optional: analytics archive in ClickHouse
# MULTIAGENT_CLICKHOUSE_URL=http://clickhouse:8123
# optional: license key, if you have one
# AGENT_LICENSE=
docker run -d \
--name agents-multiagent \
--env-file .env \
-p 3990:80 \
-v multiagent-data:/data \
--restart unless-stopped \
xedant/multiagent:min-latest
The --env-file flag reads all the variables from the file. Individual values can be overridden with extra -e flags after it, for example -e AGENT_LICENSE=your-key.