--- title: Rolling ClawMetry out to a fleet description: Silent install, virtual desktop images, shared Linux hosts, enrollment, proxy and CA, and a self-hosted server in your tenant, with what each was tested on. keywords: clawmetry fleet install, clawmetry intune, clawmetry azure virtual desktop, clawmetry vdi, clawmetry ansible, clawmetry self-hosted azure aws, silent install agent observability eyebrow: Enterprise --- # Rolling ClawMetry out to a fleet This is the one place for fleet install instructions. Other pages link here instead of repeating them. Every path below says what it was tested on, and anything without a tested configuration is marked **not tested**. :::note Which release you need The fleet install command (`clawmetry service`) and the fleet recipes ship in ClawMetry 0.12.880 and later. Signed self-hosted server images are published from 0.12.878. Check a machine with `clawmetry service --help`. If that command is unknown, upgrade before you follow the fleet sections. ::: ## 1. Choose a deployment mode The collector always runs on the machine where the agent runs. What you choose is where its data goes. | Mode | Where session data goes | Credential needed | Details | |---|---|---|---| | Local only | Stays on each machine | None | [Deployment modes](/docs/start/deployment-modes/) | | Managed cloud | Encrypted snapshot to ClawMetry Cloud | Account key, per user | [Encryption](/docs/cloud/encryption/) | | Your own server | Your self-hosted server, in your network | A node token you issue | [Section 11](#11-run-the-self-hosted-server-in-your-own-cloud-tenant) | | No collector | The runtime's own OpenTelemetry export, straight to your server | A gateway token | [OpenTelemetry ingest](/docs/runtimes/opentelemetry/) | Start local only. It needs no credential and you can connect later without losing history. ## 2. Tested environments Tested means an automated run installed the recipe and checked the result on that runner image. The fleet recipes were run on 15 September 2026 against the merged code that ClawMetry 0.12.880 contains, and the self-hosted checks ran the same day against the published 0.12.880 image. Nothing here was run on a real virtual desktop host. | Environment | Status | Tested on | What was checked | |---|---|---|---| | Shared Linux host, Ansible recipe | Tested | GitHub-hosted `ubuntu-24.04` runner, the image's system Python (`/usr/bin/python3`) | Two local users, each with a collector running as that user with no login session. Neither user can read the other's data. Uninstall removes the unit. | | Windows host, Intune PowerShell script | Tested at registration level | GitHub-hosted `windows-2025-vs2026` runner (Windows Server 2025), Python 3.11 | One logon task for the built-in Users group, least privilege, one instance per session. Desktop users cannot write the shared install. Uninstall removes the task. Two users signed in at once was **not** observed. | | Self-hosted server container | Tested on the published 0.12.880 image | `ubuntu-24.04` (amd64) and `ubuntu-24.04-arm` (arm64) runners | Pulled by digest with no registry credentials. Keyless signature and per-platform SBOM verified. The image contains no Pro plugin. An event survives a container restart. Export refusing a request with no credentials was checked on the branch build only. | | Azure Virtual Desktop, multi-session | Not tested | None | None | | Windows 11 Enterprise multi-session | Not tested | None | None | | Citrix Virtual Apps and Desktops | Not tested | None | None | | FSLogix profile containers or roaming profiles | Not tested | None | None | | Microsoft Configuration Manager (SCCM), Group Policy startup scripts | Not tested | None | The Intune script is plain PowerShell but was run only as shown above. | | Jamf or any macOS fleet tool | No recipe | None | None | | Agents inside WSL or containers on a desktop | Not tested | None | None | | Azure Container Apps, AWS ECS, Kubernetes, Helm | Not available | None | None | | Air-gapped installation | Not verified | None | None | | Reboot and network outage recovery, on either OS | Not tested | None | None | If your environment is marked not tested, we can run a compatibility assessment with you on one agreed profile before any wider rollout. Email [enterprise@clawmetry.com](mailto:enterprise@clawmetry.com). It is an assessment, not a guarantee that the profile is supported. ## 3. How the fleet collector runs One collector per user, running **as that user**. It reads only that user's agent files and keeps its data in that user's profile. A single privileged service that reads every profile was rejected: it could read every user's content and would attribute all of it to one machine. | | Linux | Windows | |---|---|---| | Registration | Per-user systemd unit plus logind linger | One logon task for the built-in Users group | | Runs as | The user | Each signed-in user, least privilege | | After logoff | Keeps running | Stops with the session. The logon task starts it again at the next sign-in, which was not observed on a real host | | Data directory | `~/.clawmetry`, readable only by the user | `%USERPROFILE%\.clawmetry`, profile permissions (not checked by ClawMetry) | | Updates | Re-run the recipe with a new pin | Re-run the recipe with a new pin | Check what a machine actually got: ```bash clawmetry service status # add --json for scripts ``` It reports whether collection survives logoff and why, whether the data directory is private, and whether automatic updates are on. On Windows it never reports that collection survives logoff. ## 4. Windows shared hosts and virtual desktop images The recipe is `deploy/fleet/intune/Install-ClawMetry.ps1` in the [ClawMetry repository at v0.12.880](https://github.com/vivekchand/clawmetry/tree/v0.12.880/deploy/fleet). It must run elevated. Intune platform scripts run as SYSTEM, which is enough. It creates `C:\Program Files\ClawMetry\venv`, installs the package you pin, and registers the all-users logon task. ```powershell powershell.exe -ExecutionPolicy Bypass -NoProfile -File Install-ClawMetry.ps1 -Package "clawmetry==" ``` Exit code `0` means the task is registered and `1` means it is not, so Intune reports a failed install correctly. Before you use it on an image: - **Python must be installed for all users**, for example under `C:\Program Files`. Every user's collector runs through that interpreter. The script uses `python` from the path unless you pass `-PythonExe`, and refuses a Python that lives inside a user profile. - **A console window may appear at sign-in.** The task starts `python.exe`, which is a console program, and closing the window stops collection until the next sign-in. This has not been checked on a real multi-session host. - **The install directory is locked down.** The script gives SYSTEM and Administrators full control and Users read and execute only, so no desktop user can change code that every other user's collector runs. - **Do not enroll inside the image.** The script takes no credential. See [section 7](#7-enroll-without-putting-a-secret-in-the-image). - **Cloned images are not guaranteed a fresh machine identity yet**, and user attribution across profile roaming has not been validated. ### One machine without Intune `clawmetry service install --all-users` registers the same logon task, but it **does not check either precondition** the script enforces. It points every user's task at the interpreter you run it from, as-is. Use it only when both of these are true: - **It runs from a virtual environment created from a machine-wide Python**, for example under `C:\Program Files`, and never from a Python inside your own profile. Otherwise other users' collectors fail at sign-in and nothing reports it. - **Only administrators can write that directory.** Otherwise any user can change code that runs as every other user who signs in. From an elevated prompt, after creating that environment: ```powershell & "$env:ProgramFiles\ClawMetry\venv\Scripts\clawmetry.exe" service install --all-users ``` If you are not sure both are true, run the script instead. ## 5. Linux shared and headless hosts The recipe is `deploy/fleet/ansible/clawmetry.yml`. It creates `/opt/clawmetry-fleet`, installs the pinned package, enables linger for each listed user and registers each user's collector. ```bash ansible-playbook -i inventory deploy/fleet/ansible/clawmetry.yml \ -e '{"clawmetry_users": ["alice", "bob"]}' -e clawmetry_package=clawmetry== ``` The shared environment is installed under `umask 022` and then forced to root ownership with no group or world write, so no user can change code another user's collector runs. If you install some other way, check this yourself. One user on a headless server can do the same without Ansible: ```bash clawmetry service install ``` If the host refuses linger, the command exits `1` and prints the administrator command to run (`sudo loginctl enable-linger `). It does not claim the collector will outlive logout. That refusal path is covered by unit tests only. To manage the unit files yourself instead, see [Run it as a service](/docs/config/service/). ## 6. macOS There is no macOS fleet recipe, and `clawmetry service install --all-users` is not supported on macOS. Install per user with the standard [installer](/docs/start/install/). A Jamf deployment has not been built or tested. ## 7. Enroll without putting a secret in the image Local-only collection needs no credential at all. **Never put an enrollment key into a golden image, a script file or a world-readable location.** Anyone who copies the image or the script copies the key. Neither fleet recipe accepts a key, and the product's tests fail if a key-shaped string appears in them. To connect, run this **as each user at sign-in**, from a user-context deployment step that reads the key from your secret store: ```bash clawmetry connect --key "$CLAWMETRY_KEY" ``` To send data to your own server instead of ClawMetry Cloud, point the node at it first. The key is a node token you issued on that server: ```bash CLAWMETRY_ENDPOINT=https://clawmetry.internal.example.com \ clawmetry connect --key "$CLAWMETRY_NODE_TOKEN" ``` Know the limits before you plan around them: - The ClawMetry Cloud key is **account scoped**. Scoped, per-host enrollment keys are not available yet. - Rotate a cloud key by connecting again with the new key. On your own server, add the new token to the server, reconnect the nodes, then remove the old token. ## 8. Corporate proxy and custom certificate authority The collector uses the operating system's trust store on Python 3.10 and newer, so a corporate root CA your IT team already pushed usually just works. It reads `HTTPS_PROXY`, `HTTP_PROXY` and `NO_PROXY` when the collector starts. ```bash export HTTPS_PROXY=http://proxy.corp.example:8080 export NO_PROXY=localhost,127.0.0.1 export CLAWMETRY_CA_BUNDLE=/etc/ssl/certs/corporate-ca.pem # only if the trust store lacks it clawmetry doctor ``` `clawmetry doctor` checks DNS, TCP, the proxy, TLS and a heartbeat, and names the certificate authority that is re-signing your traffic. Set these variables where the collector starts, not only in your terminal, then restart it. Full detail: [Ports and networking](/docs/config/networking/). ## 9. Local-only and offline operation ```bash export CLAWMETRY_OFFLINE=1 # no install ping, update check or entitlement probe ``` Collectors installed by either fleet recipe **never update themselves**. They detect that the signed-in user cannot write the install and skip automatic updates, so they never exit to retry an upgrade that cannot succeed. A per-user install the user owns keeps automatic updates unless you set `CLAWMETRY_AUTO_UPDATE=0`. See [Upgrades](/docs/ops/upgrades/). An offline or air-gapped installation has not been verified. `CLAWMETRY_OFFLINE` stops outbound calls from a collector that is already installed; it does not make the install itself work without a package index. ## 10. OpenTelemetry and SIEM wiring - **Send agent activity to your observability backend** with OTLP export. See [OpenTelemetry ingest](/docs/runtimes/opentelemetry/) and [Exports](/docs/data/export/). - **Skip the collector** for runtimes that export OpenTelemetry themselves, by pointing them at your own server. See [OpenTelemetry ingest](/docs/runtimes/opentelemetry/). - **Forward events to a syslog SIEM** in CEF or JSON with `CLAWMETRY_SIEM_HOST`, `CLAWMETRY_SIEM_PORT`, `CLAWMETRY_SIEM_PROTOCOL` and `CLAWMETRY_SIEM_FORMAT`. This is an Enterprise feature. It has not been tested against a live SIEM receiver for this guide. ## 11. Run the self-hosted server in your own cloud tenant The self-hosted server is one container that receives every node's heartbeats, sessions and events, and serves a fleet page and an audit export. It runs on any Linux host with Docker Compose, including a virtual machine inside your own Azure or AWS account. Detailed per-session views stay on each node. The image is `ghcr.io/vivekchand/clawmetry:`, for `linux/amd64` and `linux/arm64`, built from the published package with no Pro plugin inside. Deploy it **by digest**, and verify it before you run it: ```bash IMAGE=ghcr.io/vivekchand/clawmetry:@sha256: cosign verify "$IMAGE" \ --certificate-identity https://github.com/vivekchand/clawmetry/.github/workflows/container-image.yml@refs/heads/main \ --certificate-oidc-issuer https://token.actions.githubusercontent.com ``` The release pipeline opens a pull request that pins `deploy/self-hosted/docker-compose.yml` to a digest, and only after that digest has passed signature, SBOM and restart checks. If the file you have still has a `build:` block, no verified pin has been merged yet and Compose builds from your checkout. Steps on a VM in your tenant: 1. Put the node tokens and the admin user and password in your secret store (for example Azure Key Vault or AWS Secrets Manager) and write them into `.env` at deploy time. Never commit them. 2. `docker compose up -d` from `deploy/self-hosted/`. 3. Terminate TLS in front of port 8900. The container speaks plain HTTP. 4. Connect each node as shown in [section 7](#7-enroll-without-putting-a-secret-in-the-image). 5. Back up the volume before every upgrade. To roll back, set the previous digest and restore the backup. Only the container on a Docker host was tested, on the runners in [section 2](#2-tested-environments). A VM in Azure or AWS was not run, and none of these is available for the self-hosted server today: - No Azure Container Apps, AWS ECS, Kubernetes or Helm quickstart. - No single sign-on (Entra ID, OIDC or SAML), user directory or roles. - No second server instance and no high availability. - No automated retention or deletion. Nothing is deleted automatically, so size the volume for your event volume. - No non-root image. The full runbook, with backup, restore and the SBOM and provenance checks, is `docs/self-hosting.md` in the [ClawMetry repository at v0.12.880](https://github.com/vivekchand/clawmetry/blob/v0.12.880/docs/self-hosting.md). Licensing: [Plans and entitlements](/docs/ops/plans/). ## 12. Pin, update and roll back - **Pin** an exact `clawmetry==` in either recipe. - **Update** by re-running the recipe with the new pin. Windows collectors pick it up at next sign-in. On Linux, restart each user's `clawmetry-sync` unit. - **Roll back** by re-running the recipe with the previous pin. - **Self-hosted server:** change the digest, `docker compose pull`, then `docker compose up -d`. ## 13. Uninstall Windows, elevated: ```powershell & "$env:ProgramFiles\ClawMetry\venv\Scripts\clawmetry.exe" service uninstall Remove-Item -Recurse -Force "$env:ProgramFiles\ClawMetry" ``` Linux, per user, then once per host: ```bash sudo -u XDG_RUNTIME_DIR=/run/user/ /opt/clawmetry-fleet/bin/clawmetry service uninstall sudo loginctl disable-linger sudo rm -rf /opt/clawmetry-fleet ``` Disconnecting a node stops sync without removing local data. See [Uninstall](/docs/ops/uninstall/). ## 14. Resource use On the Linux runner, each idle collector used about 137 to 149 MB of memory and a lifetime average of about 2.3 to 2.4% of one CPU over its first 64 seconds, which includes startup. That is a reference point from a CI runner with no agent workload, not a sizing figure for a virtual desktop image. Measure on your own image with a real workload before you size a host pool. ## 15. Not covered yet - A Windows collector for users who are not signed in. - Capped, recoverable buffering through a long network outage, with delivery receipts. - Scoped, rotatable enrollment keys, and a fresh machine identity for pooled image clones. - Per-user attribution validated across logoff and profile roaming on a real multi-session host. - Pause, stop and pre-tool controls verified on a multi-session host.