---
title: "Monitoring Nginx Requests with Prometheus"
description: "A walkthrough on deploying Prometheus and Grafana with Docker Compose, monitoring Nginx request metrics via nginx-prometheus-exporter, and validating performance with K6 load testing."
canonical_url: "https://blog.markkulab.net/en/post/prometheus-monitoring-nginx-requests"
author: "Mark Ku"
author_url: "https://blog.markkulab.net/en/author/mark-ku"
site: "Mark Ku's Tech Notes"
date_published: "2024-11-25T01:01:35+08:00"
category: "Cloud"
tags: ["prometheus", "grafana", "nginx", "docker", "monitoring", "k6"]
language: "en"
license: "CC BY 4.0"
license_url: "https://creativecommons.org/licenses/by/4.0/"
attribution: "when reusing or quoting, credit the author and link back to the original"
---

# Monitoring Nginx Requests with Prometheus

## Introduction
Prometheus and Grafana are a common combination in the Kubernetes ecosystem. This post demonstrates how to use Prometheus to monitor Nginx requests and visualize the data with Grafana.

## Understanding Nginx `stub_status`

Before spinning up the Prometheus container, let's take a look at Nginx's `stub_status` module. It exposes basic runtime metrics about Nginx, and Prometheus primarily relies on `stub_status` to collect data from Nginx.

### Configuring the Dockerfile

First, create a Dockerfile that builds on the Nginx image with custom configuration:

```dockerfile
FROM nginx
COPY nginx.conf /etc/nginx/conf.d/default.conf
```

### Creating `nginx.conf`

Next, write an `nginx.conf` to enable the Nginx status page, which Prometheus will scrape:

```nginx
server {
    listen 80;  # 使用本地端口
    server_name localhost;  # 設定為 localhost

    location /nginx_status {
        stub_status on;  # 啟用狀態模組
        access_log off;
        allow all;  # 允許所有 IP 訪問
    }
}
```

### Build and Start the Container

Build the Docker image and start the container:

```bash
docker build -t my-nginx:latest .
docker run -d -p 8881:80 --name nginx-prometheus-exporter my-nginx:latest
```

## Accessing the Nginx Status Page

Once the container is running, visit `http://localhost:8881/nginx_status` and you'll see a page similar to this:

