This article covers setting up the AppManager OTel Collector to receive traces from Apache, authenticate them with your API key, and forward them to the ManageEngine APM backend.
Because the OpenTelemetry C agent for Apache does not support custom OTLP export headers, an otelcol-contrib proxy is used as an intermediary to inject the required api-key header.
Architecture:
Apache HTTP Server
└─► OTel Webserver SDK (gRPC spans)
└─► otelcol-contrib proxy (port 4320 — adds api-key header)
└─► AppManagerOtelCollector (port 4318 — validates + forwards)
└─► ManageEngine APM Backend (https://<your-server>:<port>)
https://app-server:8446)sudo / root accessBefore installing, obtain your API key from the Applications Manager UI:
This key (format: APMI_<hex-string>) is required for both the collector and the proxy configuration.
There are two ways to install the collector:
Download and run the official installer script. The script handles binary placement, directory creation, and service registration.
cd /tmp
wget -O InstallOtelCollector.zip \
https://www.manageengine.com/products/applications_manager/54974026/InstallOtelCollector.zip
unzip InstallOtelCollector.zip
Set ME_SERVER_ENDPOINT to point to your Applications Manager server, then run the installer:
export ME_SERVER_ENDPOINT="https://<HOST-NAME>:<SSL-PORT>"
sudo -E sh InstallOtelCollector.sh
Where:
<HOST-NAME> — Hostname or IP of your Applications Manager server<SSL-PORT> — SSL port of Applications Manager (e.g. 8443 or 8446)Example:
export ME_SERVER_ENDPOINT="https://apm-prod-server:8443"
sudo -E sh InstallOtelCollector.sh
Note: The -E flag passes your exported ME_SERVER_ENDPOINT to the sudo session so the install script can read it.
After installation, skip to Step 4: Verify the Collector is Running below.
If you already have the AppManagerOtelCollector package (e.g. from the Applications Manager product bundle), place it manually:
Copy the AppManagerOtelCollector package to a suitable location and create a symlink at /opt/AppManagerOtelCollector:
sudo ln -s /path/to/AppManagerOtelCollector /opt/AppManagerOtelCollector
The directory must contain:
/opt/AppManagerOtelCollector/
├── bin/
│ ├── AppManagerOtelCollector (main binary)
│ ├── service.sh (service wrapper)
│ ├── .env (environment config)
│ └── otel-collector-config.yaml (collector pipeline config)
└── logs/
└── collector.log
Edit /opt/AppManagerOtelCollector/bin/.env and set the required values:
sudo nano /opt/AppManagerOtelCollector/bin/.env
Key settings to configure:
# Listening addresses for this collector
ME_HTTP_LISTENING_ADDRESS="0.0.0.0:4318"
ME_GRPC_LISTENING_ADDRESS="0.0.0.0:4317"
# ManageEngine APM backend URL (required)
ME_SERVER_ENDPOINT="https://<your-apm-server>:<port>"
# TLS (set true if APM server uses a self-signed certificate)
ME_INSECURE_SKIP_VERIFY="true"
# Log file directory
ME_LOG_FILE_DIRECTORY="/opt/AppManagerOtelCollector/logs"
Important: ME_SERVER_ENDPOINT must not be left empty. The collector uses it to validate API keys; leaving it empty causes a runtime error on every incoming request.
If the collector runs as a non-root user and the binary resides under a home directory, ensure the user can traverse the path:
# Example: if binary is under /home/someuser/SCP/...
sudo chmod o+x /home/someuser
sudo chmod o+x /home/someuser/SCP
# ... and so on for each parent directory
Using the symlink approach in Step 1 (pointing to /opt/AppManagerOtelCollector) is the recommended alternative.
sudo tee /etc/systemd/system/AppManagerOtelCollector.service <<'EOF'
[Unit]
Description=AppManagerOtelCollector service
After=network.target
[Service]
Type=forking
ExecStart=/opt/AppManagerOtelCollector/bin/service.sh service_start
ExecStop=/opt/AppManagerOtelCollector/bin/service.sh service_stop
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable AppManagerOtelCollector
sudo systemctl start AppManagerOtelCollector
sudo systemctl status AppManagerOtelCollector --no-pager
Verify it is listening:
ss -tlnp | grep -E '4317|4318'
Expected:
LISTEN 0.0.0.0:4317 (gRPC)
LISTEN 0.0.0.0:4318 (HTTP)
This proxy receives spans from Apache on port 4320 and forwards them to the AppManager collector on port 4318 with the api-key header injected.
cd /tmp
wget https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v0.99.0/otelcol-contrib_0.99.0_linux_amd64.tar.gz
tar -xzf otelcol-contrib_0.99.0_linux_amd64.tar.gz
sudo mv otelcol-contrib /usr/local/bin/
Verify:
otelcol-contrib version
sudo mkdir -p /etc/otelcol-contrib
sudo tee /etc/otelcol-contrib/config.yaml <<'EOF'
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4320
http:
endpoint: 0.0.0.0:4321
exporters:
otlphttp:
endpoint: http://127.0.0.1:4318
tls:
insecure: true
headers:
"api-key": "YOUR_API_KEY_HERE"
logging:
verbosity: detailed
service:
pipelines:
traces:
receivers: [otlp]
exporters: [otlphttp, logging]
metrics:
receivers: [otlp]
exporters: [otlphttp, logging]
logs:
receivers: [otlp]
exporters: [otlphttp, logging]
EOF
Important: Replace YOUR_API_KEY_HERE with your actual API key (format: APMI_...).
The exporter endpoint must use 127.0.0.1 (not localhost) to ensure it bypasses any system HTTP proxy that may be configured.
sudo useradd --system --no-create-home otelcol
sudo tee /etc/systemd/system/otelcol-proxy.service <<'EOF'
[Unit]
Description=OTel Collector Proxy (adds api-key for Apache traces)
After=network.target AppManagerOtelCollector.service
[Service]
User=otelcol
Environment="NO_PROXY=localhost,127.0.0.1"
Environment="no_proxy=localhost,127.0.0.1"
Environment="http_proxy="
Environment="https_proxy="
ExecStart=/usr/local/bin/otelcol-contrib --config /etc/otelcol-contrib/config.yaml
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
The Environment lines ensure the proxy ignores any system-level HTTP proxy when connecting to 127.0.0.1:4318.
sudo systemctl daemon-reload
sudo systemctl enable otelcol-proxy
sudo systemctl start otelcol-proxy
sudo systemctl status otelcol-proxy --no-pager
Verify it is listening:
ss -tlnp | grep 4320
A system HTTP proxy can intercept connections to localhost/127.0.0.1 and break the pipeline. Check for and remove any proxy settings:
# Check current proxy
echo $http_proxy
echo $https_proxy
# Check if set in ~/.bashrc
grep -n "http_proxy\|https_proxy" ~/.bashrc
If proxy lines are present in ~/.bashrc, remove them:
sed -i '/export http_proxy=/d; /export https_proxy=/d' ~/.bashrc
unset http_proxy https_proxy
Ensure Apache's OTel module is pointed at the proxy (port 4320), not directly at the collector.
In /etc/apache2/conf-available/opentelemetry_module.conf:
ApacheModuleOtelExporterEndpoint http://localhost:4320
Then restart Apache:
sudo systemctl restart apache2
systemctl is-active apache2 AppManagerOtelCollector otelcol-proxy
Expected: three lines of active.
ss -tlnp | grep -E '4317|4318|4320'
for i in $(seq 1 5); do curl -s -o /dev/null http://localhost/; done
sudo tail -20 /opt/AppManagerOtelCollector/logs/collector.log | python3 -c "
import sys, json
for line in sys.stdin:
line = line.strip()
if not line: continue
try:
d = json.loads(line)
code = d.get('response_code')
if code:
print(d.get('level'), '|', d.get('msg'), '| code=', code, '| url=', d.get('URL',''))
except: pass
"
Expected output showing successful flow:
info | outbound (response) | code= 200 | url= https://<server>/otel/validate
info | inbound (response) | code= 200 | url= /v1/traces
info | outbound (response) | code= 200 | url= https://<server>/arh/connect
sudo journalctl -u otelcol-proxy --no-pager -n 30
You should see spans with attributes such as:
http.method: GET
http.target: /portfolio/
http.status_code: 200
"apikey":""Cause: The API key header is not reaching the collector, or ME_SERVER_ENDPOINT is empty.
Fix:
ME_SERVER_ENDPOINT is set in .env.api-key header value.EOF error when exportingCause: System HTTP proxy routing the connection through an external proxy.
Fix: Set the exporter endpoint in /etc/otelcol-contrib/config.yaml to http://127.0.0.1:4318 (not http://localhost:4318), and ensure the NO_PROXY environment variable is set in the service (Part B, Step 4).
Cause: Incorrect API key value.
Fix: Double-check the key in /etc/otelcol-contrib/config.yaml matches exactly what the APM portal issued (format: APMI_<hex-string>).
Cause: Apache OTel module is not sending to port 4320.
Fix: Verify ApacheModuleOtelExporterEndpoint in the Apache config is http://localhost:4320, then restart Apache.
| File | Purpose |
|---|---|
/opt/AppManagerOtelCollector/bin/.env | AppManager collector environment config |
/opt/AppManagerOtelCollector/bin/otel-collector-config.yaml | Collector pipeline config |
/opt/AppManagerOtelCollector/logs/collector.log | Collector log file |
/usr/local/bin/otelcol-contrib | otelcol-contrib proxy binary |
/etc/otelcol-contrib/config.yaml | Proxy pipeline config (receivers, exporters, API key) |
/etc/systemd/system/otelcol-proxy.service | Proxy systemd service |
/etc/systemd/system/AppManagerOtelCollector.service | AppManager collector systemd service |