Nginx Plugin

Monitor Nginx web server with real-time connection statistics, request rates, and worker status.

Overview

The Nginx plugin collects metrics from Nginx's stub_status module including:

  • Connection Statistics - Active connections, accepts, handled connections
  • Request Metrics - Total requests, requests per second
  • Worker States - Reading, writing, waiting connections
  • Connection Rate - Connection accept/drop rate

Requirements

Nginx Version

  • Any version with stub_status module compiled
  • Most common: Nginx 1.14+, 1.18+, 1.20+, 1.22+, 1.24+
  • Tested with: Nginx 1.18, 1.20, 1.22, 1.24, 1.25

Python Dependencies

pip install requests>=2.28.0

Auto-installed when using PLUGINS=nginx during agent installation.

Nginx Module

Nginx must be compiled with http_stub_status_module:

# Check if module is available
nginx -V 2>&1 | grep -o with-http_stub_status_module

Expected output: with-http_stub_status_module

Note: Most pre-built Nginx packages include this module by default.

Configuration

Basic Configuration

plugins:
  nginx:
    enabled: true
    status_url: http://127.0.0.1/nginx_status

Custom Status URL

plugins:
  nginx:
    enabled: true
    status_url: http://127.0.0.1:8080/status

Remote Nginx Server

plugins:
  nginx:
    enabled: true
    status_url: http://nginx-server.example.com/nginx_status

All Configuration Options

plugins:
  nginx:
    enabled: true                                # Enable/disable plugin
    status_url: http://127.0.0.1/nginx_status    # Nginx stub_status URL
    timeout: 5                                   # Request timeout in seconds

Environment Variables

Configuration can be overridden with environment variables:

export NGINX_STATUS_URL="http://127.0.0.1/nginx_status"

Nginx Setup

Enable stub_status Module

Edit your Nginx configuration file (e.g., /etc/nginx/sites-available/default or /etc/nginx/nginx.conf):

Option 1: Dedicated Server Block (Recommended)

server {
    listen 127.0.0.1:80;
    server_name localhost;

    location /nginx_status {
        stub_status on;
        access_log off;
        allow 127.0.0.1;
        deny all;
    }
}

Option 2: Add to Existing Server Block

server {
    listen 80;
    server_name example.com;

    # Your existing configuration...

    location /nginx_status {
        stub_status on;
        access_log off;
        allow 127.0.0.1;
        deny all;
    }
}

Option 3: Custom Port

server {
    listen 127.0.0.1:8080;
    server_name localhost;

    location /status {
        stub_status on;
        access_log off;
        allow 127.0.0.1;
        deny all;
    }
}

Security Considerations

Important: Always restrict access to stub_status:

location /nginx_status {
    stub_status on;
    access_log off;

    # Only allow localhost
    allow 127.0.0.1;
    allow ::1;
    deny all;
}

For remote monitoring:

location /nginx_status {
    stub_status on;
    access_log off;

    # Allow specific monitoring server IP
    allow 10.0.0.100;  # Agent server IP
    deny all;
}

Test Configuration

# Check Nginx configuration syntax
sudo nginx -t

# Reload Nginx
sudo systemctl reload nginx

# Test stub_status endpoint
curl http://127.0.0.1/nginx_status

Expected output:

Active connections: 5
server accepts handled requests
 1234 1234 5678
Reading: 0 Writing: 1 Waiting: 4

Collected Metrics

Connection Metrics

Metric Description Unit Type
active_connections Currently active client connections Count Gauge
accepts_total Total accepted client connections Count Counter
handled_total Total handled connections Count Counter
requests_total Total client requests Count Counter
dropped_connections Dropped connections (accepts - handled) Count Counter
accepts_per_sec Connection accept rate Connections/sec Gauge
requests_per_sec Request rate Requests/sec Gauge

Connection drop rate:

drop_rate = dropped_connections / accepts_total

Healthy: drop_rate = 0 (no dropped connections)

Worker State Metrics

Metric Description Unit Type
reading Connections reading request headers Count Gauge
writing Connections writing responses to clients Count Gauge
waiting Idle keep-alive connections Count Gauge

Connection states explained:

  • Reading: Nginx is reading the request header from the client
  • Writing: Nginx is writing the response back to the client
  • Waiting: Keep-alive connections waiting for new requests

Monitoring:

  • High reading count = slow clients or large request headers
  • High writing count = slow clients or large responses
  • High waiting count = many keep-alive connections (normal)

Dashboard Metrics

The StatusRadar dashboard displays:

Overview Card

  • Status - Nginx server up/down
  • Active Connections - Current connections
  • Requests/sec - Request rate

Connection Chart

  • Active connections over time
  • Accepts vs handled connections
  • Connection drop rate

Worker States Chart

  • Reading connections
  • Writing connections
  • Waiting connections

Request Rate Chart

  • Requests per second
  • Total requests (cumulative)

Installation

Quick Install

PLUGINS='nginx' \
NGINX_STATUS_URL='http://127.0.0.1/nginx_status' \
TOKEN='your-agent-token' \
bash -c "$(curl -sL https://statusradar.dev/install-agent.sh)"

