Home/Linux/Apache Performance Tuning: The Complete Guide to a Faster Web Server
Linux

Apache Performance Tuning: The Complete Guide to a Faster Web Server

Most sysadmins install Apache, get it running, and never touch the configuration again. And honestly, that works fine. until traffic picks up, response times cr...

Sunil

Sunil

Published on June 26, 2026 8 min read 4 views
Share:
Apache Performance Tuning: The Complete Guide to a Faster Web Server

Most sysadmins install Apache, get it running, and never touch the configuration again. And honestly, that works fine. until traffic picks up, response times creep past two seconds, and your boss starts asking uncomfortable questions in a Monday morning meeting.

Apache is a battle-tested web server that powers a huge chunk of the internet. But out-of-the-box, it's configured to be safe and compatible, not necessarily fast. The good news? With the right tuning, you can squeeze significantly more performance out of the exact same hardware. No cloud upgrade required, no new servers needed.

This guide walks through every major area of Apache performance tuning — from choosing the right MPM module to enabling compression, caching, and connection management. Whether you're running a small WordPress blog or a high-traffic production environment, these changes will make a real difference.

Why Apache Performance Tuning Actually Matters

Before diving into configs, let's talk about why this even deserves your attention.

A slow web server doesn't just frustrate users — it directly impacts your SEO rankings. Google has used page speed as a ranking signal since 2010, and with Core Web Vitals now in the mix, server response time (TTFB — Time to First Byte) is more important than ever. A TTFB above 600ms is a red flag. Under 200ms is where you want to be.

Beyond SEO, there's the resource cost angle. A poorly tuned Apache instance will spawn more processes than necessary, eat up RAM, and under heavy load — crash. Proper tuning means your server handles 500 concurrent users on the same resources that previously struggled with 100.

Step 1 — Choose the Right MPM Module

This is probably the single most impactful decision you'll make. Apache's Multi-Processing Module (MPM) determines how the server handles connections.

There are three main options:

  • prefork — Old school. One process per connection. Great for compatibility (especially PHP with mod_php), but terrible for memory efficiency at scale.

  • worker — Hybrid model. Multiple processes, each with multiple threads. Much better memory usage.

  • event — The modern choice. Similar to worker, but handles keep-alive connections much more efficiently by passing them off to a dedicated listener thread.

For most modern setups — especially those using PHP-FPM — event MPM is the right call. Here's how to enable it on Ubuntu/Debian:

sudo a2dismod mpm_prefork
sudo a2enmod mpm_event
sudo systemctl restart apache2

Once enabled, configure it in /etc/apache2/mods-enabled/mpm_event.conf:

<IfModule mpm_event_module>
    StartServers             3
    MinSpareThreads         75
    MaxSpareThreads        250
    ThreadsPerChild         25
    MaxRequestWorkers      400
    MaxConnectionsPerChild 10000
</IfModule>

Tweak MaxRequestWorkers based on your available RAM. A rough formula: divide your available RAM (in MB) by the average memory used per Apache process (usually 10–30 MB). Don't just crank this number up blindly — too high and you'll start swapping to disk, which kills performance far worse than a lower limit.

Step 2 — Tune KeepAlive Settings

KeepAlive allows multiple requests to reuse the same TCP connection. Without it, every single resource on a page — HTML, CSS, JS, images — opens a fresh connection. That's expensive.

Default Apache has KeepAlive enabled, but the timeout is often set too high. Here's a sensible configuration:

KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5

Setting KeepAliveTimeout to 5 seconds (down from the default 15) means idle connections get closed faster, freeing up worker threads for new requests. On a busy server, those freed threads matter a lot. If you're running a high-traffic API where most requests are short and frequent, you might even drop it to 2 or 3 seconds.

Step 3 — Enable mod_deflate for Compression

Transferring less data over the wire means faster page loads — simple as that. mod_deflate compresses text-based responses (HTML, CSS, JS, XML) before sending them to the browser.

Enable it and configure it like this:

<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/plain text/xml
    AddOutputFilterByType DEFLATE text/css text/javascript
    AddOutputFilterByType DEFLATE application/javascript application/x-javascript
    AddOutputFilterByType DEFLATE application/json application/xml
    BrowserMatch ^Mozilla/4 gzip-only-text/html
    BrowserMatch ^Mozilla/4\.0[678] no-gzip
    BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
</IfModule>

