Skip to content
Tools / otel-hive

otel-hive

Self-hosted OpAMP management server for OpenTelemetry Collector fleets

GitHub — storl0rd/otel-hive Apache 2.0 — free & open source

What is otel-hive?

otel-hive is a self-hosted OpAMP management server — the missing control plane for OpenTelemetry Collector fleets. The OpAMP protocol (Open Agent Management Protocol) is an emerging CNCF standard that lets you remotely configure, health-check, and update running collectors over a persistent WebSocket connection.

Without a management plane you end up SSHing into VMs, running Ansible playbooks, or baking configs into container images — every config change is a deployment. otel-hive turns that into a Git push.

┌────────────────────────────────────────────────────┐
│           otel-hive  (single Docker container)      │
│                                                     │
│  ┌──────────────┐  ┌────────────┐  ┌─────────────┐  │
│  │  UI + REST   │  │  OpAMP WS  │  │  Git Sync   │  │
│  │  :8080 (Gin) │  │  :4320     │  │  Worker     │  │
│  └──────┬───────┘  └─────┬──────┘  └──────┬──────┘  │
│         └────────────────┴─────────────────┘         │
│              SQLite  (./data/app.db)                 │
│   agents | configs | groups | users | audit_log     │
└────────────────────────────────────────────────────┘
        ↕ OpAMP WS                    ↕ HTTPS
  OTel Collectors               Git Repo
  (Supervisor or                (GitHub / GitLab
   OpAMP extension)              / Gitea / HTTP)
OpAMP WebSocket server
Push configs, receive health reports, restart collectors — all over a persistent WS on port 4320
Git-based config sync
Commit a YAML file to your repo; otel-hive picks it up via webhook or scheduled poll and pushes to matched collectors
Built-in auth
BCrypt passwords, JWT sessions (15-min access / 7-day refresh), API keys for CI/CD and programmatic access
Audit log
Every config push, sync, login, and key operation is recorded with actor, timestamp, and resource reference

Requirements

Component Requirement
otel-hive server Docker 24+ or any Linux host (amd64/arm64). No external DB — SQLite is embedded.
Network Collectors must reach :4320 (OpAMP WS) and otel-hive must reach :8080 from your browser.
Collector version OTel Collector Contrib v0.96+ (OpAMP extension or Supervisor required).
Git provider GitHub, GitLab, Gitea, or any raw HTTP URL. Token required only for private repos.
Resources (typical) 128 MB RAM, 0.25 vCPU for < 20 collectors. Comfortable up to ~300 collectors on SQLite.

Deploying otel-hive

Option A — Docker Compose (recommended)

Fastest path. One file, one command, UI at http://localhost:8080.

docker-compose.yml
services:
  otel-hive:
    image: ghcr.io/storl0rd/otel-hive:latest
    ports:
      - "8080:8080"   # UI + REST API
      - "4320:4320"   # OpAMP WebSocket
    volumes:
      - ./data:/app/data
    environment:
      JWT_SECRET: "change-me-use-openssl-rand-hex-32"
    restart: unless-stopped
docker compose up -d
# UI available at http://localhost:8080
# First visit → setup wizard creates your admin account

Data persists in ./data/app.db. Generate a strong JWT secret with openssl rand -hex 32.

Option B — Linux binary

Single static binary. No Docker required. Suitable for bare-metal VMs or systemd services.

# Download the latest release binary
curl -Lo otel-hive \
  https://github.com/storl0rd/otel-hive/releases/latest/download/otel-hive-linux-amd64
chmod +x otel-hive

# Run with defaults (data stored in ./data/)
JWT_SECRET="$(openssl rand -hex 32)" ./otel-hive

To run as a systemd service, drop a unit file in /etc/systemd/system/otel-hive.service:

/etc/systemd/system/otel-hive.service
[Unit]
Description=otel-hive OpAMP manager
After=network.target

[Service]
ExecStart=/usr/local/bin/otel-hive
WorkingDirectory=/var/lib/otel-hive
Environment=JWT_SECRET=change-me
Restart=always
User=otel-hive

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now otel-hive

Option C — Kubernetes

No Helm chart yet (roadmap). Deploy manually with a Deployment + PVC + two Services. Use the OTel Operator on the collector side — it manages the OpAMP connection without needing the Supervisor.

otel-hive-k8s.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: otel-hive
  namespace: observability
spec:
  replicas: 1
  selector:
    matchLabels:
      app: otel-hive
  template:
    metadata:
      labels:
        app: otel-hive
    spec:
      containers:
        - name: otel-hive
          image: ghcr.io/storl0rd/otel-hive:latest
          ports:
            - containerPort: 8080   # UI + REST
            - containerPort: 4320   # OpAMP WS
          env:
            - name: JWT_SECRET
              valueFrom:
                secretKeyRef:
                  name: otel-hive-secret
                  key: jwt-secret
          volumeMounts:
            - name: data
              mountPath: /app/data
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: otel-hive-data
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: otel-hive-data
  namespace: observability
spec:
  accessModes: [ReadWriteOnce]
  resources:
    requests:
      storage: 10Gi
---
apiVersion: v1
kind: Service
metadata:
  name: otel-hive
  namespace: observability
spec:
  selector:
    app: otel-hive
  ports:
    - name: ui
      port: 8080
      targetPort: 8080
    - name: opamp
      port: 4320
      targetPort: 4320
# Create the secret first
kubectl create secret generic otel-hive-secret \
  --from-literal=jwt-secret="$(openssl rand -hex 32)" \
  -n observability

kubectl apply -f otel-hive-k8s.yaml