Install on Existing Agent

  1. Configure Nginx stub_status:

    sudo nano /etc/nginx/sites-available/default

    Add:

    location /nginx_status {
        stub_status on;
        access_log off;
        allow 127.0.0.1;
        deny all;
    }
  2. Reload Nginx:

    sudo nginx -t && sudo systemctl reload nginx
  3. Test endpoint:

    curl http://127.0.0.1/nginx_status
  4. Enable plugin in agent config:

    sudo nano /opt/statusradar/config/agent.yaml

    Add:

    plugins:
      nginx:
        enabled: true
        status_url: http://127.0.0.1/nginx_status
  5. Restart agent:

    sudo systemctl restart statusradar-agent
  6. Verify:

    sudo journalctl -u statusradar-agent -n 50 --no-pager | grep nginx

    Expected:

    INFO: Plugin nginx: Metrics collected successfully

Testing

Manual Plugin Test

cd /opt/statusradar
python3 plugins/nginx_plugin.py

Expected Output:

Plugin: nginx
Enabled: True
Available: True

Collecting metrics...
{
  "active_connections": 5,
  "accepts_total": 12345,
  "handled_total": 12345,
  "requests_total": 67890,
  "dropped_connections": 0,
  "reading": 0,
  "writing": 1,
  "waiting": 4,
  "requests_per_sec": 12.5,
  "accepts_per_sec": 2.1
}

Test stub_status Endpoint

# Local test
curl http://127.0.0.1/nginx_status

# With specific port
curl http://127.0.0.1:8080/status

# Remote server
curl http://nginx-server.example.com/nginx_status

# Verbose output
curl -v http://127.0.0.1/nginx_status

Expected output format:

Active connections: 5
server accepts handled requests
 12345 12345 67890
Reading: 0 Writing: 1 Waiting: 4

Troubleshooting

Plugin Not Collecting Metrics

Check 1: Is Nginx running?

sudo systemctl status nginx

Check 2: Is stub_status configured?

curl http://127.0.0.1/nginx_status

Check 3: Is stub_status module available?

nginx -V 2>&1 | grep http_stub_status_module

Check 4: Check agent configuration

cat /opt/statusradar/config/agent.yaml | grep -A3 nginx

Check 5: Check agent logs

sudo journalctl -u statusradar-agent -n 100 --no-pager | grep nginx

Common Errors

"Connection refused"

Error:

ERROR: Plugin nginx: Connection refused

Causes:

  1. Nginx not running
  2. Wrong URL in configuration
  3. stub_status not listening on expected address/port

Solution:

# Check if Nginx is running
sudo systemctl status nginx

# Check Nginx is listening on expected port
sudo netstat -tlnp | grep nginx

# Test URL manually
curl http://127.0.0.1/nginx_status

# Check Nginx configuration
sudo nginx -T | grep stub_status

"HTTP 404 Not Found"

Error:

ERROR: Plugin nginx: HTTP 404 Not Found

Cause: stub_status location not configured or wrong URL

Solution:

# Check Nginx configuration for stub_status
sudo nginx -T | grep -A5 stub_status

# Verify location path
# If configured as '/status', use: http://127.0.0.1/status
# If configured as '/nginx_status', use: http://127.0.0.1/nginx_status

Update agent configuration with correct URL:

plugins:
  nginx:
    status_url: http://127.0.0.1/nginx_status  # Match your Nginx config

"HTTP 403 Forbidden"

Error:

ERROR: Plugin nginx: HTTP 403 Forbidden

Cause: IP address not allowed in Nginx configuration

Solution:

Edit Nginx configuration:

location /nginx_status {
    stub_status on;
    access_log off;
    allow 127.0.0.1;  # Add agent's IP address
    deny all;
}

Reload Nginx:

sudo nginx -t && sudo systemctl reload nginx

"stub_status module not available"

Error:

ERROR: Plugin nginx: stub_status not available

Cause: Nginx compiled without stub_status module

Solution:

Check if module is available:

nginx -V 2>&1 | grep http_stub_status_module

If not available, you need to:

  1. Install Nginx from official repository (includes module)
  2. Or recompile Nginx with --with-http_stub_status_module

Install Nginx with stub_status (Ubuntu/Debian):

sudo apt-get update
sudo apt-get install nginx

Metrics Showing Unexpected Values

Symptom: Metrics don't match expectations

Debug:

# View raw stub_status output
curl http://127.0.0.1/nginx_status

# Check Nginx access log
sudo tail -f /var/log/nginx/access.log

# Check Nginx error log
sudo tail -f /var/log/nginx/error.log

# Check active workers
ps aux | grep nginx | grep worker

Performance Impact

On Nginx

Negligible impact:

  • stub_status provides pre-calculated counters
  • No additional processing overhead
  • Response time < 1ms
  • Zero impact on request handling

Benchmark:

  • Nginx RPS with monitoring: 50,000+ RPS
  • Nginx RPS without monitoring: 50,000+ RPS
  • Overhead: 0%

On Agent

Resource usage:

  • Memory: +5 MB
  • CPU: +1% during collection (0.1-0.2 seconds)
  • Network: +0.5 KB per collection