Compression typically reduces response sizes by 60–80% for text content. For a page with 200KB of HTML and CSS, that's potentially 120–160KB saved on every single request. Multiply that by thousands of daily visitors and you're looking at serious bandwidth savings too.

Step 4 — Implement Caching with mod_cache and mod_expires

One of the most underutilized performance tools in Apache is its built-in caching layer. Instead of generating or fetching the same response repeatedly, caching stores it and serves it directly.

Browser-side caching with mod_expires:

<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType image/jpg "access plus 1 month"
    ExpiresByType image/jpeg "access plus 1 month"
    ExpiresByType image/png "access plus 1 month"
    ExpiresByType image/webp "access plus 1 month"
    ExpiresByType text/css "access plus 1 week"
    ExpiresByType application/javascript "access plus 1 week"
    ExpiresByType text/html "access plus 1 hour"
</IfModule>

This tells browsers to cache static assets locally, so repeat visitors don't need to re-download your logo or stylesheet on every page load.

Server-side caching with mod_cache:

<IfModule mod_cache.c>
    CacheEnable disk /
    CacheRoot /var/cache/apache2/mod_cache_disk
    CacheDefaultExpire 3600
    CacheMaxExpire 86400
    CacheIgnoreNoLastMod On
</IfModule>

For dynamic content-heavy sites (like WordPress), pairing this with a full-page caching plugin like WP Rocket or W3 Total Cache gives even better results — Apache handles the cache serving at the server level before PHP even wakes up.

Step 5 — Disable Unnecessary Modules

This one's easy to overlook, but every loaded module adds overhead — memory, processing cycles, and potential attack surface. Run this to see what's currently enabled:

apache2ctl -M

Common modules you can likely disable if not in use:

  • mod_status — useful for debugging, not for production

  • mod_autoindex — auto directory listing (security risk too)

  • mod_userdir — user home directory access

  • mod_cgi — only if you're not running CGI scripts

  • mod_info — server info endpoint

Disable on Ubuntu/Debian:

sudo a2dismod autoindex userdir status
sudo systemctl reload apache2

Less is genuinely more here. A lean Apache instance starts faster, uses less memory, and has a smaller attack surface.

Step 6 — Optimize DNS and HostnameLookups

By default, HostnameLookups is off — and it should stay that way. If it's on, Apache performs a reverse DNS lookup for every single request to log the hostname instead of the IP address. This adds latency on every request. Verify it's disabled:

HostnameLookups Off

Similarly, avoid using hostname-based access controls in your config. Use IP addresses wherever possible. Hostname resolution in access rules triggers those same expensive DNS lookups.

Step 7 — Tune the Linux Kernel for Apache

Apache performance doesn't exist in a vacuum — it depends heavily on the underlying OS. A few key kernel-level tweaks can meaningfully improve throughput.

Add these to /etc/sysctl.conf:

# Increase TCP backlog
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535

# Reuse TIME_WAIT sockets
net.ipv4.tcp_tw_reuse = 1

# Increase file descriptor limits
fs.file-max = 100000

Apply with:

sudo sysctl -p

Also update /etc/security/limits.conf to allow Apache to open more files:

apache soft nofile 65535
apache hard nofile 65535

These changes let Apache handle more simultaneous connections without hitting OS-level bottlenecks.

Step 8 — Use AllowOverride Wisely

If your Apache config uses AllowOverride All, the server checks for an .htaccess file in every directory of every request path. That's a lot of disk reads that add up fast.

Wherever possible, move rules from .htaccess into your main virtual host config and set:

<Directory /var/www/html>
    AllowOverride None
</Directory>

This single change can noticeably reduce disk I/O on high-traffic servers, especially those serving many small files.

Common Mistakes That Kill Apache Performance

Even experienced admins make these. Avoid them:

  • Leaving MaxRequestWorkers too high — causes memory exhaustion under load

  • Enabling mod_status in production without IP restriction — information leak + slight overhead

  • Forgetting to disable HostnameLookups — adds DNS latency to every request

  • Using prefork MPM with high concurrency — it just doesn't scale

  • Not monitoring Apache at all — you can't tune what you're not measuring

For monitoring, mod_status (when properly restricted) combined with tools like Netdata, Prometheus + Apache Exporter, or even a simple watch -n1 "apachectl fullstatus" gives you real-time visibility.

Comments (0)

Leave a Reply