The OpenTelemetry Collector is a vendor-agnostic agent that receives, processes, and exports telemetry data — metrics, traces, and logs — from instrumented applications. Running a standalone Collector on RHEL 9 decouples your application code from the observability backend, making it easy to route data to multiple destinations or swap backends without redeploying services. This guide covers downloading the Collector binary, writing a minimal config.yaml pipeline, running the Collector as a systemd service, and sending a test trace from an application using the OTLP SDK.
Prerequisites
- RHEL 9 server with a sudo or root account
- An observability backend to export to — Prometheus for metrics and/or Jaeger/Tempo for traces
- Firewall access to open ports 4317 (OTLP gRPC) and 4318 (OTLP HTTP)
- Basic understanding of YAML syntax
- Optional: a Prometheus remote write endpoint for metrics export
Step 1 — Download the OpenTelemetry Collector Binary
The OpenTelemetry project publishes two distributions: otelcol (core components only) and otelcol-contrib (includes community exporters for backends like Jaeger, Prometheus, and cloud providers). For most self-hosted setups, otelcol-contrib is the practical choice.
OTEL_VER="0.101.0"
ARCH="linux_amd64"
# Download the contrib distribution
wget -O /tmp/otelcol-contrib.tar.gz
"https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v${OTEL_VER}/otelcol-contrib_${OTEL_VER}_${ARCH}.tar.gz"
tar xzf /tmp/otelcol-contrib.tar.gz -C /tmp/
sudo mv /tmp/otelcol-contrib /usr/local/bin/otelcol
sudo chmod +x /usr/local/bin/otelcol
# Verify the installation
otelcol --version
Step 2 — Write the Collector Configuration
The Collector configuration is a YAML file that declares receivers (how data enters), processors (transformations), exporters (where data goes), and service pipelines that wire them together. The example below accepts OTLP data over gRPC and HTTP, batches it for efficiency, logs it to stdout, and forwards traces to a Jaeger backend via OTLP HTTP.
sudo mkdir -p /etc/otelcol
sudo tee /etc/otelcol/config.yaml > /dev/null <<'EOF'
receivers:
otlp:
protocols:
grpc:
endpoint: "0.0.0.0:4317"
http:
endpoint: "0.0.0.0:4318"
processors:
batch:
timeout: 5s
send_batch_size: 1024
exporters:
logging:
loglevel: info
otlphttp/jaeger:
endpoint: "http://localhost:4318"
tls:
insecure: true
prometheusremotewrite:
endpoint: "http://prometheus-host:9090/api/v1/write"
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [logging, otlphttp/jaeger]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [logging, prometheusremotewrite]
logs:
receivers: [otlp]
processors: [batch]
exporters: [logging]
EOF
Step 3 — Create a systemd Service Unit
Running the Collector under systemd ensures it restarts automatically after a crash or reboot. Create a dedicated system user to run the process with least-privilege and write the service unit file to /etc/systemd/system/.
sudo useradd -r -s /sbin/nologin otelcol
sudo tee /etc/systemd/system/otelcol.service > /dev/null <<'EOF'
[Unit]
Description=OpenTelemetry Collector
After=network.target
[Service]
User=otelcol
Group=otelcol
ExecStart=/usr/local/bin/otelcol --config /etc/otelcol/config.yaml
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now otelcol
sudo systemctl status otelcol
Step 4 — Open Firewall Ports
Applications send telemetry to the Collector over ports 4317 (OTLP gRPC) and 4318 (OTLP HTTP). Open both ports in firewalld so that services on other hosts can reach the Collector.
# Open OTLP gRPC and HTTP ports
sudo firewall-cmd --permanent --add-port=4317/tcp
sudo firewall-cmd --permanent --add-port=4318/tcp
sudo firewall-cmd --reload
# Confirm the ports are open
sudo firewall-cmd --list-ports
Step 5 — Send a Test Trace via the OTLP HTTP Endpoint
You can send a minimal trace payload directly with curl to confirm the Collector is receiving and processing data before integrating a full application SDK. The payload uses the OTLP JSON format over HTTP.
# Send a minimal OTLP HTTP trace
curl -X POST http://localhost:4318/v1/traces
-H "Content-Type: application/json"
-d '{
"resourceSpans": [{
"resource": {
"attributes": [{"key": "service.name", "value": {"stringValue": "test-service"}}]
},
"scopeSpans": [{
"spans": [{
"traceId": "5b8aa5a2d2c872e8321cf37308d69df2",
"spanId": "051581bf3cb55c13",
"name": "test-span",
"kind": 1,
"startTimeUnixNano": "1624558223000000000",
"endTimeUnixNano": "1624558224000000000",
"status": {"code": 1}
}]
}]
}]
}'
# Check the Collector logs to confirm receipt
sudo journalctl -u otelcol -n 50 --no-pager
Conclusion
You have installed the OpenTelemetry Collector Contrib distribution on RHEL 9, defined a multi-signal pipeline that accepts traces, metrics, and logs over OTLP gRPC and HTTP, and confirmed end-to-end data flow with a curl test. The Collector’s pipeline architecture means you can add new exporters — such as Google Cloud Trace, AWS X-Ray, or Elastic APM — simply by updating config.yaml and restarting the service, without modifying any application code. To instrument applications, use the OpenTelemetry SDK for your language and point the OTLP exporter at http://<collector-host>:4318 (HTTP) or grpc://<collector-host>:4317 (gRPC).
Next steps: How to Install Jaeger for Distributed Tracing on RHEL 9, How to Monitor MySQL with Percona Monitoring and Management on RHEL 9, and How to Configure syslog-ng for Centralised Syslog on RHEL 9.