Overview

swarmbot.it is an open-source Docker Swarm management platform consisting of two components that work together to provide zero-downtime cluster operations, real-time monitoring, and automatic failover.

Two components

swarmbot Node.js · Express · GraphQL

The central API and dashboard. Stores cluster state in PostgreSQL, exposes a GraphQL API, and coordinates failover when a node goes offline.

swarmagent Rust · bollard · tokio

A lightweight daemon running on each Docker node. Streams host metrics and container events to swarmbot.it every second via POST /events.

Key benefits

  • Zero Downtime: Docker Swarm automatically reschedules tasks when a node fails — Swarmbot surfaces it live, it doesn't get in the way.
  • No CouchDB, no Redis: Application state (users, registries, cluster config) lives in a single PostgreSQL database. Real-time metrics are stored in InfluxDB.
  • Real metrics: CPU, RAM, disk, and per-container statistics updated every second.
  • Kubernetes support: K3s/K8s cluster management in addition to Docker Swarm.
  • Open source: MIT-licensed, self-hosted, no telemetry.

swarmbot.it requires Docker Engine 20.10+ with Swarm mode initialized. Run docker swarm init on your manager node before starting.

Architecture

The system follows a hub-and-spoke model: Swarmagent instances on each node push data to the central swarmbot.it API, which stores application state in PostgreSQL, writes real-time metrics to InfluxDB, and serves both to the Angular dashboard via GraphQL.

Swarmagent (Node 1)
Swarmagent (Node 2)
swarmbot.it API
Express + Apollo GraphQL
PostgreSQL (app state)
InfluxDB (metrics)
Swarmagent (Node N)
Angular Dashboard
← GraphQL →
POST /graphql
All agents POST to the same /events endpoint · GraphQL over HTTP on port 8080 by default

Event flow

Every second, each Swarmagent instance collects the following data from the local Docker daemon and sends it as a single JSON payload to POST /events on swarmbot.it:

  • Host metrics: CPU usage (%), memory usage (%), disk usage (%), disk total bytes
  • Container metrics: Per-container CPU %, memory %, container name, state
  • Swarm metadata: Node ID, node hostname, Docker Swarm role (manager/worker)
  • Docker events: Container start/stop/die/health-status events

swarmbot.it writes host and container metrics to InfluxDB as time-series points, and records a lightweight daily count snapshot (stacks/services/tasks) to the metrics_snapshots table in PostgreSQL. Dashboard charts query InfluxDB directly through the metricsSeries GraphQL field.

Installation

Follow these steps to get swarmbot.it running in your environment. Total time: approximately 5 minutes.

Prerequisites

  • Docker Engine 20.10+ with Swarm mode active
  • Node.js 20+ (for swarmbot.it API and dashboard)
  • PostgreSQL 14+ (or use the Docker command below)
  • InfluxDB 1.8.x (required for real-time metrics — or use the Docker command below)
  • Rust 1.75+ (only needed to build Swarmagent from source)

Step 1 — Initialize Docker Swarm

bash
# Only needed if Swarm is not already initialized
docker swarm init

# Verify your node is a manager
docker info | grep -i swarm
# Swarm: active
# NodeID: abc123xyz...

Step 2 — Start PostgreSQL and InfluxDB

bash
# Using Docker (skip if you have an existing PostgreSQL)
docker run -d --name swarmbot-postgres \
  -e POSTGRES_USER=swarmbot \
  -e POSTGRES_PASSWORD=swarmbot \
  -e POSTGRES_DB=swarmbot \
  -p 5432:5432 \
  --restart unless-stopped \
  postgres:16

# Verify it's running
docker ps | grep postgres
# abc123  postgres:16  ...  0.0.0.0:5432->5432/tcp  swarmbot-postgres

# InfluxDB (required for real-time metrics)
docker run -d --name swarmbot-influxdb \
  -e INFLUXDB_DB=swarmbot \
  -p 8086:8086 \
  --restart unless-stopped \
  influxdb:1.8

Step 3 — Clone and install swarmbot.it

bash
git clone https://github.com/swarmbot-it/swarmbot
cd swarmbot