Use Cases

1. Connection Monitoring

Monitor:

  • Active connections
  • Connection accept rate
  • Connection drop rate (accepts - handled)

Alert on:

  • Active connections spike (DDoS?)
  • Connection drops > 0 (resource exhaustion)
  • Active connections > worker_connections limit

2. Request Rate Tracking

Monitor:

  • Requests per second
  • Request growth trends
  • Request patterns (time of day)

Alert on:

  • Sudden RPS drop (application issue)
  • Unusual RPS spike
  • RPS exceeds capacity

3. Worker State Analysis

Monitor:

  • Reading/writing/waiting distribution
  • Waiting connections ratio
  • Worker efficiency

Alert on:

  • High reading count (slow clients)
  • High writing count (slow backend or large responses)
  • All workers busy

4. Keep-Alive Optimization

Monitor:

  • Waiting connections (keep-alive)
  • Active vs waiting ratio

Optimize:

  • Adjust keepalive_timeout
  • Adjust keepalive_requests
  • Balance connection reuse vs memory

Best Practices

1. Secure stub_status Endpoint

Always restrict access:

location /nginx_status {
    stub_status on;
    access_log off;
    allow 127.0.0.1;
    allow ::1;
    deny all;
}

Never expose publicly:

# BAD - Don't do this!
location /nginx_status {
    stub_status on;
    # No access restrictions = security risk!
}

2. Disable Access Logging

stub_status generates frequent requests, no need to log them:

location /nginx_status {
    stub_status on;
    access_log off;  # Important: reduces I/O
    allow 127.0.0.1;
    deny all;
}

3. Use Localhost for Local Monitoring

# Good - fast, secure
plugins:
  nginx:
    status_url: http://127.0.0.1/nginx_status

# Avoid - unnecessary network overhead
plugins:
  nginx:
    status_url: http://hostname.example.com/nginx_status

4. Monitor Connection Limits

Know your limits:

# Check worker connections
grep worker_connections /etc/nginx/nginx.conf

Example:

events {
    worker_connections 1024;  # Max connections per worker
}

With 4 workers: Max = 4 * 1024 = 4096 connections

Set alert: active_connections > 3000 (75% of max)

5. Optimize for Your Workload

For API servers (mostly JSON responses):

  • Lower keepalive_timeout (10-30 seconds)
  • Higher keepalive_requests (100+)

For static content:

  • Higher keepalive_timeout (65 seconds)
  • Standard keepalive_requests (100)

Advanced Configuration

Multiple Nginx Instances

To monitor multiple Nginx instances on same server:

Option 1: Different ports

Instance 1:

plugins:
  nginx:
    status_url: http://127.0.0.1:8080/nginx_status

Instance 2: Deploy separate agent.

Option 2: Different URLs

Not currently supported in single agent - use separate agents.

HTTPS Status Endpoint

server {
    listen 127.0.0.1:443 ssl;
    server_name localhost;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location /nginx_status {
        stub_status on;
        access_log off;
        allow 127.0.0.1;
        deny all;
    }
}

Agent configuration:

plugins:
  nginx:
    status_url: https://127.0.0.1/nginx_status

Custom Status Path

location /private/monitoring/nginx {
    stub_status on;
    access_log off;
    allow 127.0.0.1;
    deny all;
}

Agent configuration:

plugins:
  nginx:
    status_url: http://127.0.0.1/private/monitoring/nginx

Example Configurations

Basic Web Server

# /etc/nginx/sites-available/default
server {
    listen 80;
    server_name example.com;

    root /var/www/html;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }

    location /nginx_status {
        stub_status on;
        access_log off;
        allow 127.0.0.1;
        deny all;
    }
}

Reverse Proxy

server {
    listen 80;
    server_name api.example.com;

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    location /nginx_status {
        stub_status on;
        access_log off;
        allow 127.0.0.1;
        deny all;
    }
}

Load Balancer

upstream backend {
    server backend1.example.com;
    server backend2.example.com;
}

server {
    listen 80;
    server_name lb.example.com;

    location / {
        proxy_pass http://backend;
    }

    location /nginx_status {
        stub_status on;
        access_log off;
        allow 127.0.0.1;
        deny all;
    }
}

Interpreting Metrics

Understanding Active Connections

Active connections = reading + writing + waiting

Example:

Active connections: 100
Reading: 5 Writing: 10 Waiting: 85

Interpretation:

  • 100 total active connections
  • 5 clients sending requests
  • 10 clients receiving responses
  • 85 idle keep-alive connections

Connection Statistics

server accepts handled requests
 12345 12345 67890

Means:

  • 12,345 accepted connections
  • 12,345 handled connections (no drops)
  • 67,890 total requests
  • Average 5.5 requests per connection (67890 / 12345)

If accepts > handled:

  • Some connections were dropped
  • Possible causes: resource limits, configuration issues

Calculating Metrics

Requests per connection:

rpc = total_requests / total_handled_connections

High value = good keep-alive usage

Connection drop rate:

drop_rate = (accepts - handled) / accepts

Should be 0%

Next Steps