---
title: "Apache vs Nginx: Performance, Architecture and Use Cases"
description: "Compare Apache and Nginx on architecture, memory use, PHP handling, .htaccess, reverse proxying and configuration syntax, with examples for Ubuntu 24.04."
category: "Comparison Guide"
language: en
source: https://cubepath.com/docs/comparison-guide/apache-vs-nginx-performance-and-use-cases
updated: 2026-09-25
---
# Apache vs Nginx: Performance, Architecture and Use Cases
Apache HTTP Server and Nginx are the two most widely deployed open source web servers. Both serve static files, run PHP applications through PHP-FPM, terminate TLS and work as reverse proxies, so for most sites either one will do the job. The real differences are in how they handle connections, how they are configured and whether you need per-directory `.htaccess` files. This guide compares both with side-by-side configuration examples for Ubuntu 24.04 and explains which one to choose for common workloads.
## Quick comparison
| Aspect | Apache 2.4 | Nginx |
|---|---|---|
| Connection model | Multi-Processing Modules (MPM): `prefork`, `worker` or `event` | Event-driven, a few worker processes handle thousands of connections each |
| Memory under many idle connections | Higher, especially with `prefork` | Low and predictable |
| PHP | PHP-FPM via `mod_proxy_fcgi`, or embedded `mod_php` | PHP-FPM via FastCGI only |
| Per-directory config | `.htaccess` files, no reload needed | Not supported; all config is central |
| Modules | Loaded dynamically with `a2enmod` | Compiled in, or dynamic modules packaged separately |
| Reverse proxy and load balancing | `mod_proxy`, `mod_proxy_balancer` | Built in (`proxy_pass`, `upstream`) |
| Caching | `mod_cache`, `mod_cache_disk` | `proxy_cache`, `fastcgi_cache` |
| Config test | `sudo apache2ctl configtest` | `sudo nginx -t` |
| Package on Ubuntu 24.04 | `apache2` (2.4.58) | `nginx` (1.24) |
## Architecture
### Apache
Apache delegates connection handling to a Multi-Processing Module:
- **prefork**: one process per connection, no threads. Needed only for non-thread-safe modules such as the embedded `mod_php`. Memory use grows quickly with concurrent connections.
- **worker**: several processes, each with many threads. One thread per connection.
- **event**: like `worker`, but idle keep-alive connections are handed to a listener thread, so they do not occupy a worker thread. This is the default on Ubuntu and the right choice with PHP-FPM.
Check which MPM a server is using:
```bash
sudo apache2ctl -M | grep mpm
```
```output
mpm_event_module (shared)
```
If you see `mpm_prefork_module`, the server is probably running `mod_php`. Switching to PHP-FPM and the event MPM is the single biggest performance improvement for most Apache servers.
### Nginx
Nginx runs one master process and a small number of worker processes (by default one per CPU core with `worker_processes auto;`). Each worker handles many connections in a non-blocking event loop, so thousands of slow or idle clients cost very little memory. Nginx never runs application code itself; PHP, Python or Node.js applications run in separate processes that Nginx talks to over FastCGI or HTTP.
## Performance in practice
Performance differences depend far more on the configuration than on the server itself:
- **Static files**: Nginx is very efficient at serving static files and handling many concurrent connections. Apache with the event MPM is close for moderate traffic, but uses more memory as concurrency grows.
- **PHP applications**: the bottleneck is PHP and the database, not the web server. With both servers passing requests to the same PHP-FPM pool, response times are nearly identical. Apache with `prefork` and `mod_php` is the slow outlier because every connection, including ones for images and CSS, occupies a full PHP-enabled process.
- **Many slow clients or long keep-alives**: Nginx keeps memory flat; Apache `prefork` can run out of processes (`MaxRequestWorkers`) and queue requests.
- **`.htaccess`**: when `AllowOverride` is enabled, Apache checks for `.htaccess` files in every directory of the path on every request. Disabling it where you do not need it saves filesystem lookups.
Do not rely on generic benchmark numbers. Measure your own site with a load testing tool such as `wrk`, from a different machine than the server:
```bash
sudo apt install wrk
wrk -t4 -c200 -d30s https://your_domain/
```
```output
Running 30s test @ https://your_domain/
4 threads and 200 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 24.10ms 10.52ms 210.33ms 78.10%
Req/Sec 2.08k 310.12 2.90k 70.25%
248913 requests in 30.03s, 1.21GB read
Requests/sec: 8288.71
Transfer/sec: 41.26MB
```
Run the same test against both servers with the same content and PHP-FPM pool, and watch memory with `free -h` while it runs.
## Configuration side by side
All examples assume Ubuntu 24.04, a site in `/var/www/your_domain` and the domain `your_domain`.
### Virtual host
Apache site file, created with `sudo nano /etc/apache2/sites-available/your_domain.conf`:
```apache
ServerName your_domain
ServerAlias www.your_domain
DocumentRoot /var/www/your_domain
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
ErrorLog ${APACHE_LOG_DIR}/your_domain_error.log
CustomLog ${APACHE_LOG_DIR}/your_domain_access.log combined
```
Enable it and reload:
```bash
sudo a2ensite your_domain.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
```
Nginx server block, created with `sudo nano /etc/nginx/sites-available/your_domain`:
```nginx
server {
listen 80;
listen [::]:80;
server_name your_domain www.your_domain;
root /var/www/your_domain;
index index.html index.php;
access_log /var/log/nginx/your_domain_access.log;
error_log /var/log/nginx/your_domain_error.log;
location / {
try_files $uri $uri/ =404;
}
}
```
Enable it and reload:
```bash
sudo ln -s /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
```
### PHP with PHP-FPM
Install PHP-FPM (PHP 8.3 on Ubuntu 24.04):
```bash
sudo apt install php8.3-fpm
```
On Apache, enable the FastCGI proxy modules and the PHP-FPM configuration shipped by the package:
```bash
sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php8.3-fpm
sudo systemctl reload apache2
```
On Nginx, add a PHP location inside the `server` block:
```nginx
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
location ~ /\.ht {
deny all;
}
```
Test and reload Nginx with `sudo nginx -t && sudo systemctl reload nginx`. In both cases, a file containing `` to ``.
2. Proxy from Nginx with `proxy_pass http://127.0.0.1:8080;` and the headers shown in the reverse proxy example.
3. Enable `sudo a2enmod remoteip` and add `RemoteIPHeader X-Forwarded-For` and `RemoteIPInternalProxy 127.0.0.1` to Apache so logs and applications see the real client IP.
It adds a moving part, so use it only if you need `.htaccess`; otherwise a single Nginx or a single Apache with the event MPM is simpler.
## Which one should you choose?
Choose **Apache** when:
- Your application or users rely on `.htaccess` (shared hosting, many WordPress plugins, legacy PHP apps).
- You need modules that exist only for Apache, such as some authentication modules.
- Your team already knows Apache configuration and your traffic is moderate.
Choose **Nginx** when:
- You serve many concurrent connections, large static files or media.
- The server is mainly a reverse proxy or load balancer in front of Node.js, Python, Go or container workloads.
- You run on a small VPS where memory is limited.
- You want built-in rate limiting and simple caching of upstream responses.
For a new PHP site you control, either works; Nginx with PHP-FPM is the more common choice today, and Apache with the event MPM and PHP-FPM performs very similarly.
## Conclusion
Apache and Nginx are both mature and fast enough for almost any site once they are configured correctly: Apache with the event MPM and PHP-FPM, Nginx with PHP-FPM or as a reverse proxy. Pick Apache when you need `.htaccess` and its module ecosystem, and Nginx when you need high concurrency, low memory use or a reverse proxy. As a next step, secure your chosen server with Let's Encrypt using Certbot, and load test your real application with `wrk` before and after tuning.