Long before I set up heavier tools like Nagios or Munin, I relied on a feature that’s built right into Apache itself: the server-status page. It’s one of the fastest ways to get a real-time snapshot of what your server is doing, and I still use it constantly for quick diagnostics. Here’s exactly how I set it up and read it.
What Is Apache’s Server-Status Page?
The server-status page is a built-in feature powered by mod_status, a module that ships with Apache. When enabled, it exposes a live view of current connections, requests per second, CPU usage, worker states, and more — all through a simple URL.
Why I Use It
- Zero setup overhead — it’s already part of Apache; you just need to enable a module and add a config block.
- Instant snapshot — no waiting for external monitoring tools to poll and report.
- Great for quick diagnostics — when a server feels slow, this is often the first place I check to see if all worker threads are busy.
- Useful for capacity planning — seeing how many workers are active under normal load helps me size
MaxRequestWorkerscorrectly.
Prerequisites
- Apache installed (
apache2orhttpd) - Root or sudo access
mod_statusavailable (it ships by default with Apache, just needs enabling)
Step 1: Enable mod_status
On Debian/Ubuntu:
sudo a2enmod status
On CentOS/RHEL, mod_status is typically already loaded via /etc/httpd/conf.modules.d/00-base.conf. Verify with:
httpd -M | grep status
Step 2: Configure the Status Location
On Debian/Ubuntu, edit /etc/apache2/mods-available/status.conf (or create it if missing):
<Location "/server-status">
SetHandler server-status
Require ip 127.0.0.1
Require ip 192.168.1.0/24
</Location>
ExtendedStatus On
On CentOS/RHEL, add a similar block to /etc/httpd/conf.d/status.conf:
<Location "/server-status">
SetHandler server-status
Require ip 127.0.0.1
Require ip 192.168.1.0/24
</Location>
ExtendedStatus On
The Require ip directives are critical — I never leave this page open to the public internet since it reveals internal details about your server (client IPs, requested URLs, etc.).
Step 3: Restart Apache
sudo systemctl restart apache2 # Debian/Ubuntu
sudo systemctl restart httpd # CentOS/RHEL
Step 4: View the Status Page
From an allowed IP, visit:
http://your-server-ip/server-status
You’ll see something like:
Apache Server Status for web01.mydomain.com
Server Version: Apache/2.4.52 (Ubuntu)
Server Built: Jan 20 2026 10:15:32
Current Time: Sunday, 26-Jul-2026 10:30:00 UTC
Restart Time: Saturday, 25-Jul-2026 08:00:00 UTC
Parent Server Config. Generation: 1
Server uptime: 1 day 2 hours 30 minutes 0 seconds
Server load: 0.15 0.20 0.18
Total accesses: 154382 - Total Traffic: 2.1 GB
CPU Usage: u45.2 s12.1 cu0 cs0 - .12% CPU load
154382 requests/sec - 2.1 MB/second - 14.2 kB/request
25 requests currently being processed, 75 idle workers
Below this summary, you’ll also see a scoreboard showing each worker’s current state.
Step 5: Understanding the Scoreboard
Each character in the scoreboard represents one worker thread/process, and its meaning is:
_— Waiting for a connectionS— Starting upR— Reading a requestW— Sending a replyK— Keepalive (waiting for next request on a persistent connection)D— DNS lookupC— Closing connectionL— LoggingG— Gracefully finishingI— Idle cleanup of worker.— Open slot with no current process
When I see mostly W‘s and no _‘s or .‘s, that tells me the server is close to maxing out its available workers — a sign I might need to tune MaxRequestWorkers.
Step 6: Getting Machine-Readable Output
For scripting or integration with monitoring tools, Apache also provides a machine-readable version:
http://your-server-ip/server-status?auto
This returns plain key-value pairs instead of HTML, perfect for parsing with a script:
curl -s http://127.0.0.1/server-status?auto
Total Accesses: 154382
Total kBytes: 2202000
CPULoad: .12
Uptime: 95400
ReqPerSec: 1.618
BytesPerSec: 23625.6
BytesPerReq: 14.2
BusyWorkers: 25
IdleWorkers: 75
Scoreboard: ____KKKWWWWWW_________________...
I often pipe this into a small monitoring script or a cron job that logs busy/idle worker counts over time for capacity planning.
Step 7: Building a Simple Polling Script
Since the ?auto endpoint returns plain key-value output, I sometimes write a tiny shell script to log busy worker counts over time, which is useful for spotting trends without setting up a full monitoring stack:
#!/bin/bash
while true; do
TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")
BUSY=$(curl -s http://127.0.0.1/server-status?auto | grep "BusyWorkers" | awk '{print $2}')
IDLE=$(curl -s http://127.0.0.1/server-status?auto | grep "IdleWorkers" | awk '{print $2}')
echo "$TIMESTAMP,BusyWorkers=$BUSY,IdleWorkers=$IDLE" >> /var/log/apache-worker-stats.csv
sleep 60
done
Running this as a background service (or via a simple systemd unit) gives me a lightweight CSV I can later graph in a spreadsheet or feed into a more sophisticated tool, without needing to install anything beyond curl.
Comparing Worker MPMs in the Status Output
The exact fields shown on the status page differ slightly depending on which Multi-Processing Module (MPM) Apache is using:
- prefork — shows one process per connection; useful for older PHP setups using
mod_php. - worker — shows threads within processes, generally handling more concurrent connections with less memory overhead.
- event — similar to worker, but handles keep-alive connections more efficiently by freeing up threads sooner.
Check which MPM you’re running with:
apache2ctl -V | grep MPM
Understanding which MPM is active helps you interpret the busy/idle worker counts correctly — an event MPM server can generally sustain far more concurrent idle keep-alive connections than a prefork server before running out of capacity.
Real-World Use Case: Diagnosing a Slow Site
I once had a client report that their site “felt slow” during peak hours. Instead of guessing, I hit /server-status and saw nearly all workers in the W (sending reply) state with very few idle. That told me the bottleneck wasn’t network or DNS — it was backend response time. Digging further, a slow database query turned out to be tying up PHP-FPM workers, which in turn tied up Apache workers waiting on responses.
Common Mistakes I’ve Made
- Leaving
/server-statusopen to the public internet — a serious information disclosure risk since it reveals client IPs and request URLs. - Forgetting
ExtendedStatus On— without it, the page shows much less detail (no request URLs or per-worker info). - Not restarting Apache after config changes — the module might load, but changes to the
<Location>block won’t take effect until a restart or reload. - Confusing it with real-time alerting — server-status is a snapshot tool, not a substitute for continuous automated monitoring like Nagios or Munin.
Using Server-Status Alongside Load Testing
Whenever I’m load-testing a server before a big launch (using a tool like ab — ApacheBench — or siege), I keep /server-status?auto open in another terminal, polling it every second:
watch -n 1 'curl -s http://127.0.0.1/server-status?auto'
This gives me a live view of exactly how the server behaves under synthetic load — how quickly busy workers climb, whether idle workers run out, and how CPU load tracks against request volume. It’s a far more direct signal than just watching the load-testing tool’s own reported latency, since it shows me the server’s actual internal state as pressure increases, which is exactly what I need to decide whether to raise MaxRequestWorkers, add more memory, or investigate a specific slow endpoint before real users hit it in production.
Security Best Practices
- Always restrict access using
Require ipto your office or VPN IP ranges — never expose this page publicly. - Consider putting it behind HTTP basic authentication as an additional layer:
<Location "/server-status">
SetHandler server-status
AuthType Basic
AuthName "Restricted Status"
AuthUserFile /etc/apache2/.htpasswd
Require valid-user
</Location>
- Periodically audit your Apache config to make sure this block hasn’t been accidentally exposed after a config migration.
Performance Optimization Tips
- Use the
?autoendpoint with a lightweight polling script rather than repeatedly loading the full HTML page, which has more overhead. - Correlate busy worker counts with
MaxRequestWorkersto decide if you need to raise limits or optimize backend response times instead. - If workers are frequently maxed out, investigate whether enabling
mod_deflate, tuningKeepAliveTimeout, or switching to an event-based MPM (mpm_event) would relieve pressure.
Troubleshooting Common Issues
“403 Forbidden” when accessing /server-status — check your Require ip rules; your current IP may not be in the allowed list.
Page loads but shows minimal detail — make sure ExtendedStatus On is set in your config and Apache has been restarted.
mod_status not found — verify it’s enabled with apache2ctl -M | grep status or httpd -M | grep status, and enable it if missing.
FAQs
Is server-status safe to leave enabled permanently? Yes, as long as access is properly restricted by IP or authentication. I keep it enabled on all my servers for quick diagnostics.
Does server-status show HTTPS traffic details? It shows request-level information regardless of whether the original request was HTTP or HTTPS, though it doesn’t expose encrypted request bodies.
Can I integrate server-status with Nagios or Munin? Yes — both tools can poll the ?auto endpoint and use the data for graphing and alerting.
Why don’t I see request URLs on the status page? That requires ExtendedStatus On to be set in your Apache configuration.
Summary and Key Takeaways
Apache’s server-status page is a lightweight, zero-cost way to get real-time insight into what your server is doing right now — active connections, worker states, and throughput. I use it constantly as a first diagnostic step before reaching for heavier tools. Just remember to restrict access properly, since the page reveals internal server details that shouldn’t be public.