# Install all workspace dependencies
npm install

Step 4 — Configure the environment

apps/api/.env.development
# PostgreSQL connection string
SWARMBOT_DB=postgresql://swarmbot:swarmbot@localhost:5432/swarmbot

# InfluxDB
SWARMBOT_INFLUXDB=http://localhost:8086
SWARMBOT_INFLUXDB_TOKEN=swarmbot-influx-dev-token

# API port
SWARMBOT_PORT=8080

# Set to false to use real Docker (true = mock data)
SWARMBOT_MOCK=false

# CORS — comma-separated allowed origins
SWARMBOT_ALLOWED_ORIGINS=http://localhost:4200,http://YOUR_IP:4200

# Optional — override the auto-generated bootstrap admin credentials
SWARMBOT_BOOTSTRAP_ADMIN=admin
SWARMBOT_BOOTSTRAP_PASSWORD=swarmbot

Step 5 — Start the API

bash
npm run dev:api

# {"msg":"Starting Swarmbot","port":8080}
# {"msg":"Postgres connected"}
# {"msg":"Migration applied","migration":"001_initial"}
# {"msg":"Bootstrap admin user created","username":"admin"}
# {"msg":"InfluxDB connected"}
# {"msg":"Swarmbot listening","port":8080}

Step 6 — Start the dashboard

bash
npm run dev:web

# Angular Live Development Server is listening on localhost:4200
# Open your browser on http://localhost:4200/

# To expose on LAN (access from other machines):
cd apps/web && npx ng serve --host 0.0.0.0 --port 4200

Install Swarmagent (Rust)

Swarmagent must be built and run on each Docker node you want to monitor.

bash
git clone https://github.com/swarmbot-it/swarmagent
cd swarmagent

# Build (release mode)
cargo build --release

# Configure and run — swarmagent is push-only, it opens no listening port
export SWARMBOT_URL=http://<your-swarmbot-ip>:8080
export STATS_FREQUENCY=30  # seconds

./target/release/swarmagent

# INFO Starting Swarmbot
# INFO Waiting for Swarmbot…
# INFO Swarmbot OK
# INFO Event collector started.
# INFO Stats collector started.

Alpine Linux / musl: Swarmagent must be compiled natively — prebuilt glibc binaries will not work on Alpine. Ensure musl-dev and the Rust toolchain are installed via apk add rust cargo musl-dev.

Default login

Default credentials
Username: admin
Password: swarmbot

# Set via SWARMBOT_BOOTSTRAP_ADMIN / SWARMBOT_BOOTSTRAP_PASSWORD.
# Change immediately after first login!

Configuration

All swarmbot.it configuration is done via environment variables, loaded from apps/api/.env.development in development or standard env vars in production.

swarmbot.it (API) variables

VariableDefaultDescription
SWARMBOT_DB postgres://localhost:5432/swarmbot PostgreSQL connection string for application state (users, registries, cluster config).
SWARMBOT_INFLUXDB unset Base URL of the InfluxDB instance used for real-time metrics.
SWARMBOT_INFLUXDB_TOKEN unset Auth token for InfluxDB.
SWARMBOT_PORT 8080 TCP port for the HTTP/GraphQL API server.
SWARMBOT_MOCK false When true, uses a mock Docker engine instead of the real Docker socket. Useful for UI development without a real cluster.
SWARMBOT_ORCHESTRATOR auto Backend selection: swarm, kubernetes, or auto-detected.
SWARMBOT_ALLOWED_ORIGINS http://localhost:4200, :8080, :8081 Comma-separated list of allowed CORS origins. Add your dashboard's LAN address here if accessing remotely.
SWARMBOT_BOOTSTRAP_ADMIN / SWARMBOT_BOOTSTRAP_PASSWORD admin / swarmbot Credentials for the admin user created on first boot, if no users exist yet.
SWARMAGENT_SHARED_SECRET unset Opt-in shared secret required from Swarmagent as X-Agent-Token on POST /events. Unset means no auth is enforced.

The JWT signing secret is generated automatically on first boot and stored in the app_secrets table — there is no env var to configure it.

