Monitor Apache with Nightingale
Reads the server-status?auto output of mod_status for request rate, busy and idle workers, CPU and traffic; rules watch worker exhaustion and unreachable servers.
Last reviewed
With mod_status enabled, Apache httpd serves a machine-readable status page at /server-status?auto. The input scrapes it for total accesses and traffic, requests per second, busy and idle workers, CPU load, uptime and the distribution of worker states.
The rules cover idle workers running out, requests queuing, httpd being unreachable and restarts. Remember to restrict who can reach the status page.
What's in the template
- 5 alert rules, each with runbook steps
- Categraf collector config:
input.apache
How to connect
-
Install Categraf, put the config below in
conf/input.apache/apache.toml, fill in your own address and credentials, and restart Categraf. The startup log printsinput: local.apache startedonce the plugin is loaded.[[instances]]# https://statuslist.app/apache/apache-status-page-simple-setup-guide/# scrape_uri = "http://localhost/server-status/?auto"# host_override = ""# insecure = false# custom_headers = {}# log_level = "info" -
Open the integration center in Nightingale, find Apache, and import the dashboards and alert rules into a business group.
-
Imported rules start disabled. Check that the metrics are arriving first, then enable the rules one by one with thresholds that fit your environment.
Bundled alert rules
5 rules. Each lists its trigger condition (PromQL) and the steps to take when it fires. Thresholds are meant to be adjusted after import.
Apache instance unreachable
S1 Critical · for 1 min · Trigger:
apache_up == 0
Runbook:
- Log in to the host and run systemctl status httpd (or apache2) to confirm whether the master process is alive;
- If the process is alive, run curl -s 'http://127.0.0.1/server-status?auto' to verify by hand whether the status page is blocked by a Require directive or a firewall;
- If the process is gone, run httpd -t to validate the configuration before starting it, and check the tail of error_log for the cause (port already in use, expired certificate, module load failure are common);
- Confirm the upstream load balancer has removed this node so traffic stops being sent to it.
Apache idle workers exhausted
S1 Critical · for 3 min · Trigger:
apache_workers{state="idle"} == 0
Runbook:
- Run curl -s 'http://127.0.0.1/server-status?auto' and read the Scoreboard to see which state workers are stuck in (W = sending reply, meaning a slow backend; R = reading request, meaning slow clients);
- If they are stuck in W, first check whether the backend (PHP-FPM, database, upstream API) has slowed down, and use tail -f access_log to find the slow URLs from the response-time column;
- As a stopgap, raise MaxRequestWorkers and ServerLimit and reload gracefully, but re-check memory first (per-worker memory x concurrency must not exceed physical memory);
- If slow clients are holding workers, enable mod_reqtimeout and lower KeepAliveTimeout.
Apache worker utilization too high
S2 Warning · for 5 min · Trigger:
sum without (state) (apache_workers{state="busy"}) / sum without (state) (apache_scoreboard) * 100 > 85
Runbook:
- Run curl -s 'http://127.0.0.1/server-status?auto' and compare BusyWorkers against the open_slot headroom in the Scoreboard;
- Use tail -n 10000 access_log | awk to rank URLs by count and latency, and decide whether this is genuine traffic growth or one slow endpoint holding workers;
- For traffic growth, scale out instances or raise MaxRequestWorkers (recalculating ServerLimit against memory);
- For a slow endpoint, fix the backend first and apply mod_reqtimeout or rate limiting to that URL so a single endpoint cannot drain the whole process pool.
Apache average request duration too long
S2 Warning · for 5 min · Trigger:
rate(apache_duration_ms_total[5m]) / (rate(apache_accesses_total[5m]) > 0) > 1000
Runbook:
- Confirm the access_log LogFormat includes %D (microsecond duration), then run awk '{print $NF, $7}' access_log | sort -rn | head -20 to find the slowest URLs;
- If the slow URLs are dynamic requests, move on to the backend (PHP-FPM slowlog, application logs, database slow queries);
- If static assets are slow, check disk IO and whether sendfile or caching was accidentally disabled;
- While investigating, apply mod_ratelimit or degrade that URL so workers are not held indefinitely.
Apache restarted recently
S3 Info · for 1 min · Trigger:
apache_uptime_seconds_total < 300
Runbook:
- First confirm whether this was a planned release by checking change records and shell history;
- If unplanned, run journalctl -u httpd --since '-30min' and tail -200 error_log to determine whether it was a segfault, an OOM, or a configuration error;
- For an OOM kill, confirm with dmesg -T | grep -i 'killed process' and lower MaxRequestWorkers based on real per-worker memory;
- For repeated crashes, keep core dumps (CoreDumpDirectory) and bisect by disabling third-party modules one at a time.
Related
- Apache template source: the raw JSON for dashboards, rules and collector config. Pull requests welcome.
- Categraf
apacheplugin docs: every config option and the full metric list. - Import dashboards and alert rules
- Verify that metrics are stored
- All integrations