Skip to main content
Docker Swarm is the default deployment target. For a Kubernetes cluster, see Kubernetes.

Prerequisites

1. Initialize Docker Swarm

On the manager node:

2. Join worker nodes (optional)

On each worker node, run the join command provided by docker swarm init:

Registry authentication

Registry authentication is zero-touch. The CLI fetches the registry token itself on every deploy and hands fresh credentials to Swarm. You do not install a credential helper, run docker login, or manage expiring tokens by hand on any node.

Hosted MCP servers

The engine runs hosted MCP servers as containers on the manager node through the Docker socket. The engine pulls an image the node lacks with the registry logins of a Docker config.json. For an image in a private registry, give it one in 2501-infra.yml:
The path is relative to the install directory, or absolute, and names a file as docker login writes it, for example docker --config ./registry-login login registry.example.com then registry-login/config.json; credential helpers are not read, so the file must hold the logins themselves. 2501 infra deploy hands it to the engine alone as a Swarm secret, readable only by the engine’s user, and points DOCKER_CONFIG at it. The secret is named after the file’s content, so after changing the file, deploy again. Without the setting the stack is unchanged. Alternatively, log in and pull the image on each manager node beforehand (docker login, then docker pull): the engine uses an image the node already has. Before enabling a hosted MCP server, run the firewall rules in Isolate hosted MCP servers on Docker on each manager node: without them a hosted MCP server reaches every container on the node that publishes a port, on the container’s own address, and the rest of your network. The engine runs at most 32 hosted MCP servers at once, each limited to half a CPU and 512 MiB, its 64 MiB /tmp included, so up to 16 CPUs and 16 GiB on the manager node that runs the engine, outside the stack’s own resource settings. Size that node for them. A hosted MCP server must answer the MCP handshake within 60 seconds (MCP_HOSTED_HANDSHAKE_TIMEOUT_MS on the engine), and an executor within 20 seconds (MCP_HANDSHAKE_TIMEOUT_MS); either one that stays silent is started once more in a fresh container, then fails. Set these in the engine’s env file, env.engine, and redeploy.

OAuth sign-in address

An OAuth plugin sends the browser back to <BASE_URL>/api/internal/mcp-oauth/callback, or to an address under it of its provider’s own. The engine builds that address from its own BASE_URL and Command Center checks it against its own, so the two must match. 2501 infra init writes the address you give it into both env.engine and env.command-center; if you change it later, change it in both files and redeploy.

Deployment

Deploy the stack:
For CI/CD pipelines, add --yes. In --yes mode the CLI auto-fixes everything it can, then aborts with an actionable list if a human-required value (such as an LLM API key or the external DATABASE_URL) is still missing. Run an interactive 2501 infra deploy to upgrade: the CLI lists published releases newest-first and self-updates its own binary to match the version you pick before deploying. Back up PostgreSQL first, and see Upgrading for the rollback path. For all deployment options, run 2501 infra deploy -h.

Post-deployment

Verify the services are healthy:
If you run 2501 infra deploy without --yes, the CLI interactively prompts you to create your first tenant, organization, and admin user. In --yes mode, create them afterward with 2501 infra tenant create, 2501 infra org create, and 2501 infra user create (use -h on each for details).