---
title: Monitor self-hosted NGINX with OpenTelemetry
source: https://docs.newrelic.com/docs/opentelemetry/integrations/nginx/nginx-otel-host
---

Monitor your self-hosted NGINX servers with OpenTelemetry to send performance metrics and telemetry data to New Relic.

You can choose between three collector options:

-   **NRDOT:** New Relic Distribution of OpenTelemetry
-   **OTel Collector Contrib:** Standard OpenTelemetry Collector with community-contributed components
-   **Prometheus Receiver:** For environments already running [nginx-prometheus-exporter](https://github.com/nginxinc/nginx-prometheus-exporter)

## Before you begin [#prerequisites]

Ensure you have:

-   Valid New Relic [license key](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#ingest-license-key)
-   NGINX with the [HTTP stub status](https://nginx.org/en/docs/http/ngx_http_stub_status_module.html) module enabled
-   One of the following collectors installed on a Linux host:
    -   [NRDOT collector](https://github.com/newrelic/nrdot-collector-releases/blob/main/distributions/README.md#deb-installation), or
    -   [OpenTelemetry Collector Contrib](https://github.com/open-telemetry/opentelemetry-collector-contrib/releases/latest)
-   Network access from the Linux host to:
    -   NGINX HTTP stub status endpoint
    -   New Relic's [OTLP endpoint](https://docs.newrelic.com/docs/opentelemetry/best-practices/opentelemetry-otlp/#configure-endpoint-port-protocol)

/\* Verify NGINX status module:
\`\`\`bash
nginx -V 2>&1 | grep -o with-http_stub_status_module
\`\`\`
Expected output: \`with-http_stub_status_module\`

Test network connectivity:
\`\`\`bash
\# For US region (default)
curl -I https&#x3A;//otlp.nr-data.net

\# For EU region
curl -I https&#x3A;//otlp.eu01.nr-data.net

\# For JP region
curl -I https&#x3A;//otlp.jp.nr-data.net
\`\`\`
Expected output: HTTP/2 200 response \*/

## Set up NGINX monitoring [#setup]

Choose your preferred collector and follow the steps:

### NRDOT collector

You can use the NRDOT collector to monitor your NGINX server. The NRDOT collector is a pre-configured distribution that includes New Relic-specific components.

To install & configure the NRDOT collector, follow these steps:

> #### 💡 TIP
>
> If any verification step fails, install the missing components before continuing. Need help installing the NRDOT collector? Check the [installation section](https://github.com/newrelic/nrdot-collector-releases/blob/main/distributions/README.md#deb-installation) of the nrdot-collector-releases repository.
>
> During installation use `export collector_distro="nrdot-collector"`

**Step 1: Configure NRDOT collector**

Configure the NRDOT collector to scrape metrics from your NGINX stub status endpoint and send them to New Relic.

/\* The NRDOT collector uses three main components for NGINX monitoring:

\- \*\*Receivers\*\* - Connect to your NGINX stub status endpoint to collect metrics
\- \*\*Processors\*\* - Add server identification and batch metrics for efficient transmission
\- \*\*Exporters\*\* - Send the processed metrics to your New Relic account via OTLP HTTP \*//\* Before configuring, you need:

\- Your stub status URL from Step 1 (default: \`http&#x3A;//&lt;NGINX_SERVER_IP>:&lt;YOUR_LOCAL_PORT>/nginx_status\`)
\- A deployment name (for example \`production-web-01\`, \`staging-api\`) \*/

> #### ⚠️ IMPORTANT
>
> **Choose your monitoring approach**:
>
> -   NGINX-only monitoring (this guide): Monitors just your NGINX web server performance and metrics
> -   Complete server monitoring: Monitors NGINX plus your entire server (CPU usage, memory, disk space, system logs)
>
> If you want to monitor your whole server, not just NGINX, use the NRDOT collector's [default configuration](https://github.com/newrelic/nrdot-collector-releases/blob/main/distributions/nrdot-collector/config.yaml) instead and add the NGINX receiver configuration to it.

Create the configuration file `/etc/nrdot-collector/nginx-config.yaml`:

```yaml
receivers:
  nginx:
    endpoint: <YOUR_STUB_STATUS_ENDPOINT>  # Replace with your stub status URL
    collection_interval: 30s                      # How often to collect metrics
    metrics:
      nginx.requests:
        enabled: true
      nginx.connections_accepted:
        enabled: true
      nginx.connections_handled:
        enabled: true
      nginx.connections_current:
        enabled: true

processors:
  # Detect system information
  resourcedetection:
    detectors: [system]
    system:
      resource_attributes:
        host.name:
          enabled: false
        host.id:
          enabled: true

  # Add NGINX-specific identification
  resource/nginx:
    attributes:
      - key: nginx.server.endpoint
        value: "<YOUR_STUB_STATUS_ENDPOINT>"  # Replace with your endpoint
        action: upsert
      - key: nginx.deployment.name
        value: "<DEPLOYMENT_NAME>"                    # Replace with your deployment name
        action: upsert
  
  # Batch metrics for efficient sending
  batch:
    timeout: 30s
    send_batch_size: 1024

  # Transform metrics for better display in New Relic
  transform/nginx_metrics:
    metric_statements:
      - context: resource
        statements:
          # Customize the display name as needed for your New Relic dashboard
          - set(attributes["nginx.display.name"], Concat(["server", attributes["nginx.deployment.name"]], ":"))
  
  transform/metadata_nullify:
    metric_statements:
      - context: metric
        statements:
          - set(description, "")
          - set(unit, "")

exporters:
  otlp_http:
    endpoint: ${env:YOUR_NEWRELIC_OTLP_ENDPOINT}
    headers:
      api-key: ${env:YOUR_NEW_RELIC_LICENSE_KEY}

service:
  pipelines:
    metrics/nginx:
      receivers: [nginx]
      processors: [resourcedetection, resource/nginx, batch, transform/nginx_metrics, transform/metadata_nullify]
      exporters: [otlp_http]
```

#### Configuration parameters

The following table describes the key configuration parameters:

| Parameter                     | Description                                                                                                                |
| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `<YOUR_STUB_STATUS_ENDPOINT>` | Replace with the NGINX stub status endpoint (for example `http://127.0.0.1/basic_status`)                                  |
| `<DEPLOYMENT_NAME>`           | Replace with a unique deployment name for this NGINX server (for example `production-web-01`, `staging-api`, `prod-lb-01`) |
| `collection_interval`         | Interval in seconds to collect metrics. The default value is set to `30s`                                                  |
| `timeout`                     | Timeout in seconds to wait before sending batched metrics. The default value is set to `30s`                               |
| `send_batch_size`             | Number of metrics to batch before sending. The default value is set to `1024`                                              |

/\* \*\*Replace these values in the configuration above:\*\*

1\. \*\*Endpoint URL\*\*: Change \`http&#x3A;//&lt;NGINX_SERVER_IP>:&lt;YOUR_LOCAL_PORT>/nginx_status\` to match your stub status configuration from Step 1
2\. \*\*Deployment name\*\*: Replace \`production-web-01\` with a unique identifier for this NGINX server

\*\*Choosing a good deployment name:\*\*
\- Use descriptive names like \`production-web-01\`, \`staging-api\`, or \`prod-lb-01\`
\- Must be unique across all NGINX servers within your New Relic account
\- This name will appear in dashboards and help you identify specific servers
\- Keep it short but meaningful for easy filtering and alerting \*/

**Step 2: Configure environment and update config path**

Update the NRDOT collector configuration to use your NGINX config file and set the OTLP endpoint.

Determine your OTLP endpoint based on your New Relic region. See [Configure endpoint, port, and protocol](https://docs.newrelic.com/docs/opentelemetry/best-practices/opentelemetry-otlp/#configure-endpoint-port-protocol) for the complete list of endpoints and supported ports for your region.

> #### ⚠️ IMPORTANT
>
> Your license key is already configured in `/etc/nrdot-collector/nrdot-collector.conf` during installation. You only need to update the config file path and OTLP endpoint.

Update the collector configuration file:

```bash
export collector_distro="nrdot-collector"
export otlp_endpoint="<YOUR_NEWRELIC_OTLP_ENDPOINT>"  # Replace with your region's endpoint

# Update the config file path to point to nginx-config.yaml
sudo sed -i 's|OTELCOL_OPTIONS="--config=/etc/nrdot-collector/config.yaml"|OTELCOL_OPTIONS="--config=/etc/nrdot-collector/nginx-config.yaml"|' /etc/${collector_distro}/${collector_distro}.conf

# Add the OTLP endpoint
echo "OTEL_EXPORTER_OTLP_ENDPOINT=${otlp_endpoint}" | sudo tee -a /etc/${collector_distro}/${collector_distro}.conf > /dev/null
```

**Step 3: (Optional) Forward NGINX logs**

In addition to metrics, you can send NGINX [access and error logs](https://docs.nginx.com/nginx/admin-guide/monitoring/logging/) to New Relic for comprehensive monitoring and troubleshooting. These logs complement the [core NGINX metrics](https://docs.newrelic.com/docs/opentelemetry/nginx/nginx-otel-metrics-reference#core-metrics) and provide detailed request-level insights.

> #### 💡 TIP
>
> Skip this step if you only need basic NGINX metrics and don't require detailed request logs.

1.  To configure NGINX to output JSON-formatted logs, add this to your NGINX configuration (`/etc/nginx/nginx.conf`):

    ```nginx
    http {
        # JSON log format for better parsing
        log_format json_combined escape=json
        '{'
          '"time":"$time_local",'
          '"remote_addr":"$remote_addr",'
          '"request":"$request",'
          '"status":$status,'
          '"bytes_sent":$body_bytes_sent,'
          '"request_time":$request_time,'
          '"referer":"$http_referer",'
          '"user_agent":"$http_user_agent"'
        '}';

        # Use the JSON format for access logs
        access_log /var/log/nginx/access.log json_combined;
        error_log /var/log/nginx/error.log warn;

        # Your existing configuration...
    }
    ```

2.  Reload NGINX to apply the changes:

    ```bash
    sudo nginx -t && sudo nginx -s reload
    ```

3.  To configure the collector for log forwarding, add these sections to your `/etc/nrdot-collector/nginx-config.yaml`:

    ```yaml
    receivers:
      # Your existing nginx receiver...
      nginx:
        # existing configuration...

      # Add log receivers
      filelog/nginx_access:
        include:
          - /var/log/nginx/access.log

      filelog/nginx_error:
        include:
          - /var/log/nginx/error.log

    processors:
      # Your existing processors...

      # Add log processor
      transform/nginx_access_logs:
        log_statements:
        - context: resource
          statements:
            - set(attributes["nginx.display.name"], Concat(["server", attributes["nginx.deployment.name"]], ":"))
            - set(attributes["logtype"], "nginx")
      transform/nginx_error_logs:
        log_statements:
        - context: resource
          statements:
            - set(attributes["nginx.display.name"], Concat(["server", attributes["nginx.deployment.name"]], ":"))
            - set(attributes["logtype"], "nginx-error")

    service:
      pipelines:
        # Your existing metrics pipeline...

        # Add log pipelines
        logs/nginx-access:
          receivers: [filelog/nginx_access]
          processors: [resource/nginx, batch, transform/nginx_access_logs]
          exporters: [otlp_http]

        logs/nginx-error:
          receivers: [filelog/nginx_error]
          processors: [resource/nginx, batch, transform/nginx_error_logs]
          exporters: [otlp_http]
    ```

4.  Set permissions and apply configuration. Allow the collector to read NGINX log files:

    ```bash
    # Add collector user to adm group (has read access to logs)
    sudo usermod -a -G adm nrdot-collector

    # Ensure log files are readable
    sudo chmod 644 /var/log/nginx/access.log
    sudo chmod 644 /var/log/nginx/error.log
    ```

**Step 4: Start monitoring**

Now that everything is configured, start the NRDOT collector and verify that data is flowing to New Relic.

1.  Start the collector:

    1.  Apply the configuration changes:

        ```bash
        sudo systemctl daemon-reload
        sudo systemctl restart nrdot-collector.service
        ```

    2.  Verify the service is running:

        ```bash
        sudo systemctl status nrdot-collector.service
        ```

        Expected output: `Active: active (running)` with no recent errors

2.  Verify data collection:

    1.  Check startup logs:

        ```bash
        sudo journalctl -u nrdot-collector.service -n 20
        ```

    2.  Generate test traffic (to create metrics):

        ```bash
        # Make a few requests to your NGINX server
        curl http://localhost
        ```

    Allow time for initial data to appear in New Relic, then [access your NGINX dashboard](https://docs.newrelic.com/docs/opentelemetry/integrations/nginx/find-and-query-your-data#find-data) to verify data collection.

### OpenTelemetry Collector Contrib

> #### 💡 TIP
>
> If any verification step fails, install the missing components before continuing. Need help installing the collector? Check the [OpenTelemetry Collector installation guide](https://github.com/open-telemetry/opentelemetry-collector-contrib).

**Step 1: Configure the OpenTelemetry Collector**

Configure the OpenTelemetry Collector to scrape metrics from your NGINX stub status endpoint and send them to New Relic.

/\* The OpenTelemetry Collector uses three main components for NGINX monitoring:

\- \*\*Receivers\*\* - Connect to your NGINX stub status endpoint to collect metrics
\- \*\*Processors\*\* - Add server identification and batch metrics for efficient transmission
\- \*\*Exporters\*\* - Send the processed metrics to your New Relic account via OTLP HTTP \*//\* Before editing the configuration, you'll need:

\- Your stub status URL from Step 1 (default: \`http&#x3A;//&lt;NGINX_SERVER_IP>:&lt;YOUR_LOCAL_PORT>/nginx_status\`)
\- A deployment name (for example \`production-web-01\`, \`staging-api\`) \*//\* The deployment name will appear in New Relic dashboards and helps you identify specific servers when you have multiple NGINX instances. \*/

> #### ⚠️ IMPORTANT
>
> Before editing: Back up your existing configuration: `sudo cp /etc/otelcol-contrib/config.yaml /etc/otelcol-contrib/config.yaml.backup`

Edit your collector configuration file (typically `/etc/otelcol-contrib/config.yaml`) and add the following sections. If you already have receivers, processors, or exporters sections, merge these with your existing configuration:

1.  Configure the NGINX receiver:

    ```yaml
    receivers:
      nginx:
        endpoint: <YOUR_STUB_STATUS_ENDPOINT>  # Replace with your stub status URL
        collection_interval: 30s                      # How often to collect metrics
        metrics:
          nginx.requests:
            enabled: true
          nginx.connections_accepted:
            enabled: true
          nginx.connections_handled:
            enabled: true
          nginx.connections_current:
            enabled: true
    ```

2.  Configure processors for metadata and batching:

    ```yaml
    processors:
      # Detect system information
      resourcedetection:
        detectors: [system]
        system:
          resource_attributes:
            host.name:
              enabled: false
            host.id:
              enabled: true

      # Add NGINX-specific identification
      resource/nginx:
        attributes:
          - key: nginx.server.endpoint
            value: "<YOUR_STUB_STATUS_ENDPOINT>"  # Replace with your endpoint
            action: upsert
          - key: nginx.deployment.name
            value: "<DEPLOYMENT_NAME>"                    # Replace with your deployment name
            action: upsert

      # Batch metrics for efficient sending
      batch:
        timeout: 30s
        send_batch_size: 1024

      # Transform metrics for better display in New Relic
      transform/nginx_metrics:
        metric_statements:
          - context: resource
            statements:
              # Customize the display name as needed for your New Relic dashboard
              - set(attributes["nginx.display.name"], Concat(["server", attributes["nginx.deployment.name"]], ":"))
      
      transform/metadata_nullify:
        metric_statements:
          - context: metric
            statements:
              - set(description, "")
              - set(unit, "")
    ```

3.  Configure the New Relic exporter:

    ```yaml
    exporters:
      # Send metrics to New Relic via OTLP
      otlp_http:
        endpoint: ${env:YOUR_NEWRELIC_OTLP_ENDPOINT}
        headers:
          api-key: ${env:YOUR_NEW_RELIC_LICENSE_KEY}
    ```

4.  Connect everything with a pipeline:

    ```yaml
    service:
      pipelines:
        metrics/nginx:
          receivers: [nginx]
          processors: [resourcedetection, resource/nginx, batch, transform/nginx_metrics, transform/metadata_nullify]
          exporters: [otlp_http]
    ```

#### Configuration parameters

The following table describes the key configuration parameters:

| Parameter                     | Description                                                                                                                |
| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `<YOUR_STUB_STATUS_ENDPOINT>` | Replace with the NGINX stub status endpoint (for example `http://127.0.0.1/basic_status`)                                  |
| `<DEPLOYMENT_NAME>`           | Replace with a unique deployment name for this NGINX server (for example `production-web-01`, `staging-api`, `prod-lb-01`) |
| `collection_interval`         | Interval in seconds to collect metrics. The default value is set to `30s`                                                  |
| `timeout`                     | Timeout in seconds to wait before sending batched metrics. The default value is set to `30s`                               |
| `send_batch_size`             | Number of metrics to batch before sending. The default value is set to `1024`                                              |

/\* \*\*Replace these values in the configuration above:\*\*

1\. \*\*Endpoint URL\*\*: Change \`http&#x3A;//&lt;NGINX_SERVER_IP>:&lt;YOUR_LOCAL_PORT>/nginx_status\` to match your stub status configuration from Step 1
2\. \*\*Deployment name\*\*: Replace \`&lt;DEPLOYMENT_NAME>\` with a unique identifier for this NGINX server

\*\*Choosing a good deployment name:\*\*
\- Use descriptive names like \`production-web-01\`, \`staging-api\`, or \`prod-lb-01\`
\- Must be unique across all NGINX servers within your New Relic account
\- This name will appear in dashboards and help you identify specific servers
\- Keep it short but meaningful for easy filtering and alerting \*/

**Step 2: Set up authentication**

Configure secure authentication so the OpenTelemetry Collector can send data to your New Relic account. This step sets up environment variables to keep your credentials secure.

1.  Get your New Relic credentials:

    -   License Key: Get your license key from the [API Keys UI page](https://one.newrelic.com/admin-portal/api-keys/home)
    -   OTLP Endpoint: Use your region's endpoint from [New Relic OTLP endpoints](https://docs.newrelic.com/docs/opentelemetry/best-practices/opentelemetry-otlp/#configure-endpoint-port-protocol)

2.  Configure the credentials:

    1.  Create a systemd override directory:

        ```bash
        sudo mkdir -p /etc/systemd/system/otelcol-contrib.service.d
        ```

    2.  Create the environment configuration file:

        ```bash
        cat <<EOF | sudo tee /etc/systemd/system/otelcol-contrib.service.d/environment.conf
        [Service]
        Environment="NEWRELIC_OTLP_ENDPOINT=<YOUR_NEWRELIC_OTLP_ENDPOINT>"  # Replace with your region's endpoint
        Environment="NEWRELIC_LICENSE_KEY=YOUR_NEW_RELIC_LICENSE_KEY"
        EOF
        ```

/\* \*\*Update the configuration with your credentials:\*\*
\- Replace \`https&#x3A;//otlp.nr-data.net:4318\` with your region's endpoint
\- Replace \`YOUR_LICENSE_KEY_HERE\` with your actual license key from above \*/

**Step 3: (Optional) Forward NGINX logs**

In addition to metrics, you can send NGINX [access and error logs](https://docs.nginx.com/nginx/admin-guide/monitoring/logging/) to New Relic for comprehensive monitoring and troubleshooting. These logs complement the [core NGINX metrics](https://docs.newrelic.com/docs/opentelemetry/integrations/nginx/nginx-otel-metrics-reference/) and provide detailed request-level insights.

> #### 💡 TIP
>
> Skip this step if you only need basic NGINX metrics and don't require detailed request logs.

1.  To configure NGINX to output JSON-formatted logs, add this to your NGINX configuration (`/etc/nginx/nginx.conf`):

    ```nginx
    http {
        # JSON log format for better parsing
        log_format json_combined escape=json
        '{'
          '"time":"$time_local",'
          '"remote_addr":"$remote_addr",'
          '"request":"$request",'
          '"status":$status,'
          '"bytes_sent":$body_bytes_sent,'
          '"request_time":$request_time,'
          '"referer":"$http_referer",'
          '"user_agent":"$http_user_agent"'
        '}';

        # Use the JSON format for access logs
        access_log /var/log/nginx/access.log json_combined;
        error_log /var/log/nginx/error.log warn;

        # Your existing configuration...
    }
    ```

2.  Reload NGINX to apply the changes:

    ```bash
    sudo nginx -t && sudo nginx -s reload
    ```

3.  To configure the collector for log forwarding, add these sections to your `/etc/otelcol-contrib/config.yaml`:

    ```yaml
    receivers:
      # Your existing nginx receiver...
      nginx:
        # existing configuration...

      # Add log receivers
      filelog/nginx_access:
        include:
          - /var/log/nginx/access.log

      filelog/nginx_error:
        include:
          - /var/log/nginx/error.log

    processors:
      # Your existing processors...

      # Add log processor
      transform/nginx_access_logs:
        log_statements:
        - context: resource
          statements:
            - set(attributes["nginx.display.name"], Concat(["server", attributes["nginx.deployment.name"]], ":"))
            - set(attributes["logtype"], "nginx")
      transform/nginx_error_logs:
        log_statements:
        - context: resource
          statements:
            - set(attributes["nginx.display.name"], Concat(["server", attributes["nginx.deployment.name"]], ":"))
            - set(attributes["logtype"], "nginx-error")

    service:
      pipelines:
        # Your existing metrics pipeline...

        # Add log pipelines
        logs/nginx-access:
          receivers: [filelog/nginx_access]
          processors: [resource/nginx, batch, transform/nginx_access_logs]
          exporters: [otlp_http]

        logs/nginx-error:
          receivers: [filelog/nginx_error]
          processors: [resource/nginx, batch, transform/nginx_error_logs]
          exporters: [otlp_http]
    ```

4.  Set permissions and apply configuration. Allow the collector to read NGINX log files:

    ```bash
    # Add collector user to adm group (has read access to logs)
    sudo usermod -a -G adm otelcol-contrib

    # Ensure log files are readable
    sudo chmod 644 /var/log/nginx/access.log
    sudo chmod 644 /var/log/nginx/error.log
    ```

**Step 4: Start monitoring**

Now that everything is configured, start the OpenTelemetry Collector and verify that data is flowing to New Relic.

1.  Start the collector:

    1.  Apply the configuration changes:
        ```bash
        sudo systemctl daemon-reload
        sudo systemctl restart otelcol-contrib.service
        ```

    2.  Verify the service is running:
        ```bash
        sudo systemctl status otelcol-contrib.service
        ```
        Expected output: `Active: active (running)` with no recent errors

2.  Verify data collection:

    1.  Check startup logs:
        ```bash
        sudo journalctl -u otelcol-contrib.service -n 20
        ```

    2.  Generate test traffic (to create metrics):
        ```bash
        # Make a few requests to your NGINX server
        curl http://localhost
        ```

    Allow time for initial data to appear in New Relic, then [access your NGINX dashboard](https://docs.newrelic.com/docs/opentelemetry/integrations/nginx/find-and-query-your-data#find-data) to verify data collection.

### Prometheus Receiver

Use this approach if you already have [nginx-prometheus-exporter](https://github.com/nginxinc/nginx-prometheus-exporter) running in your environment, or if you're migrating from a Prometheus-based monitoring stack.

> #### 💡 TIP
>
> **Recommended:** If you don't already have a Prometheus exporter running, use the **NRDOT collector** or **OpenTelemetry Collector Contrib** tabs instead. They connect directly to the NGINX stub status endpoint without needing an additional exporter component.

**Step 1: Configure the collector**

This configuration works with both **NRDOT** and **OTel Collector Contrib**. Place it in the appropriate config location:

-   **NRDOT:** `/etc/nrdot-collector/config.yaml`
-   **OTel Collector Contrib:** `/etc/otelcol-contrib/config.yaml`

> #### 💡 TIP
>
> **Backup your existing configuration before making changes:**
>
> ```bash
> # For NRDOT
> sudo cp /etc/nrdot-collector/config.yaml /etc/nrdot-collector/config.yaml.backup
>
> # For OTel Collector Contrib
> sudo cp /etc/otelcol-contrib/config.yaml /etc/otelcol-contrib/config.yaml.backup
> ```

Replace the file contents with the following configuration:

> #### ⚠️ IMPORTANT
>
> Replace `<YOUR_STUB_STATUS_ENDPOINT>` with your NGINX stub status URL (for example `http://127.0.0.1:8080/nginx_status`) and `<DEPLOYMENT_NAME>` with a unique name for this NGINX server.

```yaml
receivers:
  prometheus/nginx:
    config:
      scrape_configs:
        - job_name: nginx
          scrape_interval: 30s
          static_configs:
            - targets: ["localhost:9113"]  # Update if exporter runs on a different port

processors:
  resourcedetection/prom:
    detectors: [system]
    system:
      resource_attributes:
        host.name:
          enabled: false
        host.id:
          enabled: true

  resource/nginx_prom:
    attributes:
      - key: nginx.server.endpoint
        value: "<YOUR_STUB_STATUS_ENDPOINT>"  # Replace with your stub status URL
        action: upsert
      - key: nginx.deployment.name
        value: "<DEPLOYMENT_NAME>"            # Replace with a unique server name
        action: upsert
      # Strip prometheus receiver auto-labels — absent from nginxreceiver output
      - key: service.name
        action: delete
      - key: service.instance.id
        action: delete
      - key: net.host.name
        action: delete
      - key: net.host.port
        action: delete
      - key: server.address
        action: delete
      - key: server.port
        action: delete

  # Rename prometheus metric names to nginxreceiver schema names
  metricstransform/nginx_prom:
    transforms:
      - include: nginx_http_requests_total
        action: update
        new_name: nginx.requests
      - include: nginx_connections_accepted
        action: update
        new_name: nginx.connections_accepted
      - include: nginx_connections_handled
        action: update
        new_name: nginx.connections_handled
      - include: ^nginx_connections_(?P<state>active|reading|writing|waiting)$
        match_type: regexp
        action: combine
        new_name: nginx.connections_current

  # Keep only the 4 renamed nginx.* metrics
  filter/nginx_prom_only:
    metrics:
      include:
        match_type: regexp
        metric_names:
          - ^nginx\..*

  transform/nginx_metrics_prom:
    metric_statements:
      - context: resource
        statements:
          - set(attributes["nginx.display.name"], Concat(["server", attributes["nginx.deployment.name"]], ":"))

  transform/metadata_nullify_prom:
    metric_statements:
      - context: metric
        statements:
          - set(description, "")
          - set(unit, "")

  batch/nginx_prom:
    timeout: 30s
    send_batch_size: 1024

exporters:
  otlphttp/nginx_prom:
    endpoint: ${env:OTEL_EXPORTER_OTLP_ENDPOINT}
    headers:
      api-key: ${env:NEW_RELIC_LICENSE_KEY}

service:
  pipelines:
    metrics/nginx_prometheus:
      receivers: [prometheus/nginx]
      processors:
        - resourcedetection/prom
        - resource/nginx_prom
        - metricstransform/nginx_prom
        - filter/nginx_prom_only
        - transform/nginx_metrics_prom
        - transform/metadata_nullify_prom
        - batch/nginx_prom
      exporters: [otlphttp/nginx_prom]
```

#### Configuration parameters

| Parameter                     | Description                                                                                                                            |
| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `<YOUR_STUB_STATUS_ENDPOINT>` | Your NGINX stub status URL (for example `http://127.0.0.1:8080/nginx_status`). Used as the `nginx.server.endpoint` resource attribute. |
| `<DEPLOYMENT_NAME>`           | Unique name for this NGINX server (for example `production-web-01`). Appears in New Relic dashboards.                                  |
| `targets`                     | Address of the nginx-prometheus-exporter (default `localhost:9113`). Update if running on a different host or port.                    |
| `scrape_interval`             | How often to scrape metrics from the exporter. Default: `30s`.                                                                         |

**Step 2: Set up environment variables**

Create a systemd override to inject the required environment variables. Replace `<collector-service>` with your collector service name (`nrdot-collector` or `otelcol-contrib`):

```bash
sudo mkdir -p /etc/systemd/system/<collector-service>.service.d
```

Create the file `/etc/systemd/system/<collector-service>.service.d/environment.conf`:

```ini
[Service]
Environment="OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.nr-data.net:4318"
Environment="NEW_RELIC_LICENSE_KEY=YOUR_NEW_RELIC_LICENSE_KEY"
```

Replace `YOUR_NEW_RELIC_LICENSE_KEY` with your license key.

> #### 💡 TIP
>
> For EU accounts, use `OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.eu01.nr-data.net:4318`. See [Configure endpoint, port, and protocol](https://docs.newrelic.com/docs/opentelemetry/best-practices/opentelemetry-otlp/#configure-endpoint-port-protocol) for the full list of regional endpoints.

**Step 3: Start the collector**

Apply the configuration and restart the collector. Replace `<collector-service>` with `nrdot-collector` or `otelcol-contrib`:

```bash
sudo systemctl daemon-reload
sudo systemctl restart <collector-service>.service
```

Verify the service is running:

```bash
sudo systemctl status <collector-service>.service
sudo journalctl -u <collector-service>.service -n 20
```

Expected output: `Active: active (running)` with no errors.

**Step 4: Verify data in New Relic**

After a few minutes, run this NRQL query to confirm data is flowing. Replace `<DEPLOYMENT_NAME>` with the value you set in the configuration:

```sql
FROM Metric SELECT *
WHERE metricName LIKE 'nginx.%'
  AND nginx.deployment.name = '<DEPLOYMENT_NAME>'
SINCE 10 minutes ago
```

Allow time for initial data to appear in New Relic, then [access your NGINX dashboard](https://docs.newrelic.com/docs/opentelemetry/integrations/nginx/find-and-query-your-data#find-data) to verify data collection.

## View your data in New Relic [#find-data]

Once your setup is complete and data is flowing, you can access your NGINX metrics in New Relic dashboards and create custom alerts.

For complete instructions on accessing dashboards, querying data with NRQL, and creating alerts, see [Find and query your NGINX data](https://docs.newrelic.com/docs/opentelemetry/integrations/nginx/find-and-query-your-data).

## Troubleshooting [#troubleshooting]

If you encounter issues during setup, use this troubleshooting guide to diagnose and resolve common problems.

**NGINX stub status issues**

Getting 404 Not Found:

````bash
curl http://<NGINX_SERVER_IP>:<YOUR_LOCAL_PORT>/nginx_status
```

Solutions:
- Check that the location path matches your request URL
- Verify the configuration was added to the correct server block
- Run `sudo nginx -T | grep -A5 nginx_status` to confirm configuration is loaded

Getting 403 Forbidden:
- Ensure you're testing from the correct server IP `<NGINX_SERVER_IP>`
- Check your `allow`/`deny` directives in the NGINX configuration
- Verify no other access restrictions are blocking the request

Connection refused:
- Check if NGINX is running: `sudo systemctl status nginx`
- Verify your configured port isn't blocked: `sudo netstat -tlnp | grep :<YOUR_LOCAL_PORT>`
- Check firewall rules if applicable

````

**Collector service won't start**

Check service status:

````bash
sudo systemctl status ${collector_distro}.service
sudo journalctl -u ${collector_distro}.service -n 50
```

Common causes and fixes:
- YAML syntax errors - Fix indentation and syntax issues
- Missing environment variables - Verify credentials are set in environment file
- File permission issues - Run `sudo chown ${collector_distro}:${collector_distro} /etc/${collector_distro}/config.yaml`
- Invalid endpoint URLs - Check NGINX endpoint and New Relic OTLP endpoint
- Missing component configurations - Ensure all receivers, processors, and exporters referenced in the service pipelines section are actually defined in their respective configuration sections above

Restart after fixes:
```bash
sudo systemctl restart ${collector_distro}.service
```

````

**No data appears in New Relic**

Step-by-step diagnosis:

1.  Verify NGINX stub status works:
    ```bash
    curl http://<NGINX_SERVER_IP>:<YOUR_LOCAL_PORT>/nginx_status
    ```
    Should return connection statistics.

2.  Check Collector is running and healthy:
    ```bash
    sudo systemctl status ${collector_distro}.service
    sudo journalctl -u ${collector_distro} -n 20
    ```
    The logs will provide detailed context if there are any configuration or runtime issues with the OpenTelemetry Collector.

3.  Check for data with NRQL:
    ```sql
    FROM Metric SELECT * WHERE nginx.deployment.name LIKE '%production%' LIMIT 1
    ```

**Log forwarding issues**

No logs appearing in New Relic:

````bash
# Check Collector logs for file errors
sudo journalctl -u ${collector_distro} -f | grep -i "filelog\|error"
```
Common issues:
- File permission errors - Add collector to adm group: `sudo usermod -a -G adm ${collector_distro}`
- Wrong file paths - Verify log file locations in your config

````

## Next steps [#next-steps]

Learn more about your data:

-   [Find and query your NGINX data](https://docs.newrelic.com/docs/opentelemetry/integrations/nginx/find-and-query-your-data/) - Access dashboards, create custom queries, and set up alerts
-   [NGINX OpenTelemetry metrics and attributes reference](https://docs.newrelic.com/docs/opentelemetry/integrations/nginx/nginx-otel-metrics-reference/) - Complete metrics reference with descriptions and examples
-   [NGINX OpenTelemetry overview](https://docs.newrelic.com/docs/opentelemetry/integrations/nginx/nginx-otel-overview/) - Understand collected metrics, attributes, and use cases

Explore related monitoring:

-   [Monitor NGINX Plus with OpenTelemetry](https://docs.newrelic.com/docs/opentelemetry/integrations/nginx-plus/nginx-plus-otel/) - For commercial NGINX Plus deployments
-   [Monitor NGINX on Kubernetes](https://docs.newrelic.com/docs/opentelemetry/integrations/nginx/nginx-otel-kubernetes/) - For containerized environments