Expose the UI via an Ingress and the OpAMP port via a LoadBalancer or NodePort. The OpAMP connection is a persistent WebSocket — do not put it behind a stateless L7 proxy without sticky sessions.

Collector-side setup

Each collector needs to speak OpAMP. There are two options: the OpAMP Supervisor (bare-metal / VMs) or the OpAMP extension built into the Contrib distribution (simpler, but fewer capabilities).

Option 1 — OpAMP Supervisor (recommended for VMs)

The Supervisor wraps the collector as a managed subprocess, proxies OpAMP, and can restart the collector on config change. It lives alongside the collector binary.

1. Install the Supervisor

# Download the latest Supervisor binary
curl -Lo opampsupervisor \
  https://github.com/open-telemetry/opentelemetry-collector-releases/releases/latest/download/otelcol-contrib_linux_amd64
chmod +x opampsupervisor
sudo mv opampsupervisor /usr/local/bin/

# Install your collector binary (if not already present)
curl -Lo otelcol-contrib.tar.gz \
  https://github.com/open-telemetry/opentelemetry-collector-releases/releases/latest/download/otelcol-contrib_0.120.0_linux_amd64.tar.gz
tar -xzf otelcol-contrib.tar.gz
sudo mv otelcol-contrib /usr/local/bin/otelcol

2. Create supervisor.yaml

Adjust endpoint to point at your otel-hive server. Generate an API key from the otel-hive UI under API Keys.

/etc/otelcol/supervisor.yaml
server:
  endpoint: ws://otel-hive.internal:4320/v1/opamp
  headers:
    Authorization: "Bearer YOUR_API_KEY_HERE"

agent:
  executable: /usr/local/bin/otelcol
  config_apply_timeout: 30s
  # Fallback config used before first remote config is received
  bootstrap_config_file: /etc/otelcol/bootstrap.yaml

capabilities:
  accepts_remote_config: true
  reports_effective_config: true
  reports_health: true

# Labels used for config matching in git repo path convention
agent_description:
  non_identifying_attributes:
    - key: env
      value: production
    - key: role
      value: gateway

3. Create a bootstrap config

The bootstrap config is used on first start before otel-hive pushes a remote config. Keep it minimal.

/etc/otelcol/bootstrap.yaml
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317

exporters:
  debug:
    verbosity: basic

service:
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [debug]

4. Run the Supervisor

opampsupervisor --config /etc/otelcol/supervisor.yaml

Within ~5 seconds the collector should appear in the otel-hive UI under Agents.

Option 2 — OpAMP extension (simpler, K8s-friendly)

The opampextension is built into otelcol-contrib. No separate process — the collector manages its own OpAMP connection. Config changes require a collector restart (the extension handles this automatically).

collector-config.yaml (fragment)
extensions:
  opamp:
    server:
      ws:
        endpoint: ws://otel-hive.internal:4320/v1/opamp
        headers:
          Authorization: "Bearer YOUR_API_KEY_HERE"
    capabilities:
      accepts_remote_config: true
      reports_effective_config: true
      reports_health: true
    agent_description:
      non_identifying_attributes:
        env: production
        role: node-agent

service:
  extensions: [opamp]
  # ... rest of your pipeline

Git repo layout

otel-hive uses a path convention to map config files to collectors. The path structure encodes the collector labels that should receive each config.

configs/
├── environments/
│   ├── production/
│   │   ├── gateway.yaml      # → collectors with: env=production, role=gateway
│   │   └── node-agent.yaml   # → collectors with: env=production, role=node-agent
│   ├── staging/
│   │   └── gateway.yaml      # → collectors with: env=staging, role=gateway
│   └── default/
│       └── base.yaml         # fallback for uncategorized collectors
└── groups/
    ├── aws-east.yaml         # → collectors with: region=aws-east
    └── security.yaml

The collector's non_identifying_attributes (set in supervisor.yaml or the opamp extension config) are matched against path segments. A collector in production with role=gateway receives environments/production/gateway.yaml.

Using otel-hive

1. First-run setup wizard

On first launch, otel-hive detects no users exist and returns {"setup_required": true}. The UI redirects to the setup wizard where you create your admin account. After that, all API routes require a valid JWT or API key.

2. Connect a git source

Go to Git Sources → Add Source. Fill in your repo URL, branch, provider (GitHub / GitLab / Gitea / HTTP), and an optional token for private repos. Set a poll interval (default 5 min) and optionally configure a webhook secret for push-triggered syncs. Click Sync Now to do an immediate fetch.

3. Push a config change

Commit a collector config YAML to your repo at the appropriate path (e.g., configs/environments/production/gateway.yaml). otel-hive fetches the change on the next poll (or immediately via webhook), matches it to collectors by label, and pushes the new config via OpAMP. The collector applies it and reports back its effective config.

4. Monitor agents

The Agents page shows every connected collector: health status, last-seen timestamp, current config version, and the labels it reported. Red/yellow health badges surface problems before users notice them.

5. Audit log

Every mutating operation is recorded in the audit log: config pushes, git syncs, login events, API key creation/revocation, and agent restarts. Filter by event type or date range to answer "who changed what, and when."

Resource sizing

Fleet size vCPU RAM Notes
< 20 collectors 0.25 128 MB Lab / dev. Runs in a single Docker container fine.
20–100 collectors 0.5 256 MB Comfortable baseline for small production fleets.
100–300 collectors 1 512 MB SQLite WAL mode handles this range well.
300–500 collectors 2 1 GB Monitor SQLite write latency; plan PostgreSQL migration.
> 500 collectors PostgreSQL backend (roadmap). Open an issue if you hit this scale.

Links & resources