![Nginx Status](https://blog.markkulab.net/content/markku/posts/prometheus-monitoring-nginx-requests/images/nginx-status.png)

### Nginx Status Fields Explained

**Active connections: 2**
There are currently 2 active connections.

**server accepts handled requests: 2 2 2**
- **2**: Number of accepted connections.
- **2**: Number of successfully handled connections.
- **2**: Total number of requests (can exceed connection count, since one connection can serve multiple requests).

**Reading: 0 Writing: 1 Waiting: 1**
- **Reading: 0**: Connections currently reading a request.
- **Writing: 1**: Connections currently sending a response.
- **Waiting: 1**: Idle connections waiting for the next request (HTTP Keep-Alive).

Note: The server load is currently light — 2 connections total, 1 actively handling a request and 1 waiting for the next one.

## Container Stack Overview

grafana (dashboard visualization) > prometheus-exporter (actively scrapes data) > nginx-prometheus-exporter (exposes Nginx metrics to Prometheus) > nginx status (web server providing status information)

## Setting Up All Service Containers

Remove any previously created test containers, then create a `deployment.yaml` to deploy all services together.

### `deployment.yaml` Example

```yaml
version: "3.8"
services:
  mynginx:
    build: ./nginx/
    container_name: mynginx
    ports:
      - 8885:80

  nginx-prometheus-exporter:
    image: nginx/nginx-prometheus-exporter
    container_name: nginx-prometheus-exporter
    command: -nginx.scrape-uri http://nginx:80/nginx_status
    ports:
      - 9113:9113
    depends_on:
      - nginx

  prometheus:
    image: prom/prometheus:v2.35.0
    container_name: prometheus
    volumes:
      - ./prometheus.yaml:/etc/prometheus/prometheus.yaml
      - ./prometheus_data:/prometheus
    command:
      - "--config.file=/etc/prometheus/prometheus.yaml"
    ports:
      - "9090:9090"

  renderer:
    image: grafana/grafana-image-renderer
    environment:
      BROWSER_TZ: Asia/Taipei
    ports:
      - "8082:8081"

  grafana:
    image: grafana/grafana
    container_name: grafana
    volumes:
      - ./grafana_data:/var/lib/grafana
    environment:
      GF_SECURITY_ADMIN_PASSWORD: pass
      GF_RENDERING_SERVER_URL: http://renderer:8082/render
      GF_RENDERING_CALLBACK_URL: http://grafana:3007/
      GF_LOG_FILTERS: rendering:debug
    depends_on:
      - prometheus
      - renderer
    ports:
      - "3007:3000"
```

### Prometheus Configuration

Write a `prometheus.yaml` to configure how Prometheus scrapes data:

```yaml
global:
  scrape_interval: 5s  # 設定抓取頻率
  external_labels:
    monitor: "my-monitor"

scrape_configs:
  - job_name: "prometheus"
    static_configs:
      - targets: ["localhost:9090"]
  - job_name: "nginx_exporter"
    static_configs:
      - targets: ["nginx-prometheus-exporter:9113"]
```

Start the services with Docker Compose:

```bash
docker-compose -f ./deployment.yaml up -d
```

## Checking Prometheus Targets

Open [http://localhost:9090/targets](http://localhost:9090/targets) in your browser to view the status of Prometheus scrape targets.

![Prometheus Targets](https://blog.markkulab.net/content/markku/posts/prometheus-monitoring-nginx-requests/images/prometheus-target.png)

## Graphing Nginx Metrics in Prometheus

Switch to the Graph tab in Prometheus and search for `nginx` to plot real-time charts based on Nginx metrics:

![Prometheus Graph](https://blog.markkulab.net/content/markku/posts/prometheus-monitoring-nginx-requests/images/prometheus-graph.png)

That said, Prometheus charts are fairly basic. For richer dashboards and more filtering options, Grafana is the way to go.

## Connecting Grafana to Prometheus

1. Open the Grafana dashboard ([http://localhost:3007/](http://localhost:3007/)).
2. Go to "Connection", click "Add new connection", and select "Prometheus".

![Grafana Prometheus](https://blog.markkulab.net/content/markku/posts/prometheus-monitoring-nginx-requests/images/grafana-add-prometheus.png)

## Creating a Grafana Dashboard

You can download a ready-made dashboard template from the [Grafana Dashboard marketplace](https://grafana.com/grafana/dashboards/) to display Nginx metrics.

### Download a Dashboard Template

[Download Dashboard JSON](https://grafana.com/grafana/dashboards/18144-nginx2/)

![Download Dashboard Settings](https://blog.markkulab.net/content/markku/posts/prometheus-monitoring-nginx-requests/images/download-dashboard-json.png)

## Importing the Dashboard Template

Back in Grafana, click "New Import" and import the JSON template you downloaded.

![Import Dashboard Settings](https://blog.markkulab.net/content/markku/posts/prometheus-monitoring-nginx-requests/images/import-dashboard.png)

## Running a K6 Load Test

Write a K6 load test script to simulate traffic and validate Nginx performance:

```javascript
import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '30s', target: 3000 },  // 負載測試從 0 到 3000 個虛擬使用者，持續 30 秒
    { duration: '1m30s', target: 3000 }, // 維持 3000 個虛擬使用者，持續 1 分 30 秒
    { duration: '20s', target: 0 },      // 減少虛擬使用者數量
  ]
};

export default function () {
  const res = http.get('http://192.168.0.88:8885/nginx_status'); // your nginx ip 
  check(res, { 'status was 200': (r) => r.status == 200 });
  sleep(1);
}
```

Using the Docker-based K6 image means no local installation required:

```
// Windows 腳本
cat script.js | docker run --rm -i grafana/k6 run -
```

## Viewing Live Data in Grafana

After running the load test, the Grafana dashboard will display live Nginx metrics such as active connection counts.

![Grafana Live Data](https://blog.markkulab.net/content/markku/posts/prometheus-monitoring-nginx-requests/images/final-dashboard.png)

## Source Code

All code and configuration files are available on [GitHub](https://github.com/markku636/Prometheus).

## References
* [使用 Prometheus 和 Grafana 打造監控預警系統 (Docker 篇)](https://pin-yi.me/blog/docker/prometheus-grafana-docker/#prometheus)
* [prometheus-adapter结合custom metrics API 实现kubetnetes自定义HPA](https://blog.csdn.net/weixin_43391291/article/details/142212854)

---

## About this article and its author

Originally published on [Mark Ku's Tech Notes](https://blog.markkulab.net/en/post/prometheus-monitoring-nginx-requests)

License: [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) — when reusing or quoting, credit the author and link back to the original

### About the author

**[Mark Ku](https://blog.markkulab.net/en/author/mark-ku)** — Software Solution Provider

- 10+ years senior software engineer, now an AI Builder
- Focused on large-platform architecture — North-American e-commerce, AI SaaS subscription billing
- Combining AI Agents and automation to build evolvable product foundations

### Free tools built by the author

All of these are free to use:

- [Free PDF Sign Tool](https://blog.markkulab.net/en/tools/pdf-sign): Online PDF sign tool — draw, type, or upload a signature, then drag, resize, and download. Everything runs in your browser; nothing is uploaded.
- [VS Code Refactory](https://blog.markkulab.net/en/tools/refactory): Refactory is a VS Code refactoring extension: 34 actions plus a 37-rule code-smell inspection layer with a Code Health dashboard, across 18 languages, backed by 534 tests. It learns your repo's conventions: where interfaces live, where DI is registered, whether 'use client' belongs. It ranks files by git churn × complexity so you know what to fix first, and hands any smell to the Claude Code already on your machine. Free to use, and your source never leaves your computer.
- [DB-Kit Database Manager](https://blog.markkulab.net/en/tools/db-kit): DB-Kit is a lightweight, cross-platform database manager built with Tauri + Rust + React. Manage MySQL, MariaDB, PostgreSQL, SQL Server, Oracle, SQLite, MongoDB, Redis, Kafka, Elasticsearch and RabbitMQ from one consistent interface: passwords encrypted in the OS keychain, SSH tunnels, full CRUD, a visual query builder, stacked multi-statement result sets, cross-connection data transfer and compare/sync, Excel / CSV import & export, visualized execution plans, ER diagrams, scheduled backups, SQL stress testing with p50–p99 latency percentiles, a 15-rule SQL review engine, Kafka message browsing with monitoring & alerts, a bilingual UI (Traditional Chinese / English), a built-in AI assistant (natural-language SQL, AI review and tuning advice) and the dbk CLI. Free and open source (MIT), with installers for Windows, macOS and Linux.
- [VS Code Super Mermaid](https://blog.markkulab.net/en/tools/super-mermaid): Super Mermaid is a VS Code extension for beautiful Mermaid diagrams out of the box: auto-colored live preview, mouse pan & zoom, high-res PNG / SVG export, 21 templates and multiple themes. Free and open source (MIT).
- [React Super Mermaid](https://blog.markkulab.net/en/tools/react-super-mermaid): react-super-mermaid is an open-source React component library: render beautiful Mermaid diagrams with a single <MermaidViewer>, with built-in colorful / sketch themes, pan & zoom, in-diagram search, and high-res SVG / PNG export. Lightweight, SSR-safe, fully typed. Free and open source (MIT).
- [Jira / Confluence Super Mermaid](https://blog.markkulab.net/en/tools/jira-super-mermaid): An Atlassian Forge app: write Mermaid syntax directly inside a Jira issue or a Confluence page and get flowcharts, sequence diagrams, state machines and Gantt charts. 11 diagram types, SVG / PNG export, light and dark themes, full CJK support. Runs on Atlassian: your diagrams live in your own site and the app calls no third-party service. Free, coming soon to the Atlassian Marketplace.
- [Mermaid Live Preview](https://blog.markkulab.net/en/tools/mermaid-preview): Write Mermaid in your browser, see it render instantly, and share the whole diagram as a single link. No sign-up, nothing uploaded to a server, and mermaid.live share links work as-is.
- [React Intl Phone Number](https://blog.markkulab.net/en/tools/react-intl-phone-number): react-intl-phone-number is an open-source React component: framework-agnostic and antd-free, with E.164 in/out, a searchable flag / country-code dropdown, configurable validation levels (strict / mobile-strict / loose), themeable CSS, and i18n — phone logic powered by google-libphonenumber. Lightweight and fully typed. Free and open source (MIT).
- [Uptime Kuma Cluster](https://blog.markkulab.net/en/tools/uptime-kuma-cluster): Turn single-node Uptime Kuma into a highly available cluster: OpenResty + Lua smart load balancing, shared MariaDB state, health checks and automatic failover, plus cluster-management REST APIs. One Docker Compose command to start. Free and open source (MIT).
- [Special Education](https://blog.markkulab.net/en/education): Learning materials crafted for special education students

### Daily podcasts

- [Mark's Tech Insights — Daily AI News](https://blog.markkulab.net/en/category/tech-news): Daily curated AI and tech trends. Catch the latest developments via audio summaries — covering AI applications, software architecture, DevOps, and engineering practice. — RSS: https://blog.markkulab.net/feed.xml
- [AI股市蝦聊](https://blog.markkulab.net/en/category/ai-stock-chat): Every trading day, an AI-analyzed take on the Taiwan stock market, delivered as a two-host conversation covering the session and the next-day outlook. — RSS: https://blog.markkulab.net/ai-stock-chat/feed.xml
- [開源好物週報](https://blog.markkulab.net/en/category/open-source-weekly): A weekly two-host pick of free open-source tools surfaced from real Hacker News, GitHub, and Reddit buzz — what pain they solve and the fastest way to get started. — RSS: https://blog.markkulab.net/open-source-weekly/feed.xml

### Newsletter

[Subscribe to the newsletter](https://blog.markkulab.net/en/subscribe) — Be the first to know about new posts. No spam, unsubscribe anytime.