Swarmagent variables

VariableDefaultDescription
SWARMBOT_URL derived from EVENT_ENDPOINT Base URL of the swarmbot.it API. Swarmagent polls this on startup until it becomes available.
AGENT_MODE auto Force docker or kubernetes mode, or auto-detect the orchestrator.
STATS_FREQUENCY 30 How often (in seconds, minimum 1) to collect and send metrics.
SWARMAGENT_SHARED_SECRET unset When set, sent as X-Agent-Token on every request to swarmbot.it. Must match the API's own SWARMAGENT_SHARED_SECRET.
DOCKER_HOST unix:///var/run/docker.sock Docker socket path, read by the underlying Docker client library. Useful when running Swarmagent in a container.

Swarmagent is push-only — it opens no listening port and has no HTTP health-check endpoint of its own.

API Reference

swarmbot.it exposes a GraphQL API at POST /graphql. Use the GraphQL Playground at http://localhost:8080/graphql (in development) for interactive exploration.

Authentication

All API requests require a Bearer token in the Authorization header. Obtain a token by POSTing to the REST auth endpoint with HTTP Basic credentials:

bash
# POST /login (HTTP Basic auth)
curl -X POST http://localhost:8080/login \
  -u admin:swarmbot

# {"token":"eyJhbGciOiJIUzI1NiIsInR5..."}

# Use the token in GraphQL requests
curl -X POST http://localhost:8080/graphql \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"query":"{ nodes { id hostname role cpu mem disk } }"}'

Queries

GraphQL — nodes
# Get all Swarm nodes with current metrics
query {
  nodes {
    id
    hostname
    role            # "manager" | "worker"
    availability    # "active" | "pause" | "drain"
    cpu             # current CPU usage %
    mem             # current memory usage %
    disk            # current disk usage %
  }
}
GraphQL — services
# List all Swarm services; tasks are queried separately
query {
  services {
    id
    name
    image
    replicasRunning
    replicasTotal
    status
    stack
  }
  tasks {
    id
    serviceName
    nodeHostname
    status          # "running" | "failed" | "shutdown" | "starting"
  }
}
GraphQL — metrics
# Time-series metrics for the whole cluster (backed by InfluxDB)
query ClusterMetrics($input: MetricsSeriesInput!) {
  metricsSeries(input: $input) {
    labels    # ["15m ago", "14m ago", ...]
    cpu       # [42.1, 43.5, ...]
    mem
    disk
  }
}

# Variables: { "input": { "range": "1h", "resolution": "medium" } }
# range: any duration string · resolution: "low" | "medium" | "high"
# add "nodeId" to input to scope the series to a single node

Mutations

GraphQL — mutations
# Deploy a new service (registry must reference an existing Registry id)
mutation {
  createService(input: { name: "myapp", image: "nginx:latest", registry: "docker-hub", replicas: 3 }) {
    id
    name
    replicasTotal
  }
}

# Scale a service
mutation {
  scaleService(id: "abc123", replicas: 5)
}

# Remove a service
mutation {
  removeService(id: "abc123")
}

Swarmagent

Swarmagent is a Rust daemon built with bollard (Docker API) and tokio (async runtime). It runs on each Docker node and streams data to swarmbot.it.

What it monitors

  • Host CPU: System-wide CPU usage percentage via /proc/stat or Docker stats API
  • Host memory: Total, used, and available RAM from Docker info
  • Disk: Total and used disk space for the Docker root directory
  • Containers: Per-container CPU and memory from the Docker stats stream
  • Events: Real-time Docker event stream (start/stop/die/health events)
  • Swarm info: Node ID, hostname, Swarm role and state

POST /events payload

