Apache vs Nginx: Complete Performance Comparison & Tuning Guide

This comprehensive guide compares Apache and Nginx architectures, benchmarks static and dynamic workloads, explores high‑concurrency testing, and provides detailed tuning steps for both servers along with real‑world case studies and future trends such as HTTP/3 and container deployment.

MaGe Linux Operations
MaGe Linux Operations
MaGe Linux Operations
Apache vs Nginx: Complete Performance Comparison & Tuning Guide

Apache vs Nginx Performance Comparison and Tuning Guide

Why Web Server Performance Tuning Matters

In today’s fast‑moving internet era, website performance directly impacts user experience and business revenue; a one‑second increase in page load time can reduce conversion rates by 7%.

Chapter 1: Architecture Comparison

1.1 Apache Architecture Deep Dive

Apache HTTP Server uses a modular design based on a process/thread model. Main modes include:

Prefork mode (process mode)

Each process handles one connection

Higher memory overhead but stable

Suitable for CPU‑intensive applications

Worker mode (mixed mode)

Multi‑process + multi‑thread architecture

Higher memory efficiency

Balances performance and stability

Event mode (event‑driven)

Based on asynchronous event handling

Optimized for Keep‑Alive connections

Default mode in Apache 2.4

1.2 Nginx Architecture Deep Dive

Nginx uses a master‑worker multi‑process model with an event‑driven asynchronous non‑blocking architecture:

Master process responsibilities:

Read configuration files

Manage worker processes

Handle signals

Worker process responsibilities:

Handle actual network connections

Each worker can handle thousands of concurrent connections

Based on epoll/kqueue event model

1.3 Architecture Comparison Summary

Feature          Apache          Nginx
Concurrency Model Process/Thread  Event‑driven
Memory Usage      Higher          Lower
CPU Usage          Medium          Lower
Concurrent Capacity Medium (1‑2K)  High (10K+)
Extensibility    Rich modules    Limited but efficient modules

Chapter 2: Performance Benchmark

2.1 Test Environment Setup

# System environment
OS: CentOS 8.4
CPU: Intel Xeon 4 cores 2.4GHz
Memory: 8GB RAM
Disk: SSD 100GB

# Apache version: 2.4.53
# Nginx version: 1.20.2

# Install Apache
sudo dnf install httpd httpd-tools -y

# Install Nginx
sudo dnf install nginx -y

# Install load testing tools
sudo dnf install httpd-tools wrk -y

2.2 Static File Performance Test

# Create test files
dd if=/dev/zero of=/var/www/html/test1k.html bs=1024 count=1
dd if=/dev/zero of=/var/www/html/test10k.html bs=1024 count=10
dd if=/dev/zero of=/var/www/html/test100k.html bs=1024 count=100

# Apache benchmark
ab -n 10000 -c 100 http://localhost/test1k.html

# Nginx benchmark (using wrk)
wrk -t4 -c100 -d30s http://localhost/test1k.html

Test results show Nginx has a clear advantage for static file serving.

2.3 Dynamic Content Test

<?php
header('Content-Type: text/html; charset=utf-8');
echo "Hello World! " . date('Y-m-d H:i:s');
usleep(1000); // 1ms delay
echo "
Database query completed.";
$result = 0;
for ($i = 0; $i < 1000; $i++) { $result += $i; }
echo "
Calculation result: " . $result;
?>

Results:

Server          QPS   Avg Resp Time   Memory   CPU%
Apache+PHP       487   205ms           156MB    68%
Nginx+PHP-FPM   612   163ms           124MB    52%

2.4 High Concurrency Test

# High concurrency with wrk
wrk -t12 -c1000 -d60s --latency http://localhost/

# Staircase test with ApacheBench
for i in 50 100 200 500 1000 2000; do
  echo "Testing with $i concurrent connections"
  ab -n 10000 -c $i http://localhost/ > results_$i.txt
  sleep 5
done

Key indicators:

Apache limit ~2,000 connections

Nginx limit >10,000 connections

Memory usage: Nginx saves about 40%

CPU efficiency: Nginx leads by ~25%

Chapter 3: Apache Performance Tuning

3.1 MPM Module Optimization

# /etc/httpd/conf/httpd.conf
# Event MPM (recommended)
LoadModule mpm_event_module modules/mod_mpm_event.so

