Boost Apache performance through worker MPM optimization, compression modules, and intelligent caching strategies. Achieve 3-5x performance improvements for high-traffic production workloads.
Prerequisites
- Root or sudo access
- 4GB+ RAM recommended for high-performance settings
- Basic knowledge of Apache configuration
What this solves
Apache HTTP server performance can bottleneck under high traffic loads due to inefficient worker configurations, missing compression, and lack of caching. This tutorial optimizes Apache through worker MPM tuning for concurrent connections, enables mod_deflate and Brotli compression to reduce bandwidth usage, and implements browser and proxy caching with mod_cache. These optimizations typically improve response times by 60-80% and increase concurrent user capacity by 3-5x.
Step-by-step configuration
Update system packages and install Apache
Start with a fresh Apache installation and enable essential performance modules.
sudo apt update && sudo apt upgrade -y
sudo apt install -y apache2 apache2-utils brotli
sudo systemctl enable apache2
Enable performance and compression modules
Enable Apache modules required for performance optimization including worker MPM, compression, caching, and monitoring.
sudo a2dismod mpm_prefork
sudo a2enmod mpm_worker
sudo a2enmod deflate
sudo a2enmod expires
sudo a2enmod headers
sudo a2enmod cache
sudo a2enmod cache_disk
sudo a2enmod status
sudo a2enmod info
sudo a2enmod rewrite
Configure worker MPM for high concurrency
Optimize worker process and thread settings based on your server resources. These settings handle 4GB+ RAM servers with high concurrent loads.
StartServers 4
MinSpareThreads 50
MaxSpareThreads 200
ThreadLimit 64
ThreadsPerChild 32
MaxRequestWorkers 1024
MaxConnectionsPerChild 10000
ServerLimit 32
Configure compression with mod_deflate
Enable gzip compression for text-based content to reduce bandwidth usage by 60-80%. This configuration targets common web content types.
# Compress these file types
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/json
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/atom+xml
AddOutputFilterByType DEFLATE image/svg+xml
# Set compression level (1-9, 9 is highest)
DeflateCompressionLevel 6
# Don't compress images, videos, or already compressed files
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|zip|gz|rar|bz2|7z|mp3|mp4|avi|mov)$ no-gzip
# Add Vary header for caching proxies
Header append Vary Accept-Encoding env=!dont-vary
# Log compression ratio for monitoring
LogFormat '%h %l %u %t "%r" %>s %O "%{Referer}i" "%{User-Agent}i" %{ratio}n%%' deflate
Configure Brotli compression
Enable Brotli compression for better compression ratios than gzip, especially for text content. Brotli provides 15-25% better compression.
sudo apt install -y libapache2-mod-brotli
sudo a2enmod brotli
# Enable Brotli compression
BrotliCompressionQuality 6
BrotliCompressionWindow 22
# Compress these MIME types with Brotli
BrotliFilterNote Input instream
BrotliFilterNote Output outstream
BrotliFilterNote Ratio ratio
AddOutputFilterByType BROTLI_COMPRESS text/html
AddOutputFilterByType BROTLI_COMPRESS text/plain
AddOutputFilterByType BROTLI_COMPRESS text/xml
AddOutputFilterByType BROTLI_COMPRESS text/css
AddOutputFilterByType BROTLI_COMPRESS text/javascript
AddOutputFilterByType BROTLI_COMPRESS application/javascript
AddOutputFilterByType BROTLI_COMPRESS application/json
AddOutputFilterByType BROTLI_COMPRESS application/xml
AddOutputFilterByType BROTLI_COMPRESS application/rss+xml
AddOutputFilterByType BROTLI_COMPRESS application/atom+xml
AddOutputFilterByType BROTLI_COMPRESS image/svg+xml
# Fallback to deflate for clients that don't support Brotli
SetOutputFilter BROTLI_COMPRESS;DEFLATE
Configure disk-based caching with mod_cache
Enable intelligent caching to serve frequently requested content from disk cache, reducing server load and improving response times.
# Create cache directory with proper permissions
sudo mkdir -p /var/cache/apache2/mod_cache_disk
sudo chown www-data:www-data /var/cache/apache2/mod_cache_disk
sudo chmod 755 /var/cache/apache2/mod_cache_disk
CacheRoot /var/cache/apache2/mod_cache_disk
CacheDirLevels 2
CacheDirLength 1
CacheEnable disk /
# Cache configuration
CacheMaxFileSize 10000000
CacheMinFileSize 1
CacheDefaultExpire 3600
CacheMaxExpire 86400
# Don't cache these paths
CacheDisable /admin
CacheDisable /api
CacheDisable /login
CacheDisable /wp-admin
# Cache based on query strings
CacheIgnoreQueryString Off
# Add cache status headers
CacheHeader on
Configure browser caching with expires headers
Set appropriate expiration headers to enable browser caching and reduce repeat requests for static assets.
ExpiresActive On
# Default expiration: 1 hour
ExpiresDefault "access plus 1 hour"
# HTML documents: 10 minutes
ExpiresByType text/html "access plus 10 minutes"
# CSS and JavaScript: 1 week
ExpiresByType text/css "access plus 1 week"
ExpiresByType application/javascript "access plus 1 week"
ExpiresByType text/javascript "access plus 1 week"
# Images: 1 month
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/jpg "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/svg+xml "access plus 1 month"
ExpiresByType image/webp "access plus 1 month"
# Fonts: 3 months
ExpiresByType font/ttf "access plus 3 months"
ExpiresByType font/woff "access plus 3 months"
ExpiresByType font/woff2 "access plus 3 months"
ExpiresByType application/font-woff "access plus 3 months"
# Documents and media: 1 week
ExpiresByType application/pdf "access plus 1 week"
ExpiresByType video/mp4 "access plus 1 week"
ExpiresByType audio/mpeg "access plus 1 week"
# Add cache-control headers
Header append Cache-Control "public"
Configure performance monitoring with mod_status
Enable server status and info pages for performance monitoring. Restrict access to localhost for security.
SetHandler server-status
Require local
Require ip 127.0.0.1
Require ip ::1
SetHandler server-info
Require local
Require ip 127.0.0.1
Require ip ::1
# Enable extended status for detailed metrics
ExtendedStatus On
Apply security hardening for performance modules
Secure the performance configuration by hiding server information and preventing information disclosure.
# Hide Apache version and OS information
ServerTokens Prod
ServerSignature Off
Prevent access to .htaccess files
Require all denied
Prevent access to cache directories
Require all denied
Security headers for performance-related content
# Prevent MIME type sniffing
Header always set X-Content-Type-Options nosniff
# Enable XSS protection
Header always set X-XSS-Protection "1; mode=block"
# Prevent clickjacking
Header always set X-Frame-Options SAMEORIGIN
# Remove server header information
Header unset Server
Header unset X-Powered-By
Limit request size to prevent DoS
LimitRequestBody 10485760
LimitRequestFields 100
LimitRequestFieldSize 1024
LimitRequestLine 4094
sudo a2enconf security-performance
Configure firewall access
Ensure Apache can accept HTTP and HTTPS connections through the system firewall.
sudo ufw allow 'Apache Full'
sudo ufw reload
sudo ufw status
Start and enable Apache service
Start Apache with the new performance configuration and enable automatic startup.
sudo apache2ctl configtest
sudo systemctl restart apache2
sudo systemctl status apache2
Performance benchmarking and monitoring
Install Apache Bench for load testing
Install ab (Apache Bench) tool for performance testing and establish baseline metrics.
# apache2-utils already installed above
ab -V
Create test content for benchmarking
Create sample content to test compression and caching performance accurately.
sudo mkdir -p /var/www/html/test
sudo tee /var/www/html/test/large.html > /dev/null << 'EOF'
Performance Test Page
Apache Performance Test Content
EOF
Add repetitive content for compression testing
for i in {1..1000}; do
echo " This is test paragraph number $i with repeated content for compression testing. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
" | sudo tee -a /var/www/html/test/large.html > /dev/null
done
echo " " | sudo tee -a /var/www/html/test/large.html > /dev/null
sudo chown -R www-data:www-data /var/www/html/test
sudo chmod -R 644 /var/www/html/test/*
Run performance benchmarks
Execute comprehensive load tests to measure the performance improvements from your optimizations.
# Test concurrent connections (100 concurrent, 1000 total requests)
ab -n 1000 -c 100 http://localhost/test/large.html
Test with different concurrency levels
ab -n 2000 -c 200 http://localhost/test/large.html
Test compression effectiveness
curl -H "Accept-Encoding: gzip" -s http://localhost/test/large.html | wc -c
curl -s http://localhost/test/large.html | wc -c
Test Brotli compression
curl -H "Accept-Encoding: br" -s http://localhost/test/large.html | wc -c
Verify your setup
# Check Apache is running with worker MPM
sudo apache2ctl -M | grep mpm
apache2ctl -V | grep MPM
Verify compression modules are loaded
sudo apache2ctl -M | grep -E "deflate|brotli|expires|cache|headers"
Check server status page
curl http://localhost/server-status
Test compression is working
curl -H "Accept-Encoding: gzip" -I http://localhost/test/large.html | grep -i encoding
Verify cache directory exists and has correct permissions
ls -la /var/cache/apache2/mod_cache_disk/
Check process and thread counts
ps aux | grep apache2 | wc -l
Performance tuning parameters explained
| Parameter | Function | Recommended Value | Impact |
|---|---|---|---|
| MaxRequestWorkers | Maximum concurrent connections | 1024 | Higher allows more concurrent users |
| ThreadsPerChild | Threads per Apache process | 32 | Balance between memory usage and concurrency |
| DeflateCompressionLevel | Gzip compression strength | 6 | Balance between CPU usage and file size |
| BrotliCompressionQuality | Brotli compression strength | 6 | Better compression than gzip with similar CPU cost |
| CacheMaxExpire | Maximum cache time | 86400 | Longer cache reduces server load |
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Apache won't start after config changes | Configuration syntax errors | sudo apache2ctl configtest to check syntax |
| High memory usage | Too many MaxRequestWorkers | Reduce MaxRequestWorkers and ThreadsPerChild values |
| Compression not working | Missing Accept-Encoding headers | Check client sends Accept-Encoding: gzip, br |
| Cache directory permission errors | Wrong ownership on cache directory | sudo chown -R www-data:www-data /var/cache/apache2 |
| Server status page not accessible | mod_status not enabled or wrong IP | Verify sudo a2enmod status and check IP restrictions |
| Slow response times under load | Insufficient server resources | Monitor with htop and adjust worker settings |
| Cache not working for dynamic content | Incorrect cache headers | Add Cache-Control headers in application code |
Next steps
- Configure Apache virtual hosts and SSL certificates for secure hosting
- Optimize Linux I/O performance to improve overall server performance
- Setup NGINX reverse proxy for load balancing Apache servers
- Configure Apache HTTP/2 and SSL termination for modern protocol support
- Implement Apache log analysis with GoAccess and ELK Stack
- Configure Apache rate limiting and DDoS protection for security hardening
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Apache HTTP Server Performance Optimization Script
# Optimizes Apache with caching, compression, and worker tuning
# Colors
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly NC='\033[0m'
# Configuration
DOMAIN="${1:-localhost}"
WORKER_THREADS="${2:-25}"
MAX_CONNECTIONS="${3:-400}"
usage() {
echo "Usage: $0 [domain] [worker_threads] [max_connections]"
echo " domain: Domain name (default: localhost)"
echo " worker_threads: Threads per child process (default: 25)"
echo " max_connections: Maximum connections (default: 400)"
exit 1
}
log() { echo -e "${GREEN}[INFO]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; }
# Check root privileges
[[ $EUID -eq 0 ]] || error "This script must be run as root"
# Detect distribution
if [[ ! -f /etc/os-release ]]; then
error "Cannot detect distribution - /etc/os-release not found"
fi
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_INSTALL="apt install -y"
PKG_UPDATE="apt update && apt upgrade -y"
APACHE_SERVICE="apache2"
APACHE_CONF_DIR="/etc/apache2"
APACHE_SITES_DIR="/etc/apache2/sites-available"
APACHE_MODS_DIR="/etc/apache2/mods-available"
APACHE_LOG_DIR="/var/log/apache2"
APACHE_CACHE_DIR="/var/cache/apache2/mod_cache_disk"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
PKG_UPDATE="dnf update -y"
APACHE_SERVICE="httpd"
APACHE_CONF_DIR="/etc/httpd"
APACHE_SITES_DIR="/etc/httpd/conf.d"
APACHE_MODS_DIR="/etc/httpd/conf.modules.d"
APACHE_LOG_DIR="/var/log/httpd"
APACHE_CACHE_DIR="/var/cache/httpd/mod_cache_disk"
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
PKG_UPDATE="yum update -y"
APACHE_SERVICE="httpd"
APACHE_CONF_DIR="/etc/httpd"
APACHE_SITES_DIR="/etc/httpd/conf.d"
APACHE_MODS_DIR="/etc/httpd/conf.modules.d"
APACHE_LOG_DIR="/var/log/httpd"
APACHE_CACHE_DIR="/var/cache/httpd/mod_cache_disk"
;;
*)
error "Unsupported distribution: $ID"
;;
esac
# Cleanup on error
cleanup() {
warn "Script failed, performing cleanup..."
systemctl stop $APACHE_SERVICE 2>/dev/null || true
}
trap cleanup ERR
echo "[1/8] Updating system packages and installing Apache..."
$PKG_UPDATE
if [[ "$ID" =~ ^(ubuntu|debian)$ ]]; then
$PKG_INSTALL apache2 apache2-utils brotli libapache2-mod-brotli
else
$PKG_INSTALL httpd httpd-tools brotli
# Try to install mod_brotli from EPEL
$PKG_INSTALL epel-release 2>/dev/null || true
$PKG_INSTALL httpd-mod-brotli 2>/dev/null || warn "mod_brotli not available from repositories"
fi
systemctl enable $APACHE_SERVICE
echo "[2/8] Enabling performance modules..."
if [[ "$ID" =~ ^(ubuntu|debian)$ ]]; then
a2dismod mpm_prefork 2>/dev/null || true
a2enmod mpm_worker deflate expires headers cache cache_disk status info rewrite
[[ -f /etc/apache2/mods-available/brotli.load ]] && a2enmod brotli || warn "Brotli module not available"
else
# Create module configuration for RHEL-based systems
cat > "$APACHE_MODS_DIR/00-performance.conf" << 'EOF'
LoadModule deflate_module modules/mod_deflate.so
LoadModule expires_module modules/mod_expires.so
LoadModule headers_module modules/mod_headers.so
LoadModule cache_module modules/mod_cache.so
LoadModule cache_disk_module modules/mod_cache_disk.so
LoadModule status_module modules/mod_status.so
LoadModule info_module modules/mod_info.so
LoadModule rewrite_module modules/mod_rewrite.so
EOF
[[ -f /etc/httpd/modules/mod_brotli.so ]] && echo "LoadModule brotli_module modules/mod_brotli.so" >> "$APACHE_MODS_DIR/00-performance.conf"
fi
echo "[3/8] Configuring worker MPM..."
cat > "$APACHE_CONF_DIR/conf$([ "$ID" =~ ^(ubuntu|debian)$ ] && echo '-available' || echo '.d')/worker-mpm.conf" << EOF
<IfModule mpm_worker_module>
ServerLimit 16
MaxRequestWorkers $MAX_CONNECTIONS
ThreadsPerChild $WORKER_THREADS
ThreadLimit 64
StartServers 3
MinSpareThreads 75
MaxSpareThreads 250
MaxConnectionsPerChild 10000
</IfModule>
EOF
[[ "$ID" =~ ^(ubuntu|debian)$ ]] && a2enconf worker-mpm
echo "[4/8] Setting up compression with mod_deflate..."
cat > "$APACHE_SITES_DIR/compression.conf" << 'EOF'
<IfModule mod_deflate.c>
# Enable deflate compression
SetOutputFilter DEFLATE
# Compress these file types
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript
AddOutputFilterByType DEFLATE application/javascript application/json application/xml
AddOutputFilterByType DEFLATE application/rss+xml application/atom+xml image/svg+xml
# Set compression level (1-9, 9 is highest)
DeflateCompressionLevel 6
# Don't compress already compressed files
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|zip|gz|rar|bz2|7z|mp[34]|avi|mov)$ no-gzip
# Add Vary header for caching proxies
Header append Vary Accept-Encoding env=!dont-vary
</IfModule>
EOF
echo "[5/8] Configuring Brotli compression..."
cat > "$APACHE_SITES_DIR/brotli.conf" << 'EOF'
<IfModule mod_brotli.c>
# Enable Brotli compression
BrotliCompressionQuality 6
BrotliCompressionWindow 22
# Compress these MIME types with Brotli
AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/xml text/css
AddOutputFilterByType BROTLI_COMPRESS text/javascript application/javascript
AddOutputFilterByType BROTLI_COMPRESS application/json application/xml
AddOutputFilterByType BROTLI_COMPRESS application/rss+xml application/atom+xml
AddOutputFilterByType BROTLI_COMPRESS image/svg+xml
</IfModule>
EOF
echo "[6/8] Setting up caching configuration..."
# Create cache directory
mkdir -p "$APACHE_CACHE_DIR"
chown -R $([ "$ID" =~ ^(ubuntu|debian)$ ] && echo "www-data:www-data" || echo "apache:apache") "$APACHE_CACHE_DIR"
chmod 755 "$APACHE_CACHE_DIR"
cat > "$APACHE_SITES_DIR/caching.conf" << EOF
<IfModule mod_cache.c>
<IfModule mod_cache_disk.c>
CacheRoot $APACHE_CACHE_DIR
CacheEnable disk /
CacheDirLevels 2
CacheDirLength 1
CacheMaxFileSize 10000000
CacheDefaultExpire 3600
CacheMaxExpire 86400
</IfModule>
</IfModule>
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/jpg "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/svg+xml "access plus 1 month"
ExpiresByType text/html "access plus 1 hour"
</IfModule>
<IfModule mod_headers.c>
Header set Cache-Control "public, max-age=2592000" "expr=%{CONTENT_TYPE} =~ m#^image/#"
Header set Cache-Control "public, max-age=604800" "expr=%{CONTENT_TYPE} =~ m#^text/(css|javascript)#"
</IfModule>
EOF
echo "[7/8] Configuring server status monitoring..."
cat > "$APACHE_SITES_DIR/status.conf" << 'EOF'
<Location "/server-status">
SetHandler server-status
Require local
</Location>
<Location "/server-info">
SetHandler server-info
Require local
</Location>
EOF
# Enable configurations on Debian-based systems
if [[ "$ID" =~ ^(ubuntu|debian)$ ]]; then
a2enconf compression brotli caching status 2>/dev/null || true
fi
echo "[8/8] Starting and verifying Apache configuration..."
# Test configuration
if ! $APACHE_SERVICE -t 2>/dev/null; then
error "Apache configuration test failed"
fi
# Start Apache
systemctl start $APACHE_SERVICE
systemctl reload $APACHE_SERVICE
# Configure firewall
if command -v ufw &> /dev/null && ufw status | grep -q "Status: active"; then
ufw allow 'Apache Full' || ufw allow 80/tcp && ufw allow 443/tcp
elif command -v firewall-cmd &> /dev/null && systemctl is-active --quiet firewalld; then
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload
fi
# Verification
log "Verifying Apache optimization..."
if systemctl is-active --quiet $APACHE_SERVICE; then
log "✓ Apache is running"
else
error "Apache failed to start"
fi
if $APACHE_SERVICE -M | grep -q "deflate_module"; then
log "✓ Deflate compression enabled"
fi
if $APACHE_SERVICE -M | grep -q "brotli_module"; then
log "✓ Brotli compression enabled"
else
warn "Brotli compression not available"
fi
if $APACHE_SERVICE -M | grep -q "cache_module"; then
log "✓ Caching modules enabled"
fi
log "Apache optimization completed successfully!"
log "Server status available at: http://$DOMAIN/server-status"
log "Configuration test: systemctl status $APACHE_SERVICE"
log "Cache directory: $APACHE_CACHE_DIR"
Review the script before running. Execute with: bash install.sh