---
title: "Nginx integration | Grafana Cloud documentation"
description: "Learn about Nginx Grafana Cloud integration."
---

> For a curated documentation index, see [llms.txt](/llms.txt). For the complete documentation index, see [llms-full.txt](/llms-full.txt).

# Nginx integration for Grafana Cloud

NGINX is open source software for web serving, reverse proxying, caching, load balancing, media streaming, and more. It started out as a web server designed for maximum performance and stability. In addition to its HTTP server capabilities, NGINX can also function as a proxy server for email (IMAP, POP3, and SMTP) and a reverse proxy and load balancer for HTTP, TCP, and UDP servers.

This integration includes 2 pre-built dashboards to help monitor and visualize Nginx metrics and logs.

## Before you begin

For this integration to work, you must first configure a custom JSON access log in the NGINX configuration, as well as enable the [Stub Status Module](https://nginx.org/en/docs/http/ngx_http_stub_status_module.html#example) and configure the [nginx-prometheus-exporter](https://github.com/nginxinc/nginx-prometheus-exporter).

First, to enable the logging, place the following configuration within the `http` block, by the `# Logging Settings` line:

![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```none
log_format json_analytics escape=json '{'
'"msec": "$msec", ' # request unixtime in seconds with a milliseconds resolution
'"connection": "$connection", ' # connection serial number
'"connection_requests": "$connection_requests", ' # number of requests made in connection
'"pid": "$pid", ' # process pid
'"request_id": "$request_id", ' # the unique request id
'"request_length": "$request_length", ' # request length (including headers and body)
'"remote_addr": "$remote_addr", ' # client IP
'"remote_user": "$remote_user", ' # client HTTP username
'"remote_port": "$remote_port", ' # client port
'"time_local": "$time_local", '
'"time_iso8601": "$time_iso8601", ' # local time in the ISO 8601 standard format
'"request": "$request", ' # full path no arguments if the request
'"request_uri": "$request_uri", ' # full path and arguments if the request
'"args": "$args", ' # args
'"status": "$status", ' # response status code
'"body_bytes_sent": "$body_bytes_sent", ' # the number of body bytes exclude headers sent to a client
'"bytes_sent": "$bytes_sent", ' # the number of bytes sent to a client
'"http_referer": "$http_referer", ' # HTTP referer
'"http_user_agent": "$http_user_agent", ' # user agent
'"http_x_forwarded_for": "$http_x_forwarded_for", ' # http_x_forwarded_for
'"http_host": "$http_host", ' # the request Host: header
'"server_name": "$server_name", ' # the name of the vhost serving the request
'"request_time": "$request_time", ' # request processing time in seconds with msec resolution
'"upstream": "$upstream_addr", ' # upstream backend server for proxied requests
'"upstream_connect_time": "$upstream_connect_time", ' # upstream handshake time incl. TLS
'"upstream_header_time": "$upstream_header_time", ' # time spent receiving upstream headers
'"upstream_response_time": "$upstream_response_time", ' # time spent receiving upstream body
'"upstream_response_length": "$upstream_response_length", ' # upstream response length
'"upstream_cache_status": "$upstream_cache_status", ' # cache HIT/MISS where applicable
'"ssl_protocol": "$ssl_protocol", ' # TLS protocol
'"ssl_cipher": "$ssl_cipher", ' # TLS cipher
'"scheme": "$scheme", ' # http or https
'"request_method": "$request_method", ' # request method
'"server_protocol": "$server_protocol", ' # request protocol, like HTTP/1.1 or HTTP/2.0
'"pipe": "$pipe", ' # "p" if request was pipelined, "." otherwise
'"gzip_ratio": "$gzip_ratio"'
'}';

access_log /var/log/nginx/json_access.log json_analytics;
```

To use country mapping, you must enable the [GeoIP2](https://docs.nginx.com/nginx/admin-guide/dynamic-modules/geoip2/) module, and add the relevant `geoip_country_code` configuration to the access log, replacing the last few lines of the previous snippet with the following, starting at `"gzip_ratio"`:

![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```none
'"gzip_ratio": "$gzip_ratio", '
'"geoip_country_code": "$geoip_country_code"'
'}';

geoip_country /etc/nginx/GeoLite2-Country.mmdb {
  $geoip_country_code default=US source=$remote_addr country iso_code;
}

access_log /var/log/nginx/json_access.log json_analytics;
```

Then, to enable scraping metrics from your NGINX instance, enable the [Stub Status Module](https://nginx.org/en/docs/http/ngx_http_stub_status_module.html#example) in your NGINX configuration.

![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```none
server {
  listen 127.0.0.1:8080;
  server_name localhost;

  location /stub_status {
    stub_status on;
    # Optionally restrict access to IP addresses if needed
    # allow 127.0.0.1;
    # deny all;
  }
}
```

The [nginx-prometheus-exporter](https://github.com/nginxinc/nginx-prometheus-exporter) should then be configured to scrape NGINX. Adjust the `stub_status` module as required for your environment.

## Install Nginx integration for Grafana Cloud

1. In your Grafana Cloud stack, click **Connections** in the left-hand menu.
2. Find **Nginx** and click its tile to open the integration.
3. Review the prerequisites in the **Configuration Details** tab and set up Grafana Alloy to send Nginx metrics and logs to your Grafana Cloud instance.
4. Click **Install** to add this integration’s pre-built dashboards to your Grafana Cloud instance, and you can start monitoring your Nginx setup.

## Configuration snippets for Grafana Alloy

### Advanced mode

The following snippets provide examples to guide you through the configuration process.

To instruct Grafana Alloy to scrape your Nginx instances, **manually** copy and append the snippets to your alloy configuration file, then follow subsequent instructions.

### Advanced metrics snippets

Alloy ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```alloy
discovery.relabel "metrics_integrations_integrations_nginx" {
	targets = [{
		__address__  = "localhost:9113",
	}]

	rule {
		target_label = "instance"
		replacement  = constants.hostname
	}
}

prometheus.scrape "metrics_integrations_integrations_nginx" {
  targets    = discovery.relabel.metrics_integrations_integrations_nginx.output
  forward_to = [prometheus.remote_write.metrics_service.receiver]
  job_name   = "integrations/nginx"
}
```

To monitor your NGINX instance, you must use a [discovery.relabel](/docs/alloy/latest/reference/components/discovery.relabel/) component to discover your [nginx-prometheus-exporter](https://github.com/nginxinc/nginx-prometheus-exporter) endpoint and apply appropriate labels, followed by a [prometheus.scrape](/docs/alloy/latest/reference/components/prometheus.scrape) component to scrape it.

Configure the following properties within each `discovery.relabel` component:

- `__address__`: The address to your NGINX Prometheus exporter metrics endpoint.
- `instance` label: `constants.hostname` sets the `instance` label to your Grafana Alloy server hostname. If that is not suitable, change it to a value uniquely identifies this NGINX instance.

If you have multiple NGINX servers to scrape, configure one `discovery.relabel` for each and scrape them by including each under `targets` within the `prometheus.scrape` component.

### Advanced logs snippets

#### darwin

Alloy ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```alloy
local.file_match "logs_integrations_integrations_nginx" {
	path_targets = [{
		__address__ = "localhost",
		__path__    = "<path to json nginx access log>",
		host        = "<http_hostname>",
		instance    = constants.hostname,
		job         = "integrations/nginx",
	}]
}

loki.source.file "logs_integrations_integrations_nginx" {
	targets    = local.file_match.logs_integrations_integrations_nginx.targets
	forward_to = [loki.write.grafana_cloud_loki.receiver]
}
```

To monitor your Nginx instance logs, you will use a combination of the following components:

- [local.file\_match](/docs/alloy/latest/reference/components/local.file_match) defines where to find the log file to be scraped. Change the following properties according to your environment:
  
  - `__address__`: The Nginx instance address
  - `__path__`: The path to the log file.
  - `instance` label: `constants.hostname` sets the `instance` label to your Grafana Alloy server hostname. If that is not suitable, change it to a value uniquely identifies this Nginx instance.
- [loki.source.file](/docs/alloy/latest/reference/components/loki.source.file) sends logs to Loki.

#### linux

Alloy ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```alloy
local.file_match "logs_integrations_integrations_nginx" {
	path_targets = [{
		__address__ = "localhost",
		__path__    = "<path to json nginx access log>",
		host        = "<http_hostname>",
		instance    = constants.hostname,
		job         = "integrations/nginx",
	}]
}

loki.source.file "logs_integrations_integrations_nginx" {
	targets    = local.file_match.logs_integrations_integrations_nginx.targets
	forward_to = [loki.write.grafana_cloud_loki.receiver]
}
```

To monitor your Nginx instance logs, you will use a combination of the following components:

- [local.file\_match](/docs/alloy/latest/reference/components/local.file_match) defines where to find the log file to be scraped. Change the following properties according to your environment:
  
  - `__address__`: The Nginx instance address
  - `__path__`: The path to the log file.
  - `instance` label: `constants.hostname` sets the `instance` label to your Grafana Alloy server hostname. If that is not suitable, change it to a value uniquely identifies this Nginx instance.
- [loki.source.file](/docs/alloy/latest/reference/components/loki.source.file) sends logs to Loki.

#### windows

Alloy ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```alloy
local.file_match "logs_integrations_integrations_nginx" {
	path_targets = [{
		__address__ = "localhost",
		__path__    = "<path to json nginx access log>",
		host        = "<http_hostname>",
		instance    = constants.hostname,
		job         = "integrations/nginx",
	}]
}

loki.source.file "logs_integrations_integrations_nginx" {
	targets    = local.file_match.logs_integrations_integrations_nginx.targets
	forward_to = [loki.write.grafana_cloud_loki.receiver]
}
```

To monitor your Nginx instance logs, you will use a combination of the following components:

- [local.file\_match](/docs/alloy/latest/reference/components/local.file_match) defines where to find the log file to be scraped. Change the following properties according to your environment:
  
  - `__address__`: The Nginx instance address
  - `__path__`: The path to the log file.
  - `instance` label: `constants.hostname` sets the `instance` label to your Grafana Alloy server hostname. If that is not suitable, change it to a value uniquely identifies this Nginx instance.
- [loki.source.file](/docs/alloy/latest/reference/components/loki.source.file) sends logs to Loki.

## Kubernetes instructions

Instructions for Kubernetes

### Before you begin with Kubernetes

**Please note**: These instructions assume the use of the [Kubernetes Monitoring Helm chart](https://github.com/grafana/k8s-monitoring-helm)

For this integration to work, you must first configure a custom JSON access log in the NGINX configuration, as well as enable the [Stub Status Module](https://nginx.org/en/docs/http/ngx_http_stub_status_module.html#example) and configure the [nginx-prometheus-exporter](https://github.com/nginxinc/nginx-prometheus-exporter).

First, to enable the logging, place the following configuration within the `http` block, by the `# Logging Settings` line:

![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```none
log_format json_analytics escape=json '{'
'"msec": "$msec", ' # request unixtime in seconds with a milliseconds resolution
'"connection": "$connection", ' # connection serial number
'"connection_requests": "$connection_requests", ' # number of requests made in connection
'"pid": "$pid", ' # process pid
'"request_id": "$request_id", ' # the unique request id
'"request_length": "$request_length", ' # request length (including headers and body)
'"remote_addr": "$remote_addr", ' # client IP
'"remote_user": "$remote_user", ' # client HTTP username
'"remote_port": "$remote_port", ' # client port
'"time_local": "$time_local", '
'"time_iso8601": "$time_iso8601", ' # local time in the ISO 8601 standard format
'"request": "$request", ' # full path no arguments if the request
'"request_uri": "$request_uri", ' # full path and arguments if the request
'"args": "$args", ' # args
'"status": "$status", ' # response status code
'"body_bytes_sent": "$body_bytes_sent", ' # the number of body bytes exclude headers sent to a client
'"bytes_sent": "$bytes_sent", ' # the number of bytes sent to a client
'"http_referer": "$http_referer", ' # HTTP referer
'"http_user_agent": "$http_user_agent", ' # user agent
'"http_x_forwarded_for": "$http_x_forwarded_for", ' # http_x_forwarded_for
'"http_host": "$http_host", ' # the request Host: header
'"server_name": "$server_name", ' # the name of the vhost serving the request
'"request_time": "$request_time", ' # request processing time in seconds with msec resolution
'"upstream": "$upstream_addr", ' # upstream backend server for proxied requests
'"upstream_connect_time": "$upstream_connect_time", ' # upstream handshake time incl. TLS
'"upstream_header_time": "$upstream_header_time", ' # time spent receiving upstream headers
'"upstream_response_time": "$upstream_response_time", ' # time spent receiving upstream body
'"upstream_response_length": "$upstream_response_length", ' # upstream response length
'"upstream_cache_status": "$upstream_cache_status", ' # cache HIT/MISS where applicable
'"ssl_protocol": "$ssl_protocol", ' # TLS protocol
'"ssl_cipher": "$ssl_cipher", ' # TLS cipher
'"scheme": "$scheme", ' # http or https
'"request_method": "$request_method", ' # request method
'"server_protocol": "$server_protocol", ' # request protocol, like HTTP/1.1 or HTTP/2.0
'"pipe": "$pipe", ' # "p" if request was pipelined, "." otherwise
'"gzip_ratio": "$gzip_ratio"'
'}';

access_log /var/log/nginx/json_access.log json_analytics;
```

To use country mapping, you must enable the [GeoIP2](https://docs.nginx.com/nginx/admin-guide/dynamic-modules/geoip2/) module, and add the relevant `geoip_country_code` configuration to the access log, replacing the last few lines of the previous snippet with the following, starting at `"gzip_ratio"`:

![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```none
'"gzip_ratio": "$gzip_ratio", '
'"geoip_country_code": "$geoip_country_code"'
'}';

geoip_country /etc/nginx/GeoLite2-Country.mmdb {
  $geoip_country_code default=US source=$remote_addr country iso_code;
}

access_log /var/log/nginx/json_access.log json_analytics;
```

Then, to enable scraping metrics from your NGINX instance, enable the [Stub Status Module](https://nginx.org/en/docs/http/ngx_http_stub_status_module.html#example) in your NGINX configuration.

![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```none
server {
  listen 127.0.0.1:8080;
  server_name localhost;

  location /stub_status {
    stub_status on;
    # Optionally restrict access to IP addresses if needed
    # allow 127.0.0.1;
    # deny all;
  }
}
```

Finally, deploy the [nginx-prometheus-exporter](https://github.com/nginxinc/nginx-prometheus-exporter) to your cluster and then be configured to scrape NGINX. Adjust the `stub_status` module as required for your environment.

Update the provided configuration for the Kubernetes Monitoring Helm Chart to discover your [nginx-prometheus-exporter](https://github.com/nginxinc/nginx-prometheus-exporter) endpoint and apply appropriate labels, followed by a [prometheus.scrape](/docs/alloy/latest/reference/components/prometheus.scrape) component to scrape it.

### Configuration snippets for Kubernetes Helm chart

The following snippets provide examples to guide you through the configuration process.

To scrape your NGINX instances, **manually** modify your Kubernetes Monitoring Helm chart with these configuration snippets.

Replace any values between the angle brackets `<>` in the provided snippets with your desired configuration values.

#### Metrics snippets

Alloy ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```alloy
podLogs:
    extraDiscoveryRules: |-
        rule {
            source_labels = ["__meta_kubernetes_pod_label_<nginx_label>"]
            regex         = "<nginx_label_value>"
            replacement   = "nginx"
            target_label  = "integration"
        }

        rule {
            source_labels = ["integration", "__meta_kubernetes_namespace", "__meta_kubernetes_pod_container_name"]
            separator = "-"
            regex = "nginx-(.*-.*)"
            target_label = "instance"
        }

        rule {
            source_labels = ["integration"]
            regex = "nginx"
            replacement = "integrations/nginx"
            target_label = "job"
        }
```

## Dashboards

The Nginx integration installs the following dashboards in your Grafana Cloud instance to help monitor your system.

- NGINX Logs
- NGINX Overview

## Metrics

The most important metrics provided by the Nginx integration, which are used on the pre-built dashboards, are as follows:

- nginx\_connections\_accepted
- nginx\_connections\_active
- nginx\_connections\_handled
- nginx\_connections\_reading
- nginx\_connections\_waiting
- nginx\_connections\_writing
- nginx\_http\_requests\_total
- nginx\_up
- up

## Changelog

md ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```md
# 1.1.2 - November 2024

- Add missing metrics scrape snippet

# 1.1.1 - November 2024

- Update status panel check queries

# 1.1.0 - October 2024

* Update mixin to latest
  * Add metric dashboard based on nginx-prometheus-exporter
* Update Alloy scrape config

# 1.0.1 - August 2024

* Update mixin to latest
  * Update queries to use `$__interval` instead of hardcoded time ranges

# 1.0.0 - June 2024

* Update mixin to latest
  * Update all `cluster` queries to be conditional
  * Remove news panel
* Update installation instructions
* Add missing job label to Alloy snippet

# 0.0.5 - September 2023

* New Filter Metrics option for configuring the Grafana Agent, which saves on metrics cost by dropping any metric not used by this integration. Beware that anything custom built using metrics that are not on the snippet will stop working.

# 0.0.4 - August 2023

* Add regex filter for logs datasource

# 0.0.3 - July 2023

* Update mixin to latest version:
  - Add cluster variable to support Kubernetes clusters
* Added Grafana Agent Operator configuration snippet to support nginx in a Kubernetes cluster.

# 0.0.2 - September 2022

* Update mixin to latest version:
  - Update queries to use $__rate_interval

# 0.0.1 - May 2021

* Initial release
```

## Cost

By connecting your Nginx instance to Grafana Cloud, you might incur charges. To view information on the number of active series that your Grafana Cloud account uses for metrics included in each Cloud tier, see [Active series and dpm usage](/docs/grafana-cloud/fundamentals/active-series-and-dpm/) and [Cloud tier pricing](/products/cloud/pricing/).
