EvoHub DocsEvoHub Docs Sign in

Install the agent on a VM

Use with AI
View as MarkdownThis page as plain text, for pasting into an AI tool Open in ClaudeAsk Claude questions about this page Open in ChatGPTAsk ChatGPT questions about this page
Connect to Cursor / VS Code / ClaudeSearch and read these docs from your AI tool (MCP server)

MCP server URL

https://docs.evohub.io/mcp

Claude Code

claude mcp add --transport http evohub-docs https://docs.evohub.io/mcp

Claude (claude.ai and Claude Desktop): Settings → Connectors → Add custom connector, and paste the URL above.

Claude Desktop — claude_desktop_config.json

{
  "mcpServers": {
    "evohub-docs": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://docs.evohub.io/mcp"
      ]
    }
  }
}

Cursor — ~/.cursor/mcp.json

{
  "mcpServers": {
    "evohub-docs": {
      "url": "https://docs.evohub.io/mcp"
    }
  }
}

VS Code — .vscode/mcp.json

{
  "servers": {
    "evohub-docs": {
      "type": "http",
      "url": "https://docs.evohub.io/mcp"
    }
  }
}

On a Linux VM the agent runs under systemd and describes the machine it runs on: the host, its systemd services, its Docker containers, its listening ports and, if you turn it on, its installed packages. This is host mode, EVOHUB_PLATFORM=vm, which the unit file sets for you.

Before you start, create the environment in Catalog and an enrollment token for it, choosing Linux VM under Where it runs; see Enrollment. One environment can hold many VMs, each with its own agent, and it is billed once.

Install

The agent is published as static binaries for linux/amd64 and linux/arm64, with its systemd unit, beside the image on ghcr.io, one tag per file. Fetching them needs only curl and sha256sum.

The console's New agent dialog shows the complete install for your version, with the token and the agent's name filled in, as One command or as Keep it out of shell history. It runs these steps:

Fetch the binary and the unit

Download the release's binary for the machine's architecture and the evohub-agent-host.service unit, each checked against the digest its manifest names.

Install the binary and create the agent's user

sudo install -m 0755 evohub-agent /usr/local/bin/evohub-agent
sudo useradd --system --home-dir /nonexistent --shell /usr/sbin/nologin evohub-agent

Store the enrollment token

sudo install -d -m 0700 -o evohub-agent /etc/evohub-agent
sudo install -m 0600 -o evohub-agent /dev/stdin /etc/evohub-agent/enrollment-token
# paste the token, press Enter, then Ctrl-D

Install and start the unit

sudo cp evohub-agent-host.service /etc/systemd/system/
sudo systemctl daemon-reload && sudo systemctl enable --now evohub-agent-host

Check it and remove the token

journalctl -u evohub-agent-host -f

Once the agent logs enrolled, delete the token file: sudo rm /etc/evohub-agent/enrollment-token.

What the machine runs appears in Catalog within a few minutes, under the provider host, and the agent shows as Reporting under Organization → Agents.

Verify a release

The fetch checks that each file is byte for byte the one its manifest names. That proves integrity, not origin. To know the file is EvoHub's, verify the manifest's Sigstore signature by the digest the fetch printed, not by the tag:

cosign verify ghcr.io/evolutionarysynchronization/evohub-agent@sha256:<manifest digest> \
  --certificate-identity-regexp '^https://github.com/EvolutionarySynchronization/evohub-agent/\.github/workflows/release\.yml@refs/tags/v' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

The binaries' SHA256SUMS is signed the same way (SHA256SUMS.sigstore.json, checked with cosign verify-blob --bundle).

Settings

Settings go in a drop-in for the unit (sudo systemctl edit evohub-agent-host), under [Service]:

[Service]
Environment=EVOHUB_AGENT_NAME=web-01
Environment=EVOHUB_HOST_PACKAGES=true
Variable Default
EVOHUB_AGENT_NAME the hostname How the agent appears in EvoHub
EVOHUB_API_URL https://api.evohub.io EvoHub's API, scheme and host only
EVOHUB_HOST_PACKAGES false Report installed packages (dpkg-query or rpm)
EVOHUB_DOCKER_SOCKET /var/run/docker.sock Where to list containers; empty turns containers off
EVOHUB_SWEEP_INTERVAL 5m How often to run a full sweep, 1m to 24h
EVOHUB_HEARTBEAT_INTERVAL 1m How often to send a heartbeat, 10s to 3m
HTTPS_PROXY, NO_PROXY none An egress proxy