<IfModule mpm_event_module>
ServerLimit 16
MaxRequestWorkers 1000
ThreadsPerChild 64
AsyncRequestWorkerFactor 100
MinSpareThreads 75
MaxSpareThreads 250
ThreadLimit 64
StartServers 3
MaxMemFree 2048
</IfModule>

# Worker MPM (alternative)
<IfModule mpm_worker_module>
StartServers 4
MaxRequestWorkers 1000
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild 25
ServerLimit 40
</IfModule>

Key parameters explained: MaxRequestWorkers: maximum concurrent requests ThreadsPerChild: threads per child process ServerLimit: maximum server processes AsyncRequestWorkerFactor: async connection handling factor

3.2 Cache Optimization

# Enable modules
LoadModule expires_module modules/mod_expires.so
LoadModule headers_module modules/mod_headers.so
LoadModule deflate_module modules/mod_deflate.so

# Static resource cache
<LocationMatch "\.(css|js|png|jpg|jpeg|gif|ico|svg)$">
ExpiresActive On
ExpiresDefault "access plus 30 days"
Header append Cache-Control "public, immutable"
</LocationMatch>

# HTML cache
<LocationMatch "\.html$">
ExpiresActive On
ExpiresDefault "access plus 1 hour"
</LocationMatch>

# Gzip compression
<Location />
SetOutputFilter DEFLATE
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary
SetEnvIfNoCase Request_URI \.(?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary
</Location>

3.3 Memory and Connection Optimization

# Connection tuning
Timeout 60
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5

# Request size limits
LimitRequestBody 10485760
LimitRequestFields 100
LimitRequestFieldSize 8190
LimitRequestLine 4094

# Preload optimization
<Location />
Header always set Link "</css/main.css>; rel=preload; as=style"
Header always set Link "</js/main.js>; rel=preload; as=script"
</Location>

3.4 Security vs Performance

# Hide version info
ServerTokens Prod
ServerSignature Off

# Disable unnecessary modules
#LoadModule autoindex_module modules/mod_autoindex.so
#LoadModule status_module modules/mod_status.so

# Log optimization
LogLevel warn
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
CustomLog logs/access_log combined

Chapter 4: Nginx Performance Tuning

4.1 Worker Process Optimization

# /etc/nginx/nginx.conf
worker_processes auto;
worker_cpu_affinity auto;
worker_priority -5;

events {
    worker_connections 4096;
    use epoll;
    multi_accept on;
    accept_mutex off;
}

4.2 Core HTTP Parameters

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    keepalive_timeout 65;
    keepalive_requests 1000;
    client_header_timeout 60;
    client_body_timeout 60;
    send_timeout 60;

    client_body_buffer_size 16k;
    client_header_buffer_size 4k;
    large_client_header_buffers 8 16k;
    client_max_body_size 50m;

    open_file_cache max=10000 inactive=60s;
    open_file_cache_valid 120s;
    open_file_cache_min_uses 2;
    open_file_cache_errors on;
}

4.3 Gzip Compression

http {
    gzip on;
    gzip_vary on;
    gzip_min_length 1000;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/atom+xml image/svg+xml;
    gzip_static on;
    gzip_proxied any;
}

4.4 Cache Strategy

http {
    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m use_temp_path=off;

    server {
        listen 80;
        server_name example.com;

        # Static assets
        location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
            expires 30d;
            add_header Cache-Control "public, no-transform";
            access_log off;
        }

        # API cache
        location /api/ {
            proxy_cache my_cache;
            proxy_cache_valid 200 302 10m;
            proxy_cache_valid 404 1m;
            proxy_cache_use_stale error timeout updating;
            proxy_pass http://backend;
        }

        # HTML cache
        location / {
            expires 1h;
            add_header Cache-Control "public";
            try_files $uri $uri/ @fallback;
        }
    }
}

4.5 Load Balancing and Reverse Proxy

upstream backend {
    least_conn;
    server 192.168.1.10:8080 weight=3 max_fails=3 fail_timeout=30s;
    server 192.168.1.11:8080 weight=2 max_fails=3 fail_timeout=30s;
    server 192.168.1.12:8080 weight=1 backup;
    keepalive 32;
    keepalive_requests 100;
    keepalive_timeout 60s;
}

server {
    location / {
        proxy_pass http://backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_buffering on;
        proxy_buffer_size 8k;
        proxy_buffers 8 8k;
        proxy_busy_buffers_size 16k;
    }
}

Chapter 5: System‑Level Optimization

5.1 Kernel Parameter Tuning

# /etc/sysctl.conf
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 5000
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_fin_timeout = 10
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_max_tw_buckets = 6000

