Docker Swarm

Docker Swarm is the recommended high-availability deployment for Docker environments. Swarm’s ingress routing mesh provides VIP load balancing and automatic failover without keepalived, and the stack file (docker-swarm.yml) declares replica counts, placement constraints, and health checks.

When to use Swarm

TopologyUse when
Single-node SwarmYou want Swarm’s declarative stack model on one host (no HA, but ready to scale).
Multi-node Swarm + HAYou need HAProxy/Coraza redundancy and Valkey Sentinel failover across hosts.

For a single-host non-HA deployment, the Quick Start Docker Compose flow is simpler. For Kubernetes, see Kubernetes.

Prerequisites

  • A Linux host (or cluster) with Docker Engine and Swarm mode initialized
  • Ports 80, 443, 3000, 8000, 8404 available (configurable)
  • For multi-node: a container registry reachable from all nodes, or images manually loaded on each node

1. Initialize the Swarm

On the manager node:

docker swarm init

If you have multiple network interfaces, specify the advertise IP:

docker swarm init --advertise-addr <manager-ip>

Join worker nodes using the token printed by docker swarm init:

docker swarm join --token <worker-token> <manager-ip>:2377

Retrieve the join token later with docker swarm join-token worker.

2. Configure Environment

Copy the example environment file and edit it:

cp .env.example .env

At minimum set the secrets (SECRET_KEY, ADMIN_PASSWORD, DATAPLANE_API_PASSWORD). For HA, also set:

HA_ENABLED=true
SWARM_MODE=true
Why SWARM_MODE=true?

When SWARM_MODE=true, keepalived is skipped — Swarm’s ingress mesh already provides the VIP and failover. The backend reports swarm_mode in HA health/config responses so the UI shows the correct topology.

See the Quick Start environment reference for the full variable list, including the Swarm-specific section.

3. Make Images Available

Images must be present on every node that will run a replica. Either:

Option A — Use a registry (recommended for multi-node):

docker tag corex-api:latest registry.example.com/corex-api:v1.0
docker push registry.example.com/corex-api:v1.0
# Set in .env:
#   SWARM_API_IMAGE=registry.example.com/corex-api:v1.0
#   SWARM_HAPROXY_IMAGE=registry.example.com/corex-haproxy:v1.0
#   SWARM_FRONTEND_IMAGE=registry.example.com/corex-frontend:v1.0

Option B — Load images on each node manually:

# On the build node:
docker save corex-api:latest corex-haproxy:latest corex-frontend:latest | gzip > corex-images.tar.gz
# Transfer and load on each Swarm node:
docker load < corex-images.tar.gz

4. Deploy the Stack

Single-node Swarm

docker stack deploy -c docker-swarm.yml corex

Multi-node Swarm with HA (via deploy.py)

The deploy.py script handles rsync, selective rebuilds, and docker stack deploy:

python3 deploy.py --target swarm \
  --host <manager-ip> --user admin \
  --stack-name corex \
  --registry registry.example.com \
  --image-tag v1.0

Manual HA stack deploy

# Ensure HA_ENABLED=true and SWARM_MODE=true in .env, then:
docker stack deploy -c docker-swarm.yml corex

5. Verify the Stack

docker stack services corex       # list services and replicas
docker stack ps corex              # list tasks (per-replica status)
docker service logs corex_api      # view API logs

All services should show REPLICAS as x/x (e.g. 2/2). A 0/x replica count or FAILED task state indicates a scheduling or health-check failure — inspect with docker service ps --no-trunc <service>.

HA Behavior

When HA_ENABLED=true + SWARM_MODE=true:

ComponentBehavior
HAProxy2 replicas (SWARM_HAPROXY_REPLICAS). Swarm ingress mesh provides the VIP — no keepalived.
Coraza SPOA2 replicas (SWARM_CORAZA_REPLICAS), load-balanced by HAProxy.
ValkeyPrimary + 1 replica (SWARM_VALKEY_REPLICA_REPLICAS) + 3 Sentinels (SWARM_SENTINEL_REPLICAS) for quorum failover.
Stick-table syncHAProxy peers connect via tasks.corex DNS (dnsrr endpoint mode).

Adjust replica counts in .env (the SWARM_*_REPLICAS variables) and redeploy.

Service URLs

After deployment, the services are available at:

ServiceURLNotes
Web GUI (HTTP)http://<host>:3000React frontend
Web GUI (HTTPS)https://<host>:3443React frontend over TLS
APIhttp://<host>:8000FastAPI control plane
HAProxy (HTTP)http://<host>:80Data plane ingress
HAProxy (HTTPS)https://<host>:443Data plane ingress over TLS
HAProxy (HTTP/3)https://<host>:443QUIC/HTTP3 over UDP (443/udp)
HAProxy Statshttp://<host>:8404Stats page (set HAPROXY_STATS_USER/PASS to enable auth)
Data Plane APIhttps://<host>:5555/v3HAProxy Data Plane API (when DATAPLANE_API_ENABLED=true)
HAProxy peertcp://<host>:10000Stick-table replication (dnsrr endpoint mode; open between instances)
CAPTCHAhttp://<host>:3001Cap challenge service (when CAPTCHA enabled)
MCP Gatewayhttp://<host>:8089/mcpTools appear as corex-manager__* (when MCP_GATEWAY_ENABLED=true)
MCP Serverhttp://<host>:8082/mcpDirect MCP server; requires Authorization: Bearer <COREX_MCP_TOKEN>
PostgreSQL<host>:5432Database (bind to 127.0.0.1 in production)

With the ingress mesh, any Swarm node accepts traffic on the published ports and routes to a healthy replica. The peer port (10000) uses endpoint_mode: dnsrr so HAProxy instances discover each other directly for stick-table sync.

Managing the Stack

docker stack services corex       # list services
docker stack ps corex             # list tasks
docker service logs corex_api     # view logs
docker service scale corex_corex=3   # scale HAProxy to 3 replicas
docker stack rm corex              # remove the stack
Removing the stack

docker stack rm corex stops and removes all services and networks. Persistent data on bind mounts (under DATA_DIR) is preserved, but named volumes created by the stack are removed.

Deploy Script Options

The deploy.py Swarm-specific options:

OptionDescriptionDefault
--target swarmUse the Docker Swarm deploy flow
--stack-nameSwarm stack namecorex
--registryContainer registry URL for multi-node image distribution
--image-tagDocker image tag for rebuilt imageslatest

The script shares the same selective-rebuild change detection as the Docker target: a manifest of file hashes is compared against the last deploy, and only services whose files changed are rebuilt. See deploy.md in the corex_manager repo for full details.

Next Steps