To optimize Apache on a Linux server, use the event MPM with PHP-FPM, enable HTTP/2 and Brotli/Gzip, tune KeepAlive and MaxRequestWorkers to your RAM/CPU, cache static assets with proper Cache-Control, compress and minimize TLS overhead, monitor via mod_status, and validate with load testing. Secure, logrotate, and review regularly.
Optimizing Apache on a Linux server means tuning modules, connection handling, caching, and operating system limits to match your workload. In this guide, I’ll show you how to optimize Apache on Linux server environments step-by-step, using safe defaults, practical formulas, and commands you can apply on Ubuntu/Debian and RHEL/CentOS/AlmaLinux.
Understand Your Stack and Goals
Before changing settings, identify what you’re serving and where the bottleneck is: static files, PHP/WordPress, APIs, or file downloads. Your optimization path differs for TLS-heavy traffic, chatty APIs, or content sites.
Baseline and Monitor
- Check current Apache build and MPM: apachectl -V
- Monitor resources: top/htop, free -m, iostat, ss -s
- Enable server-status: mod_status for live concurrency and scoreboard
- Benchmark: ab, wrk, or siege to simulate realistic concurrency
# Enable mod_status (Debian/Ubuntu)
sudo a2enmod status
echo "<Location /server-status>
SetHandler server-status
Require ip 203.0.113.0/24
</Location>" | sudo tee /etc/apache2/conf-available/status.conf
sudo a2enconf status
sudo systemctl reload apache2
# RHEL/AlmaLinux (httpd)
/usr/lib64/httpd/modules/mod_status.so is built-in or loadable
# Add in a vhost or conf.d/status.conf:
# <Location /server-status>SetHandler server-status Require ip 203.0.113.0/24</Location>
sudo systemctl reload httpd
Pick the Right MPM: event vs worker vs prefork
Apache’s Multi-Processing Module (MPM) dictates concurrency. For most modern sites (especially PHP via PHP-FPM), use event MPM. Prefork is legacy and needed only if you run non-thread-safe modules like mod_php (which you should avoid in favor of PHP-FPM).
Switch to event MPM and PHP-FPM
# Debian/Ubuntu: switch to event MPM and PHP-FPM
sudo a2dismod mpm_prefork
sudo a2enmod mpm_event proxy_fcgi setenvif http2 headers deflate
sudo a2enconf php8.2-fpm # adjust your PHP version
sudo systemctl restart php8.2-fpm
sudo systemctl restart apache2
# RHEL/AlmaLinux
sudo dnf install php-fpm
sudo systemctl enable --now php-fpm
# Ensure httpd uses event MPM (default on newer releases)
httpd -V | grep -i mpm
# In vhost, pass PHP to FPM:
# <FilesMatch \.php$>SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost/"</FilesMatch>
sudo systemctl restart httpd
Tune event MPM for Your RAM/CPU
Goal: prevent swapping by setting MaxRequestWorkers to the maximum concurrent Apache threads your RAM can handle.
- Estimate per-request memory: watch RES in top for apache2/httpd under load (e.g., 30–80 MB with PHP).
- Formula: MaxRequestWorkers ≈ (Available RAM for Apache) ÷ (Average Apache+PHP memory per request).
- Keep 30–40% RAM for MySQL/Redis/OS cache.
# Example event MPM (Debian/Ubuntu: /etc/apache2/mods-available/mpm_event.conf)
# Example for 4 vCPU, 8 GB RAM, PHP-FPM workload where each request ≈ 60 MB
# Budget 4.5 GB for Apache: 4500 MB / 60 ≈ 75 workers (round down to 64 or 72)
<IfModule mpm_event_module>
StartServers 2
ServerLimit 8
ThreadsPerChild 25
ThreadLimit 64
MaxRequestWorkers 200 # Threads = ServerLimit * ThreadsPerChild (cap at your calculation)
MinSpareThreads 75
MaxSpareThreads 150
MaxConnectionsPerChild 3000 # Recycle to mitigate leaks
</IfModule>
Adjust ServerLimit × ThreadsPerChild to meet your target MaxRequestWorkers without exceeding available memory.
Enable HTTP/2, H2 Priorities, and TLS Optimizations
Turn on HTTP/2
HTTP/2 reduces latency via multiplexing and header compression. Ensure your vhost is SSL-enabled with a strong certificate.
# Debian/Ubuntu
sudo a2enmod http2 headers ssl
# In your SSL vhost:
Protocols h2 http/1.1
H2Push off
H2Direct on
# Reload
sudo systemctl reload apache2
# RHEL/AlmaLinux
# LoadModule http2_module modules/mod_http2.so
# In SSL vhost:
Protocols h2 http/1.1
sudo systemctl reload httpd
Enable Compression: Brotli (best) or Gzip
# Brotli (preferred if available)
sudo a2enmod brotli || true
# Add globally or in vhost:
AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/css text/javascript application/javascript application/json image/svg+xml
# Fallback to Gzip (mod_deflate)
sudo a2enmod deflate
AddOutputFilterByType DEFLATE text/html text/plain text/css text/javascript application/javascript application/json image/svg+xml
# Avoid double-compressing already compressed formats
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|webp|avif|zip|gz|bz2|rar|7z|mp4|mp3|woff2?)$ no-gzip dont-vary
TLS Settings That Save CPU
# Example TLS for performance and security (in SSL vhost or ssl.conf)
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite TLS-CHACHA20-POLY1305-SHA256:TLS-AES-256-GCM-SHA384:TLS-AES-128-GCM-SHA256
SSLHonorCipherOrder off
SSLCompression off
SSLSessionCache shmcb:/var/run/apache2/ssl_scache(512000)
SSLSessionCacheTimeout 300
SSLOpenSSLConfCmd Curves X25519:secp256r1
Session resumption and modern ciphers reduce CPU per handshake. Use Let’s Encrypt with auto-renewal for minimal maintenance.
Tune KeepAlive, Timeouts, and Request Limits
KeepAlive improves performance but can exhaust workers if set too high. For HTTP/2 you can often allow shorter KeepAliveTimeout due to multiplexing.
# In apache2.conf or httpd.conf
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 2
# Timeouts to protect from slowloris and hanging backends
Timeout 30
RequestReadTimeout header=10-20,MinRate=500 body=20,MinRate=500
# Size limits (protect resources)
LimitRequestBody 10485760 # 10 MB (adjust for your app)
LimitRequestFields 100
LimitRequestFieldSize 16384
Caching and Static Asset Optimization
Leverage Browser Caching
# mod_expires / mod_headers
sudo a2enmod expires headers
# In a global conf or vhost:
ExpiresActive On
ExpiresByType text/css "access plus 30 days"
ExpiresByType application/javascript "access plus 30 days"
ExpiresByType image/webp "access plus 90 days"
ExpiresByType image/png "access plus 90 days"
Header append Cache-Control "public"
Optional: Server-Side Caching for Dynamic Pages
Use Apache’s mod_cache for page or fragment caching when your app allows it. For WordPress, pair with a page cache plugin or reverse proxy/CDN.
# Disk cache example
sudo a2enmod cache cache_disk
CacheQuickHandler on
CacheEnable disk "/"
CacheRoot /var/cache/apache2/mod_cache_disk
CacheIgnoreCacheControl On
CacheDefaultExpire 600
CacheMaxFileSize 10000000
Always test cache rules to avoid serving private content. Consider a CDN for global delivery; it offloads bandwidth and TLS handshakes.
Optimize PHP Handling with PHP-FPM
PHP-FPM performs best with event MPM. Configure the pool for your concurrency and memory budget.
# PHP-FPM pool (/etc/php/8.2/fpm/pool.d/www.conf)
pm = dynamic
pm.max_children = 60 # Match your MaxRequestWorkers and memory
pm.start_servers = 6
pm.min_spare_servers = 6
pm.max_spare_servers = 12
pm.max_requests = 500 # Recycle to avoid memory leaks
# Enable OPcache (/etc/php/8.2/fpm/php.ini)
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
Map PHP to FPM via ProxyPassMatch or FilesMatch, and confirm sockets/ports align. Watch FPM’s slow log to spot bottlenecks in plugins or themes.
Logging, Rotation, and Observability
Right-Size Logs
# Use combined log and rotate
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
CustomLog /var/log/apache2/access.log combined
ErrorLog /var/log/apache2/error.log
LogLevel warn
# Ensure logrotate (Debian/Ubuntu: /etc/logrotate.d/apache2)
sudo logrotate -f /etc/logrotate.conf
Test Under Load
# Basic wrk example (install wrk first)
wrk -t4 -c100 -d60s --latency https://example.com/
# ApacheBench (ab)
ab -k -n 10000 -c 200 https://example.com/
Compare latency percentiles and error rates before and after changes. Use mod_status to confirm you’re not exhausting workers.
OS-Level Tuning for High Concurrency
Linux defaults are conservative. Increase file descriptors and network backlog when you serve thousands of concurrent connections.
# Increase file descriptors
# /etc/security/limits.d/99-apache.conf
www-data soft nofile 65536
www-data hard nofile 65536
# Kernel networking (e.g., /etc/sysctl.d/99-web.conf)
net.core.somaxconn = 4096
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_tw_reuse = 1
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_max_syn_backlog = 4096
fs.file-max = 2097152
sudo sysctl --system
Replace www-data with apache on RHEL-based systems. Validate with ulimit -n under the Apache worker process.
Security Hardening That Also Saves CPU
- Enable a WAF: mod_security with a tuned ruleset (disable high-cost rules you don’t need).
- Rate-limiting/DoS mitigation: mod_evasive or a CDN’s edge firewall.
- Block abusive bots with RewriteCond on User-Agent/IP lists.
- Disable and remove unused modules to reduce attack surface and memory.
# Simple bot throttle with mod_evasive (example)
/etc/httpd/conf.d/mod_evasive.conf or /etc/apache2/mods-available/evasive.conf
DOSHashTableSize 3097
DOSPageCount 5
DOSPageInterval 1
DOSSiteCount 100
DOSSiteInterval 1
DOSBlockingPeriod 10
Maintenance Checklist
- Patch Apache, OpenSSL, and PHP regularly.
- Review mod_status weekly; adjust MaxRequestWorkers and FPM pool sizes.
- Rotate and compress logs; prevent disk fill.
- Audit vhosts and .htaccess for expensive rewrites.
- Use a staging environment to test changes and updates.
When to Consider Managed Hosting
If you’d rather focus on your app than kernel and MPM tuning, a managed stack helps. At YouStable, we optimize Apache on Linux with event MPM, PHP-FPM, HTTP/2, Brotli, and OS-level tuning, then validate with benchmarks and 24×7 monitoring. It’s a safe path to predictable performance.
Practical End-to-End Example (WordPress on Ubuntu)
- Switch to event MPM and PHP-FPM, disable prefork/mod_php.
- Enable HTTP/2, Brotli/Gzip, Expires and Cache-Control headers.
- Tune MaxRequestWorkers to memory budget; set KeepAliveTimeout 2.
- Use a page cache plugin and a CDN for global assets.
- Harden TLS and add mod_evasive; logrotate and monitor mod_status.
# Quick validation
apachectl -M | egrep 'mpm|http2|deflate|brotli|headers|ssl'
apachectl -V | grep -i mpm
systemctl status php8.2-fpm
curl -I https://example.com/ | egrep 'HTTP/|content-encoding|cache-control|expires|alt-svc'
By following these steps, you can optimize Apache on Linux server environments for lower latency, better throughput, and improved stability, without guesswork. Tweak based on real metrics, protect your resources, and iterate. If you need a hand, YouStable’s managed hosting team can handle the tuning and monitoring end-to-end.
FAQs
What is the best MPM for WordPress on Apache?
Use event MPM with PHP-FPM. Event handles keep-alives efficiently and PHP runs out-of-process, improving concurrency and stability. Avoid prefork unless you must run non-thread-safe modules.
How do I calculate MaxRequestWorkers safely?
Measure average memory per request under load, reserve 30–40% RAM for the OS/DB/cache, then divide your Apache RAM budget by per-request memory. Set ServerLimit × ThreadsPerChild accordingly and cap MaxRequestWorkers at or below that number.
How do I enable HTTP/2 on Apache?
Load mod_http2, ensure SSL/TLS is enabled, and add “Protocols h2 http/1.1” to your SSL vhost. Reload Apache. Confirm with curl -I and look for HTTP/2 or use your browser’s DevTools.
Is Nginx always faster than Apache?
No. With event MPM, HTTP/2, compression, and proper caching, Apache performs competitively. Nginx can be leaner for static files, but for many WordPress/PHP stacks, tuned Apache is excellent and feature-rich.
Which modules should I disable to improve performance?
Disable unused modules like autoindex, status (on public sites), negotiation, cgi, and any legacy modules not required. Run apachectl -M to list modules and comment out LoadModule lines for those you don’t need.