# File descriptor limits
fs.file-max = 2097152

# Application limits
echo "* soft nofile 65535" >> /etc/security/limits.conf
echo "* hard nofile 65535" >> /etc/security/limits.conf

sysctl -p

5.2 Monitoring Script Deployment

#!/bin/bash
LOG_FILE="/var/log/webserver_performance.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
LOAD=$(uptime | awk '{print $10,$11,$12}')
MEM_USED=$(free | grep Mem | awk '{printf("%.2f%%", $3/$2 * 100.0)}')
CONNECTIONS=$(ss -s | grep TCP: | awk '{print $4}')

if pgrep nginx > /dev/null; then
    NGINX_ACTIVE=$(curl -s http://localhost/nginx_status | head -n 3 | tail -n 1)
    echo "$DATE [NGINX] Active: $NGINX_ACTIVE, Load: $LOAD, Memory: $MEM_USED" >> $LOG_FILE
fi

if pgrep httpd > /dev/null; then
    APACHE_REQUESTS=$(curl -s http://localhost/server-status?auto | grep "ReqPerSec")
    echo "$DATE [APACHE] $APACHE_REQUESTS, Load: $LOAD, Memory: $MEM_USED" >> $LOG_FILE
fi

Chapter 6: Real‑World Cases

6.1 E‑commerce Site Optimization

Background: 5 million daily PV, peak QPS > 2000.

Apache prefork mode, avg response 850 ms, error rate 3.2 %, CPU 85 %.

Strategy: Switch to Nginx + PHP‑FPM, CDN static assets, configure upstream pool.

upstream php_backend {
    server 127.0.0.1:9000;
    server 127.0.0.1:9001;
    server 127.0.0.1:9002;
}
server {
    listen 80;
    root /var/www/html;
    index index.php;

    location ~* \.(jpg|jpeg|png|gif|css|js)$ {
        expires 30d;
        return 301 https://cdn.example.com$request_uri;
    }

    location ~ \.php$ {
        fastcgi_pass php_backend;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_cache_key $scheme$request_method$host$request_uri;
        fastcgi_cache_valid 200 10m;
        fastcgi_cache_use_stale error timeout updating;
    }
}

Results:

Avg response ↓ to 245 ms (‑71 %).

Error rate ↓ to 0.8 %.

CPU usage ↓ to 45 %.

QPS ↑ to > 4500.

6.2 API Service Optimization

Micro‑service API gateway with rate limiting.

http {
    limit_req_zone $binary_remote_addr zone=api:10m rate=100r/s;
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;

    server {
        listen 80;

        limit_req zone=api burst=200 nodelay;
        limit_conn conn_limit 20;

        location /health { access_log off; return 200 "healthy
"; }

        location /api/v1/users {
            limit_req zone=api burst=50 nodelay;
            proxy_pass http://user_service;
        }

        location /api/v1/orders {
            limit_req zone=api burst=100 nodelay;
            proxy_pass http://order_service;
        }
    }
}

Chapter 7: Monitoring and Troubleshooting

7.1 Key Metrics

QPS (Queries Per Second)

Average response time

95 % response time

Error rate

Concurrent connections

CPU/Memory usage

7.2 Monitoring Tools

# Nginx status
server {
    listen 8080;
    location /nginx_status {
        stub_status on;
        access_log off;
        allow 127.0.0.1;
        deny all;
    }
}

7.3 Troubleshooting Checklist

System resources – top, iotop, netstat.

Log analysis – slow requests, error codes.

Configuration validation – nginx -t, nginx -T.

Chapter 8: Future Trends

8.1 HTTP/3 and QUIC

server {
    listen 443 quic reuseport;
    listen 443 ssl http2;
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
    add_header Alt‑Svc 'h3-29=":443"; ma=86400';
}

8.2 Edge Computing Integration

Web servers increasingly integrate with CDNs and edge nodes for faster content delivery.

8.3 Containerized Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  template:
    spec:
      containers:
      - name: nginx
        image: nginx:1.21-alpine
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"

Conclusion: Choosing the Right Web Server

Apache is suitable when you need rich module support, existing legacy configurations, or .htaccess files. Nginx excels for high‑concurrency, static content, reverse‑proxy, and micro‑service gateways. Continuous monitoring and tuning are essential regardless of the choice.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

performance tuningNginxBenchmarkWeb serverApache
MaGe Linux Operations
Written by

MaGe Linux Operations

Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.