JSON
// Envelope: { "type": "stats" | "event", "message": <payload> }
{
  "type": "stats",
  "message": {
    "id":            "mqyml912ulvx2m7nyijmdmuf3",
    "hostname":      "Legion",
    "orchestrator":  "swarm",
    "cpu":            { "usedPercentage": 12.4, "cores": 16 },
    "memory":         { "total": 17179869184, "used": 6644629504, "usedPercentage": 38.7, "free": 10535239680 },
    "disk":           { "total": 512110190592, "used": 266770219008, "usedPercentage": 52.1, "free": 245339971584 },
    "containers": [
      {
        "name":             "nginx.1.abc123",
        "id":               "a1b2c3d4e5f6",
        "cpuPercentage":    0.8,
        "memory":           128.4,
        "memoryLimit":      512,
        "memoryPercentage": 25.1,
        "pids":             3
      }
    ],
    "engineVersion": "27.3.1",
    "apiVersion":    "1.44",
    "agentVersion":  "0.1.2"
  }
}

Swarmagent is push-only — it has no HTTP server, no health endpoint, and opens no listening port. It only makes outbound requests to swarmbot.it.

Security

Authentication

swarmbot.it uses JWT tokens. The signing secret is generated automatically on first boot and stored in the app_secrets database table — there is nothing to configure. Revoked tokens are recorded in the revoked_jti table and rejected on every subsequent request until they would have expired anyway.

Password hashing

Passwords are hashed with PBKDF2. Legacy SHA-256 digests are automatically upgraded on next login.

CORS

The API only accepts requests from origins listed in SWARMBOT_ALLOWED_ORIGINS. Set this to your exact dashboard URL — wildcard origins are not supported.

Encryption at rest

Sensitive values (registry passwords, API tokens) are encrypted with AES-256-GCM before being stored in PostgreSQL. The encryption key is derived from the auto-generated JWT secret.

Production checklist: Change the default admin password (SWARMBOT_BOOTSTRAP_PASSWORD), run behind a reverse proxy with TLS, and restrict SWARMBOT_ALLOWED_ORIGINS to your exact dashboard domain.

Network security

  • Swarmagent → swarmbot.it communication should be on a private/overlay network
  • The swarmbot.it API port (8080) should not be publicly exposed — use a reverse proxy
  • All short-lived tokens (SLTs) expire in 5 minutes

Troubleshooting

Common issues and their solutions.

SymptomCauseFix
Login fails with 401 Wrong credentials or expired token Use admin / swarmbot on first boot. Check API logs for JWT error details.
API returns "Connecting to PostgreSQL" then exits PostgreSQL not reachable Check SWARMBOT_DB in .env and verify PostgreSQL is running on port 5432.
Dashboard shows "0 nodes" Docker Swarm not initialized or MOCK=true Run docker swarm init and set SWARMBOT_MOCK=false.
Swarmagent: "node_id = unknown" Docker Swarm not initialized on this node Run docker swarm init (manager) or docker swarm join (worker).
CORS error in browser console Dashboard origin not whitelisted Add your exact dashboard URL to SWARMBOT_ALLOWED_ORIGINS, restart API.
Port 8080 already in use on restart Stale Node.js process kill -9 $(lsof -t -i:8080) then restart.
Swarmagent binary fails on Alpine Prebuilt binary uses glibc, Alpine uses musl Build from source: apk add rust cargo musl-dev && cargo build --release
Metrics not appearing in charts Swarmagent not connected, wrong SWARMBOT_URL, or InfluxDB unreachable Check SWARMBOT_URL in Swarmagent env and SWARMBOT_INFLUXDB on the API. Verify the API can reach InfluxDB: curl $SWARMBOT_INFLUXDB/ping

Getting logs

bash
# API logs (structured JSON)
npm run dev:api 2>&1 | tee /tmp/swarmbot-api.log

# Swarmagent logs (human-readable tracing)
RUST_LOG=info ./target/release/swarmagent 2>&1 | tee /tmp/swarmagent.log

# Check application state in PostgreSQL
psql postgresql://swarmbot:swarmbot@localhost:5432/swarmbot \
  -c "SELECT username, role, last_login_at FROM users;"

# Check the last hour of CPU metrics for a node in InfluxDB
curl -G http://localhost:8086/query \
  --data-urlencode "db=swarmbot" \
  --data-urlencode "q=SELECT * FROM cpu WHERE time > now() - 1h"

For bug reports and feature requests, open an issue on GitHub. Include the API log output and your environment (OS, Docker version, Node.js version).