Restart the unit after changing them: sudo systemctl restart evohub-agent-host.

Docker containers

The agent lists Docker containers only if it can reach Docker's socket. Add SupplementaryGroups=docker to the drop-in to allow it.

Warning

Membership of the docker group is equivalent to root on that machine: whoever controls the agent could then start a privileged container, and the unit's sandbox no longer protects the machine from it. The agent only lists containers. If that matters to you, put a read-only proxy for Docker's API (one that allows GET /containers/json only) in front of the socket and point EVOHUB_DOCKER_SOCKET at it.

How it runs

The unit runs the agent as its own system user, evohub-agent, with a read-only view of the system: the only writable place is its private state directory, where it keeps its key (/var/lib/evohub-agent/identity.json, mode 0600). It needs outbound HTTPS and nothing else.

It sees which user owns each listening socket, not which process, so a port is put down to the one service running as that user, and left unattributed when that user is root or runs several services. Running the agent as root would name every port's process; that is your decision, not the unit's default.

What it reads and sends

It reads For
/etc/machine-id The host's identity; every resource is named host://<machine id>/<Kind>/<name>
/etc/os-release, /proc/sys/kernel, /proc/cpuinfo, /proc/meminfo, /proc/stat, /proc/mounts What the machine is
/sys/class/dmi/id/sys_vendor, /var/lib/cloud/data/instance-id, /sys/class/dmi/id/board_asset_tag Which cloud, and its instance ID; no metadata endpoint is called
systemctl list-units, list-unit-files, show Its services
/proc/net/tcp, tcp6, udp, udp6, /etc/passwd (user names and IDs only) What listens, and as which user
/proc/<pid>/fd, comm, cgroup Which process holds a socket, where the agent may read it (as root)
Docker's socket, only if you allow it Its containers
dpkg-query or rpm, only with EVOHUB_HOST_PACKAGES=true Installed packages

It sends:

  • Host: hostname, distribution, kernel, architecture, CPU count, memory, each local disk's mount point, filesystem and size (a network mount's server name, not its path), IP addresses, boot time, cloud and instance ID.
  • Service, a systemd unit that is enabled, running, starting or failed: its unit file's path, whether it is enabled, its type, its description, the path of the binary it starts and the user it runs as. Never its arguments, its environment or its drop-ins.
  • Container: its name, image and image digest, published ports, and the Compose project and service it belongs to. No command, environment, mounts or other labels.
  • ListeningPort, one per protocol and port: the addresses it is bound to, and the service, container or process name that listens, when the agent can tell. Never a command line.
  • Packages, if turned on: each installed package's name, version and architecture.
  • Live state, every minute: whether the host, each service and each container runs as it should, and the name of what is wrong (Failed, Restarting, Unhealthy, Error).

It never reads or sends file contents, logs, shell history, anything from a home directory, any process's environment variables or command-line arguments, or what a service or container is doing (connections, traffic, metrics). Every document goes through the same redaction as a Kubernetes object before it is hashed or sent.

In Catalog, each container and non-system service is an application of its own (a Compose project is one application), a port is linked to what listens on it, and services and containers are shown running on their host.

Upgrade

The agent never upgrades itself. To upgrade, fetch the new version's binary as in the install, replace /usr/local/bin/evohub-agent with it, and restart the unit:

sudo install -m 0755 evohub-agent /usr/local/bin/evohub-agent
sudo systemctl restart evohub-agent-host

Its key stays in its state directory, so it keeps its identity and history.

Uninstall

sudo systemctl disable --now evohub-agent-host
sudo rm /etc/systemd/system/evohub-agent-host.service
sudo rm -rf /etc/systemd/system/evohub-agent-host.service.d /etc/evohub-agent /var/lib/evohub-agent
sudo rm /usr/local/bin/evohub-agent
sudo systemctl daemon-reload

Removing /var/lib/evohub-agent deletes the agent's key. Then revoke the agent under Organization → Agents; until you do, it stays enrolled. What it reported stays in Catalog and is shown as stale.

Last updated Powered by