Onboard Grafana Alloy via remotecfg
This is the Standards onboarding path for Grafana Alloy: no LinkMesh agent
on the host. You install upstream Alloy and add a small remotecfg block that
pulls config from LinkMesh’s CollectorService. Alloy authenticates with a
per-collector bearer token you mint in the UI.
How it differs from the OpAMP path
Alloy doesn’t use OpAMP for config — it uses its own remotecfg component,
which polls LinkMesh over Connect-RPC. So the auth model is slightly different:
instead of an enrollment token on a WebSocket upgrade, Alloy carries a
per-collector OTLP bearer token that you mint once and paste into the
config. The same token also authenticates the optional own_metrics push.
1. Install Grafana Alloy
sudo mkdir -p /etc/apt/keyringscurl -fsSL https://apt.grafana.com/gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/grafana.gpgecho "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" | sudo tee /etc/apt/sources.list.d/grafana.listsudo apt-get update && sudo apt-get install -y alloysudo tee /etc/yum.repos.d/grafana.repo >/dev/null <<'EOF'[grafana]name=grafanabaseurl=https://rpm.grafana.comenabled=1gpgcheck=1gpgkey=https://rpm.grafana.com/gpg.keyEOFsudo dnf install -y alloyThis installs an alloy systemd service that reads /etc/alloy/config.alloy.
2. Create the collector and mint a token
In the LinkMesh UI: Collectors → + Add Collector, choose the Grafana
Alloy option (a collector in alloy-remotecfg mode). On the new collector’s
detail page, the enrollment banner’s Grafana Alloy tab mints a per-collector
OTLP token and shows the ready-to-paste config. Copy the token (and note
the collector’s id).
3. Write config.alloy
Create /etc/alloy/config.alloy. Point remotecfg.url at the server base
URL — Alloy appends the CollectorService path itself, so do not add
/v1/opamp (that’s the OpAMP endpoint, a different protocol).
logging { level = "info"}
remotecfg { url = "https://linkmesh.example.com" id = constants.hostname poll_frequency = "60s"
// Per-collector bearer token minted in the LinkMesh UI (step 2). // LinkMesh's remotecfg auth accepts ONLY the Bearer scheme — not basic_auth. bearer_token = "<COLLECTOR_OTLP_TOKEN>"}
// ── Optional: own_metrics → LinkMesh, so the topology canvas shows// per-component throughput for this Alloy collector. ───────────────prometheus.exporter.self "default" { }
prometheus.scrape "linkmesh_self" { targets = prometheus.exporter.self.default.targets forward_to = [otelcol.receiver.prometheus.linkmesh.receiver] scrape_interval = "30s"}
otelcol.receiver.prometheus "linkmesh" { output { metrics = [otelcol.exporter.otlphttp.linkmesh.input] }}
otelcol.exporter.otlphttp "linkmesh" { client { endpoint = "https://linkmesh.example.com" headers = { "Authorization" = "Bearer <COLLECTOR_OTLP_TOKEN>", } }}The same token goes in both places: remotecfg.bearer_token (pulling config)
and the own_metrics exporter’s Authorization header (pushing throughput). If
you skip the own_metrics block, config pull still works — you just won’t see
per-component throughput on the canvas.
4. Restart and verify
sudo systemctl restart alloy
# Watch remotecfg fetch its config:sudo journalctl -u alloy -f | grep -i remotecfgIn the LinkMesh UI:
- Collectors — the host appears (mode alloy-remotecfg), status leaves
awaiting_connectionwithin ~60s (one poll interval). - Its Events tab shows
remotecfg_registered, then config delivery. - The topology canvas renders throughput once own_metrics start landing.
Troubleshooting
- 401 /
Unauthenticatedfrom remotecfg — the token is wrong or was rotated. Re-mint on the collector page and updatebearer_token. - Alloy connects but gets no pipeline — confirm the collector has sources and a route configured in LinkMesh; an empty config renders an empty pipeline.
- Nothing on the canvas — the own_metrics block is missing or its
Authorizationtoken differs fromremotecfg.bearer_token; they must match. - More: Enrollment troubleshooting.