Start from the MPM
Throughput and latency on Apache are bounded first by the MPM and OS resources, then by application code. On modern TLS-heavy sites, event (when compatible with your module set—typically php-fpm instead of mod_php) generally offers the best combination of keep-alive handling and thread pool utilization. prefork remains when non-thread-safe modules require isolated processes; each connection can consume an entire process at peak.
Sizing workers and RAM
Rough planning: estimate resident memory per worker process or thread (RSS from mod_status or ps samples under load), then solve MaxRequestWorkers ≤ (RAM - OS/cache overhead) / per_worker_RSS. Leave headroom for spikes and the rest of the stack (database connections, php-fpm pools). For event MPM, AsyncRequestWorkerFactor scales how many asynchronous connections each worker thread may handle—raising it increases concurrency but also file descriptor and kernel socket table pressure; validate with load tests rather than defaults alone.
| Directive | What to watch |
|---|---|
ServerLimit / MaxRequestWorkers | Hard cap on concurrent connections; raising without RAM causes swap storms |
ThreadsPerChild | Threads inside each child process (worker/event) |
KeepAliveTimeout | How long idle connections linger—long values improve TLS reuse, short values free fds faster |
MaxKeepAliveRequests | Requests per connection before close—balances fairness vs reuse |
File descriptors and systemd limits
Each connection, log pipe, and backend socket consumes an fd. Align LimitNOFILE in the unit file with MaxRequestWorkers plus margin. Use apachectl fullstatus / mod_status ExtendedStatus to watch slot usage and idle workers during peaks.
Keep-Alive vs throughput
Keep-Alive reduces TLS handshakes but holds sockets. When behind a reverse proxy that terminates TLS, origin Keep-Alive may still help HTTP/1.1 reuse to app servers. Align Timeout, ProxyTimeout (if mod_proxy), and upstream idle timeouts to avoid half-open piles.
Slow clients and request limits
mod_reqtimeout limits time to receive request line and headers—mitigates slowloris-style header dribbles without crushing legitimate mobile uploads if tuned carefully. Pair with kernel SYN/backlog tuning at the OS edge for large fronts.
Compression: mod_deflate
Compress text/* and JavaScript with AddOutputFilterByType DEFLATE patterns; exclude already compressed types (image/jpeg, video/*, application/zip) to save CPU. Vary: Accept-Encoding interactions with CDNs must be understood before enabling globally.
Caching
mod_cache_disk (and friends) can offload hot static assets or micro-cached dynamic responses. Define CacheIgnoreURLSessionIdentifiers when session IDs in URLs would fragment the keyspace. For many sites, a dedicated CDN or reverse proxy cache simplifies invalidation—see clearing Apache cache.
Filesystem and sendfile
EnableSendfile On maps kernel sendfile for static files; on some network filesystems or virtio bugs it can cause corruption—benchmark before enabling on NFS. EnableMMAP is similar: faster on local SSD, questionable on flaky network mounts.
Logging and HostnameLookups
Set HostnameLookups Off (default on sane builds) so access logs do not trigger reverse DNS per hit—do name resolution in your log pipeline if needed. High LogLevel on production adds I/O—scope per-module levels.
HTTP/2 and thread pools
With Protocols h2 http/1.1, long-lived streams multiplex on fewer TCP connections—worker/thread exhaustion manifests differently than HTTP/1.1 fan-out. Monitor concurrency inside php-fpm or app servers, not only Apache’s slot table.
Enterprise checklist
- Baseline
mod_statusunder representative TLS and payload mix. - Disable
.htaccesswhere policy allows (htaccess guide). - Automate config tests before reload; capture before/after RPS and p99 latency.
Foundations: Apache configuration explained, virtual hosts.