Skip to content

Onboard an OpenTelemetry Collector via OpAMP

This onboards otelcol-contrib via the OpAMP runtime: two upstream OTel binaries run on the host — opampsupervisor (handles the OpAMP connection to LinkMesh and writes the collector config it receives) and otelcol-contrib (the data plane the supervisor manages). No LinkMesh-specific code on the host.

  • A reachable LinkMesh server (you know its public base URL, e.g. https://linkmesh.example.com).
  • externalUrl set on that server — see Quickstart step 2. It is the endpoint the server offers this collector for its own_metrics push. Without it the collector enrols and processes data normally but reports throughput 0 / CPU 0 / memory 0 / uptime 0 forever, with no error anywhere.
  • A Linux host where you can install binaries and edit a config file.
  • The OpAMP endpoint reachable from the host over WebSocket — same host/port as the web UI, path /v1/opamp.

LinkMesh ships an installer that downloads both binaries, writes the supervisor config, and starts the systemd unit. This is what the Add Collector → OpAMP wizard hands you in the UI.

  1. Get an enrollment token. UI: Collectors → + Add Collector → OpAMP, or Settings → Enrollment Tokens → Create Token. A single-use token enrols one collector and then persists in supervisor.yaml as that host’s durable reconnect credential; an un-redeemed token expires — mint a fresh one if it lapses before you install it.

  2. Run the installer on the host:

    curl -fsSL https://linkmesh.example.com/api/v1/downloads/install-opamp.sh | \
      sudo sh -s -- --token <YOUR_ENROLLMENT_TOKEN>

    The script fetches otelcol-contrib and opampsupervisor from upstream OTel releases (or from the LinkMesh mirror if your server has staged them for air-gapped use), writes /etc/otelcol-supervisor/supervisor.yaml, installs opamp-supervisor.service, and starts it.

  3. Verify in the LinkMesh UI — Collectors shows the host with management mode OpAMP, status Connected within ~30 s.

That’s the whole path for most operators. The manual install below is for hosts where you want explicit control over each step.

  1. Install both binaries. Upstream OTel publishes them under separate release tags — collector here, supervisor under cmd/opampsupervisor:

    OTEL_VERSION=0.153.0
    SUPERVISOR_VERSION=0.135.0
    ARCH=amd64   # or arm64
    
    # otelcol-contrib (tarball)
    curl -fsSL \
      "https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v${OTEL_VERSION}/otelcol-contrib_${OTEL_VERSION}_linux_${ARCH}.tar.gz" \
      | sudo tar -xz -C /usr/local/bin otelcol-contrib
    
    # opampsupervisor (raw binary, no tarball)
    sudo curl -fsSL -o /usr/local/bin/opampsupervisor \
      "https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/cmd%2Fopampsupervisor%2Fv${SUPERVISOR_VERSION}/opampsupervisor_${SUPERVISOR_VERSION}_linux_${ARCH}"
    sudo chmod 755 /usr/local/bin/opampsupervisor
    
    sudo mkdir -p /etc/otelcol-supervisor /var/lib/otelcol-supervisor
  2. Get an enrollment token the same way as Option A step 1.

  3. Write /etc/otelcol-supervisor/supervisor.yaml:

    server:
      endpoint: "wss://linkmesh.example.com/v1/opamp"
      headers:
        Authorization: "Bearer <YOUR_ENROLLMENT_TOKEN>"
    
    capabilities:
      accepts_remote_config: true
      reports_effective_config: true
      reports_health: true
      reports_remote_config: true
      reports_own_metrics: true
    
    agent:
      executable: /usr/local/bin/otelcol-contrib
      description:
        non_identifying_attributes:
          linkmesh.environment: "production"
    
    storage:
      directory: /var/lib/otelcol-supervisor

    The LinkMesh UI can render this exact file pre-filled with your token: on the collector’s detail page, the enrollment banner’s otelcol-contrib tab fetches it from /api/v1/downloads/opamp-bootstrap-config.yaml. Copy from there to avoid typos.

  4. Install a systemd unit for the supervisor (it spawns the collector as a subprocess — you don’t need a separate otelcol-contrib.service):

    sudo tee /etc/systemd/system/opamp-supervisor.service > /dev/null <<'UNIT'
    [Unit]
    Description=OpenTelemetry OpAMP Supervisor (LinkMesh-managed otelcol-contrib)
    After=network-online.target
    Wants=network-online.target
    
    [Service]
    Type=simple
    ExecStart=/usr/local/bin/opampsupervisor --config /etc/otelcol-supervisor/supervisor.yaml
    Restart=always
    RestartSec=5
    
    [Install]
    WantedBy=multi-user.target
    UNIT
    
    sudo systemctl daemon-reload
    sudo systemctl enable --now opamp-supervisor
  5. Watch the handshake:

    sudo journalctl -u opamp-supervisor -f
  • Collectors — the host appears with management mode OpAMP, status Connected within ~30 s.
  • Its Events tab shows registered and config_applied on first connect.

Throughput shows up on the topology canvas automatically: after the handshake LinkMesh offers the collector an own_metrics destination (a per-collector OTLP bearer token) over OpAMP, and the collector starts pushing its internal metrics to /v1/metrics.

   ┌──────────────────┐    OpAMP (WS/HTTP)    ┌──────────────┐
   │ opampsupervisor  │ ◄──────────────────► │  LinkMesh    │
   │  (talks OpAMP)   │                       │   server     │
   └────────┬─────────┘                       └──────────────┘
            │ writes config, manages process
            ▼
   ┌──────────────────┐
   │ otelcol-contrib  │
   │  (data plane)    │
   └──────────────────┘

The supervisor receives RemoteConfig pushes from LinkMesh, writes the collector’s effective config.yaml into its storage directory, and restarts the collector subprocess to pick it up. The collector itself never talks OpAMP directly — the supervisor is its bridge.

  • 401 on the WebSocket upgrade — the token is wrong, expired, or already used. Mint a fresh one.
  • websocket: bad handshake — your supervisor.yaml is using ws:// instead of wss://, or the request is hitting an HTTP/2 listener in front of LinkMesh. See Run behind a reverse proxy for the nginx WebSocket + HTTPS configuration.
  • Supervisor starts but never appears in the UI — confirm the host can reach wss://<server>/v1/opamp (try nc -vz <server> 443), and that agent.executable in supervisor.yaml points at an existing otelcol-contrib binary. The supervisor logs the path on startup.
  • agent::executable does not exist — fix the agent.executable path; the supervisor refuses to start without a valid collector binary.
  • Collector is online and healthy but every number is zero — the server’s externalUrl is almost certainly unset, so no own_metrics offer was ever made. Re-enrolling does not help. See Self-telemetry troubleshooting.
  • More: Enrollment troubleshooting.
  • How the edge talks to the server — how OpAMP compares to the Alloy remotecfg and agent channels.
  • Enrollment tokens — the Bearer credential in supervisor.yaml and how it stays durable across restarts.
  • OpAMP explained — background on how the protocol works, its deployment models, and the control-plane gap it leaves for a server like LinkMesh to fill.