How to monitor Nginx
Monitor Nginx from outside and inside. Outside, an HTTP check per site catches downtime, slow responses and expiring certificates. Inside, watch the 5xx rate and upstream errors in the access and error logs, active connections against worker_connections, and the nginx service itself. Vigil's agent parses the access log automatically and alerts on error rate.
What can go wrong with Nginx
- 502 Bad Gateway. The upstream (your app) refused the connection or died mid-response. The error log says
connect() failed (111: Connection refused) while connecting to upstream. - 504 Gateway Timeout. The upstream accepted the request but did not answer within
proxy_read_timeout(60 s by default):upstream timed out (110: Connection timed out). - Out of worker connections. Each worker handles
worker_connections(often 512 or 1024) connections, including those to upstreams. When they run out the error log saysworker_connections are not enoughand clients see resets. - A bad reload. A config error makes
nginx -s reloadfail and the old config keeps running, so nothing looks wrong until the next full restart fails to start at all. - Certificate not reloaded. Certbot renewed the file but Nginx still serves the old certificate from memory until it is reloaded.
The signals that matter, with alert thresholds
| Signal | Alert when | Why it matters |
|---|---|---|
| HTTP status and latency per site | non-2xx/3xx, or p95 > 1 s | What users see. |
| 5xx share of requests | > 5% over at least 20 requests | Upstream trouble even when the home page is fine. |
| 502/504 lines in the error log | > 10 per minute | Which upstream is failing. |
| Active connections | > 80% of workers × worker_connections | Headroom before resets. |
| Certificate days left | ≤ 14 | Renewal or reload is broken. |
| nginx service | not active | Down on this host. |
Thresholds are starting points. Tune them after a week of data: an alert nobody acts on should be raised or removed.
How to check Nginx by hand
sudo nginx -t sudo nginx -T | less
systemctl status nginx
sudo grep -E 'upstream timed out|Connection refused|worker_connections are not enough' /var/log/nginx/error.log | tail -20
awk '$9 ~ /^5/' /var/log/nginx/access.log | wc -l
curl -s http://127.0.0.1/nginx_status
Enable the status page with location = /nginx_status { stub_status; allow 127.0.0.1; deny all; }. The awk one-liner assumes the default combined log format, where the status is field 9.
How to watch Nginx with Vigil
- In New monitor create an Uptime monitor for every site Nginx serves. SSL expiry is included (alert at 14 days by default), and a weekly security scan grades HSTS, CSP, cookies and TLS versions.
- Add the host under Servers and run the one-line installer it shows (
curl -fsSL https://puzaricloud.in/install-server-agent.sh | sh -s -- --token <token>). The agent is one Python file with no dependencies; CPU, memory, disk, inode and load rules start working with the first report. The agent reads/var/log/nginx/access.logautomatically. - The server's APIs & traffic tab shows each endpoint's request rate, 5xx share and p95. The default rule alerts when more than 5% of at least 20 requests fail; set a p95 limit too if latency matters.
- Add
nginxto the systemd services to watch, and the error-log watches below. Counts becomelog:<name>metrics you can limit (log:nginx_upstream_errors = 10). - Running the nginx-prometheus-exporter? Add it under Prometheus exporters to scrape; an automatic NGINX dashboard appears.
{
"log_watch": [
{"name": "nginx_upstream_errors", "path": "/var/log/nginx/error.log", "pattern": "upstream timed out|Connection refused"},
{"name": "nginx_worker_limit", "path": "/var/log/nginx/error.log", "pattern": "worker_connections are not enough"}
],
"commands": {
"nginx_active": "curl -s http://127.0.0.1/nginx_status | awk '/Active connections/ {print $3}'"
}
}
Every alert goes to the channels you pick: email, Slack, Telegram, Discord, Microsoft Teams, Pushover, webhooks or on-call paging. Failures are confirmed by a second check before anyone is woken up.
Nginx monitoring FAQ
Why does my uptime check pass while users get 502s?
The home page may be static or cached while an API location proxies to a dead upstream. Monitor one URL per upstream (an API check on /api/health), and let the access-log 5xx rule catch the rest.
Do I need the Nginx Plus API?
No. Open-source Nginx gives you stub_status for connections and the access log for status codes and timings, which is what the agent uses.
Why does the old certificate still show after renewal?
Nginx loads certificates at start and reload. Add a deploy hook to certbot (--deploy-hook 'systemctl reload nginx') and keep the SSL expiry alert as the safety net.