Skip to main content
On a virtual machine or a bare-metal host, the collector runs as a native systemd service. That gives you host metrics, system logs and an OTLP endpoint for anything running on the box — with restart-on-failure and start-on-boot handled by the init system rather than by you.
Before you start, you need two values.
  1. Your base endpoint — shown on Get Started in the dashboard. These pages write it as $OIQ_ENDPOINT.
  2. A license key — created in Settings → License Keys, starting oiq_. Requires the Admin role. See Create a license key. These pages write it as $OIQ_LICENSE_KEY.
Export both before running anything below:
You also need sudo on a host with systemd, and outbound HTTPS to your ingest endpoint.

Why a package rather than a container

On a host whose job is running your application, a containerised collector adds a layer that gets in the way of the thing you most want: host metrics. A container sees its own filesystem and its own process namespace, so collecting real host telemetry from inside one means mounting the host back in and telling the receiver where you put it. Installed natively, it just sees the host. It also restarts with the machine without a container runtime having to be up first.

1. Install the collector

The package installs the binary, a systemd unit called otelcol-contrib, and a default config at /etc/otelcol-contrib/config.yaml. It starts the service immediately on the default config, which exports nowhere — the next two steps replace it.
Pin OTEL_VERSION rather than tracking the latest release. The collector’s configuration schema changes between versions, and an unattended upgrade that invalidates your config will stop telemetry at the least convenient moment.

2. Supply the endpoint and key

The key must not live in the config file, which is world-readable. systemd reads an environment file you can lock down instead:
Use tee with a heredoc, not echo into a file you then edit by hand. A trailing newline or a stray space becomes part of the key value, and the result is a 401 that looks nothing like a formatting problem. Mode 600 matters too: the default config directory is readable by every user on the box.
Point the unit at that file:
Add:

3. Write the config

The OTLP receivers bind to 127.0.0.1, not 0.0.0.0. On a VM, the things exporting to this collector are on the same machine, so loopback is sufficient and it means the collector is not an open OTLP relay reachable from your network. Change it only if you deliberately want other hosts to export here, and put a firewall in front of it if you do.
journald collects system logs. Narrow units to what you actually want — without a filter, a busy host will ship a great deal of noise you pay to store. Remove the journald receiver from the logs pipeline if you do not want system logs at all.

4. Start it

Expected output from systemctl status otelcol-contrib:
active (running) — and, critically, still running thirty seconds later. A collector that fails on its config exits and systemd restarts it in a loop, which reads as “running” if you look at exactly the wrong moment. Confirm from the log:

5. Point applications at it

Applications on this host export to loopback and carry no license key:
For a service managed by systemd, put those in its own EnvironmentFile rather than in a shell profile — a profile is not read by a unit.

Verify

The collector publishes its own metrics on port 8888. Three counters separate the two things that can be wrong:
Accepted rising while sent stays flat is the classic signature of a wrong endpoint or a missing key in the exporter block. It is worth checking before anything else, because from inside your application everything looks fine. Expected output within a minute of start, with host metrics flowing:
Then open Infrastructure in the product, set the range to the last 15 minutes, and find this host by its hostname — resourcedetection sets it from the OS.

Troubleshooting

A config error. The collector refuses to run on an invalid configuration rather than running degraded, and systemd restarts it.
Validate before restarting:
No output and exit code 0 means the config is valid.
The unit is not reading your environment file. systemctl edit writes a drop-in at /etc/systemd/system/otelcol-contrib.service.d/override.conf — confirm it exists and contains the EnvironmentFile line, then sudo systemctl daemon-reload.Exporting the variables in your shell does not reach a systemd unit.
The collector user must be able to read the journal. The package normally handles this; where it has not, add the service user to the systemd-journal group and restart:
Also check your units filter actually matches units on this host — systemctl list-units --type=service shows the real names.
The hostmetrics receiver is in the metrics pipeline only. Confirm it is listed under service.pipelines.metrics.receivers; a receiver defined but not wired into a pipeline is silently inert — no error, no data.
Read the error field on that line — it names the cause exactly.
  • no such host — the endpoint hostname does not resolve. Check $OIQ_ENDPOINT against the value on Get Started.
  • connection refused — the host resolves but nothing is listening on that port.
  • 401 Unauthorized — the key is missing, malformed or revoked.
  • 404 — the endpoint already ends in /v1/…. It must be the base URL; the collector appends the signal path itself.
The collector retries with backoff and does not drop data while it retries, so a transient failure here is not a loss.
The collector is running and receiving nothing. That is an application-side problem, not a collector one — your services are not exporting to it.Check that your application’s OTEL_EXPORTER_OTLP_ENDPOINT points at the collector’s OTLP port (4318 for HTTP, 4317 for gRPC), not at aiAxonIQ.
Two causes that are not about the key’s value:
  • A trailing newline. A key read from a file created by a shell heredoc, or a Kubernetes Secret made with --from-file, carries the newline as part of the value. Use --from-literal, or printf rather than echo.
  • A validation outage. If the receiver cannot reach the service that validates keys it fails closed and returns the same 401. A sudden 401 across every service at once, with a key you have not changed, is far more likely to be this. Check $OIQ_ENDPOINT/health first.
The collector reads its configuration only at startup. Restart it after any edit, and confirm the file you edited is the one mounted into the process — a bind mount pointing at a path that does not exist silently yields the image’s default config rather than an error.

Next

Instrument your application

Zero-code setup per language.

Docker

For containerised workloads on this host.

Verify your data

Confirm it landed.