Skip to content

Installation

Swarm ships as three binaries: swarm (CLI client), swarm-server (control-plane daemon), and swarm-agent (runs on each VM — the server deploys it automatically, you never install it by hand).

Requires Go 1.25+.

Terminal window
make build-all

This produces three binaries in dist/:

Binary Purpose
swarm CLI client
swarm-server Control-plane server
swarm-agent-linux-amd64 Agent binary (deployed to VMs)

To build individually:

Terminal window
make build # CLI only
make build-server # Server only
make build-agent # Agent only (linux/amd64)

Install the CLI to your $GOPATH/bin:

Terminal window
make install
Terminal window
brew tap hyperengineering/tap
brew install swarm

swarm and swarm-server are published as Debian packages via the GPG-signed Gemfury apt repository:

Terminal window
curl -fsSL https://apt.fury.io/neuralmux/gpg.key | gpg --dearmor | sudo tee /usr/share/keyrings/neuralmux-keyring.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/neuralmux-keyring.gpg] https://apt.fury.io/neuralmux/ * *" | sudo tee /etc/apt/sources.list.d/neuralmux.list
sudo apt update
sudo apt install swarm swarm-server

The gpg --dearmor step matters: Gemfury serves the key ASCII-armored, which apt cannot use directly (NO_PUBKEY).

swarm-server installs the binaries to /usr/bin, an example config to /etc/swarm/swarm-server.json (never overwritten on upgrade), a systemd unit, and a swarm service user. Start it with:

Terminal window
sudo systemctl enable --now swarm-server

The server image is published to ghcr.io/hyperengineering/swarm-server.

Terminal window
cd packaging/docker
cp ../swarm-server.json.example swarm-server.json
# edit swarm-server.json with your credentials and paths
docker compose up -d

The Compose file mounts:

Mount Container path Purpose
swarm-data volume /var/lib/swarm Persistent registry data
./swarm-server.json /etc/swarm/swarm-server.json Configuration (read-only)
~/.ssh/id_ed25519.pub /etc/swarm/id_ed25519.pub SSH public key (read-only)

The container exposes port 8800 and restarts unless explicitly stopped.

Terminal window
docker run -d \
--name swarm-server \
-p 8800:8800 \
-v /path/to/swarm-server.json:/etc/swarm/swarm-server.json:ro \
-v /path/to/id_ed25519:/etc/swarm/id_ed25519:ro \
-v /path/to/id_ed25519.pub:/etc/swarm/id_ed25519.pub:ro \
-v swarm-data:/var/lib/swarm \
--restart unless-stopped \
ghcr.io/hyperengineering/swarm-server:latest

The image is based on Alpine and runs as a non-root swarm user.

Terminal window
make package-server

This creates dist/swarm-server-linux-amd64.tar.gz containing the server binary, agent binary, systemd unit, installer script, and example configuration. Copy it to the host and run:

Terminal window
tar xzf swarm-server-linux-amd64.tar.gz
cd swarm-server-package
sudo bash install.sh

The installer copies the binaries to /usr/bin, creates the swarm system user, creates /etc/swarm/ and /var/lib/swarm/, places an example config if none exists, and installs the systemd unit. It is idempotent — safe to re-run for upgrades.

The service runs as the swarm user with ProtectSystem=full, NoNewPrivileges=true, and PrivateTmp=true hardening. It restarts on failure after a 5-second delay.

Systemd / bare metal: rebuild the package, copy the tarball, and re-run the installer. The installer never overwrites an existing /etc/swarm/swarm-server.json. Then:

Terminal window
sudo systemctl restart swarm-server

Docker Compose: rebuild and restart:

Terminal window
docker compose build
docker compose up -d

Upgrading from v0.7-beta: the API is HTTPS-only and authenticated (mTLS) since that release. After the upgrade the first server start prints a one-time enrollment token — re-enroll with swarm login --token <token> and point the CLI at the https:// URL (swarm config set server https://…).

Configure the server — see Server setup.