Skip to main content
Capture distributed traces from Nginx with the OpenTelemetry Nginx module and send them to ClickHouse Observability. Use the demo dataset to try the integration without installing Nginx.

Prerequisites

  • A ClickHouse Observability service
  • For your own traces, an Nginx installation with the OpenTelemetry module and permission to update its configuration; the Docker example below uses nginx:1.27-otel
  • For the demo dataset, curl and Docker

Connection details

Open ClickHouse Observability and go to Team Settings → Data → Managed Telemetry. Copy your endpoint and API key using Copy connection details, or select Reveal key to view the masked key.The Nginx module exports over OTLP/gRPC, normally on port 4317. The JSON demo uses OTLP/HTTP, normally on port 4318. Use the endpoint for the matching protocol, including https:// when TLS is required:
Replace the placeholders with your service’s connection details. Use the base HTTP endpoint without /v1/traces; the collector exporter adds that path.
The gRPC endpoint must be reachable from Nginx. With Docker Desktop, use host.docker.internal to reach a collector on the host. For containers on a shared Docker network, use the collector’s container name. Use http:// for a local endpoint without TLS.

Integration with existing Nginx

1

Install the OpenTelemetry Nginx module

The nginx:1.27-otel image includes ngx_otel_module.so. For an installation outside Docker, follow the installation instructions linked from the Nginx OpenTelemetry module documentation.
2

Configure Nginx tracing

The following Docker example uses a template so the container’s startup script substitutes the connection environment variables. Save it as nginx.conf.template. The return 200 location provides a simple smoke test; for your application, retain your existing server and routing configuration and add the tracing directives shown here.
Save this as compose.yaml in the same directory:
The substitution filter preserves Nginx variables such as $request_method and $uri. Nginx does not automatically substitute shell environment variables in a directly mounted nginx.conf. Outside Docker, replace the connection placeholders with their actual values before validating the configuration, and restrict access to the file containing the key.
3

Validate and start Nginx

Set the connection variables in the same terminal, then run:
Each request creates a span with the method, path, status code, and duration. For an existing deployment, generate requests to your application’s URL. After changing the template or environment variables, run docker compose up -d --force-recreate nginx to apply them.
4

Verify traces in the UI

Open Search, select Traces, and filter for ServiceName:nginx-proxy. Select a time range covering your requests and allow a few seconds for export. Open a trace to inspect its spans and HTTP attributes.

Demo dataset

The sample contains 1,000 Nginx spans across nine endpoints, with successful requests, HTTP errors, and varied latencies. Set the connection variables before sending it.
1

Download the sample dataset

2

Configure the demo collector

Save the following as nginx-traces-demo.yaml in the download directory:
The demo-only transform/demo_timestamps processor shifts this sample into roughly the past 24 hours, ending two minutes before ingestion, while preserving span durations and the traffic pattern. Omit this processor for your own Nginx traces so their original timestamps are preserved. Sending the sample again can produce duplicate spans.
3

Run the demo collector

For a destination collector running on this computer, set OTEL_EXPORTER_OTLP_ENDPOINT to http://host.docker.internal:4318. The command below includes the Docker host mapping.
Run OpenTelemetry Collector Contrib 0.161.0 from the directory containing the configuration, in the terminal where you set the connection variables. Keep this terminal open:
The local receiver uses port 14318 to avoid conflicting with an existing collector on port 4318. The collector forwards the traces to your configured endpoint using the authentication settings above.
4

Send the traces

In another terminal, from the download directory, send the original sample to the local collector:
An empty success response such as {} or {"partialSuccess":{}} indicates the local collector accepted the request. Check the collector’s output for export errors and allow a few seconds for the batch to reach your service. Stop the demo collector with Ctrl+C when finished.
5

Verify the demo traces

Open Search, select Traces, filter for ServiceName:nginx-proxy, and select Last 2 days to include the full shifted dataset. Open a trace to inspect the HTTP attributes.

Dashboards and visualization

1

Download the dashboard configuration

.
2

Import the dashboard

  1. Open Dashboards and click Import in the upper-right corner.
  2. Upload nginx-traces-dashboard.json.
  3. Map the charts to your Traces source and click Finish Import.
3

View the dashboard

Filter for ServiceName:nginx-proxy and select a time range covering your traces. For the demo, select Last 2 days.

Troubleshooting

Nginx fails to start

Run docker compose run --rm nginx nginx -t to validate the generated configuration. An unknown otel_* directive or missing module file means the module is not installed or loaded. Check that you are using the -otel image and that the template is mounted at the documented path.

No traces appearing

  • Verify the gRPC endpoint and any authentication required by your destination collector. Managed services use the Bearer prefix. Do not use the HTTP endpoint for the Nginx module.
  • Confirm the endpoint is reachable from the Nginx container and that its scheme matches the destination’s TLS configuration.
  • Generate requests; an idle Nginx instance produces no request spans.
  • Check Traces, the service-name filter, and the selected time range. For the demo, confirm transform/demo_timestamps is included in the collector pipeline and select Last 2 days.
  • For the demo, check the collector terminal for authentication or export errors. Verify its HTTP endpoint and authorization value against your connection details.
  • Inspect Nginx errors with docker compose logs nginx. Outside Docker, inspect your Nginx error log.

Next steps