Nginx Monitoring: stub_status, Logs, Prometheus and Alerts

Key Takeaways
- ✓stub_status shows active connections and request totals; keep it private.
- ✓Add $request_time and $upstream_response_time to your log format.
- ✓The official nginx-prometheus-exporter turns stub_status into metrics.
- ✓Alert on 5xx rate, slow responses, connections and disk space.
Table of Contents
- •Nginx Monitoring: stub_status, Logs, Prometheus and Alerts
- •What to Monitor on Nginx
- •Step 1: Enable stub_status
- •Step 2: Log Response Times
- •Step 3: Quick Checks From the Command Line
- •Step 4: Graphs With Prometheus and Grafana
- •Step 5: Alerts Worth Setting
- •Common Problems Monitoring Reveals
- •Frequently Asked Questions
- •Run Nginx on a Server You Control
Nginx Monitoring: stub_status, Logs, Prometheus and Alerts
Monitoring Nginx means answering three questions before your users do: is it up, is it slow, and is it returning errors? Open-source Nginx gives you everything you need for that out of the box: the stub_status page for live connection counts, and access and error logs for response codes and timings. This guide sets up both, shows how to turn them into graphs with Prometheus and Grafana, and lists the alerts worth having.
Quick answer: enable stub_status on a private location, add $request_time and $upstream_response_time to your log format, and watch three things: 5xx error rate, response time and active connections.
What to Monitor on Nginx
| Metric | Where it comes from | Why it matters |
|---|---|---|
| Up/down | An external HTTP check | The only metric that tells you what users see |
| 5xx error rate | Access log status codes | 502 and 504 mean the backend (PHP-FPM, Node, Gunicorn) is failing |
| Response time | $request_time, $upstream_response_time | Slowness usually starts in the backend, not Nginx |
| Active connections | stub_status | Spikes show traffic surges or bots |
| Requests per second | stub_status or logs | Capacity planning |
| Errors in error.log | Error log | Upstream failures, permission and config problems |
| Server CPU, RAM, disk | The OS | Nginx is rarely the bottleneck; the server often is |
Step 1: Enable stub_status
The ngx_http_stub_status_module is included in most Nginx packages. Check with nginx -V 2>&1 | grep -o with-http_stub_status_module. Then add a private location, for example in your default server block:
server {
listen 127.0.0.1:8080;
server_name localhost;
location = /nginx_status {
stub_status;
allow 127.0.0.1;
deny all;
}
}Test and reload: sudo nginx -t && sudo systemctl reload nginx. Our guide to testing and reloading Nginx config explains both commands. Then:
curl http://127.0.0.1:8080/nginx_statusActive connections: 43
server accepts handled requests
18523 18523 52410
Reading: 0 Writing: 5 Waiting: 38Active connections: open client connections right now, including idle keep-alive ones.
accepts / handled / requests: running totals since start. If
handledis lower thanaccepts, Nginx is dropping connections, usually becauseworker_connectionsis too low.Reading / Writing / Waiting: connections reading a request, writing a response, and idle keep-alive connections.
Never expose this page publicly; the allow/deny lines keep it local.
Step 2: Log Response Times
The default “combined” log format has status codes but no timings. Add a format with them in the http block:
log_format timed '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time urt=$upstream_response_time';
access_log /var/log/nginx/access.log timed;$request_time is the total time Nginx spent on the request; $upstream_response_time is the time your backend took. If both are high, the backend is slow. If only $request_time is high, look at slow clients or large responses.
Step 3: Quick Checks From the Command Line
# Status codes in the current log
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
# 5xx responses in the last 1,000 requests
tail -n 1000 /var/log/nginx/access.log | awk '$9 ~ /^5/' | wc -l
# Slowest requests (with the timed format above)
grep -o 'rt=[0-9.]*' /var/log/nginx/access.log | sort -t= -k2 -rn | head
# Latest errors
sudo tail -n 50 /var/log/nginx/error.logFor an interactive dashboard in the terminal or a browser, GoAccess reads Nginx logs directly: goaccess /var/log/nginx/access.log --log-format=COMBINED.
Step 4: Graphs With Prometheus and Grafana
For history and alerts, collect the numbers over time. The official nginx-prometheus-exporter from the Nginx team reads stub_status and exposes Prometheus metrics:
docker run -d --name nginx-exporter --network host \
nginx/nginx-prometheus-exporter:1.5.1 \
--nginx.scrape-uri=http://127.0.0.1:8080/nginx_statusIt serves metrics on port 9113 by default, such as nginx_connections_active and nginx_http_requests_total. Point Prometheus at it and build Grafana panels for active connections and requests per second. For status codes and latency, add a log-based exporter or ship logs to Loki or another log tool.
Hosted monitoring services (Datadog, New Relic, Grafana Cloud and others) offer Nginx integrations built on the same stub_status page and logs, if you’d rather not run Prometheus yourself.
Step 5: Alerts Worth Setting
Site down: an external uptime check every minute from outside your server. Internal checks can’t see network or DNS problems.
5xx rate: more than 1–2% of requests over 5 minutes.
Slow responses: the 95th percentile of
$request_timeabove your target, for example 1 second.Connections near the limit: active connections close to
worker_processes×worker_connections.Disk space: logs grow fast; alert at 80% full and make sure logrotate runs.
Common Problems Monitoring Reveals
A burst of 502s: the backend crashed or ran out of workers. See 502 Bad Gateway in Nginx.
Waiting connections climbing with no traffic increase: long keep-alive timeouts or a bot holding connections open.
handled lower than accepts: raise
worker_connectionsand the open-files limit.Errors you can’t explain: our Nginx errors guide lists the common ones and their fixes.
Frequently Asked Questions
How do I check if Nginx is running?
Run systemctl status nginx on the server, and use an external uptime check to confirm the site actually responds from the internet.
What is Nginx stub_status?
A small built-in status page from the ngx_http_stub_status_module that shows active connections, total accepted and handled connections, total requests, and reading, writing and waiting connections.
Does open-source Nginx have a monitoring dashboard?
Not a graphical one. Open-source Nginx provides stub_status and logs; tools like GoAccess, Prometheus with Grafana, or hosted monitoring services turn them into dashboards.
How do I see Nginx response times?
Add $request_time and $upstream_response_time to your log_format. They record total request time and backend time for each request.
Where are Nginx logs on Ubuntu?
By default in /var/log/nginx/access.log and /var/log/nginx/error.log.
Run Nginx on a Server You Control
RackUp’s Developer VPS gives you root access to run Nginx, Prometheus and Grafana your way: 8 vCPU, 12 GB RAM, 150 GB NVMe and 32 TB of monthly bandwidth for $35 a month. See plans.
Unsure Which Cloud Hosting Plan Fits Your Site?
Answer 4 quick diagnostic questions to estimate the server CPU, RAM and storage you need with transparent pricing.
Cloud Infrastructure Engineer.
Related Posts
Server StackLiteSpeed Enterprise vs Nginx: Which Server Engine is Faster?
A technical benchmark comparison evaluating LiteSpeed Enterprise LSCache against Nginx for high-concurrency WordPress and web application hosting.
Cloud HostingSupabase Alternatives in 2026: Self-Hosted and Managed Backends Compared
Why people leave Supabase, and the alternatives: Firebase, Appwrite, PocketBase, Nhost, self-hosting Supabase, or your own API with a private Postgres database.
WordPress HostingWordPress White Screen of Death: Causes and How to Fix It
A blank white page or "There has been a critical error" in WordPress is a hidden PHP error. Here's how to find it and fix it, even without admin access.