Nginx vs Apache : quel serveur web choisir ?
Le choix entre Nginx et Apache dépend de votre cas d'usage. Voici une comparaison objective. Les deux sont des logiciels libres matures, maintenus activement, et servent ensemble une très large part des sites web. Aucun n'est « meilleur » dans l'absolu : ils ont été conçus à des époques différentes, avec des priorités différentes, et ces choix d'origine expliquent encore aujourd'hui leurs forces respectives.
Architecture
Apache utilise un modèle basé sur les processus/threads (prefork ou worker). Chaque connexion est gérée par un processus ou thread dédié.
Nginx utilise une architecture événementielle asynchrone. Un processus worker peut gérer des milliers de connexions simultanées.
Concrètement, Apache délègue ce comportement à un module appelé MPM (Multi-Processing Module) :
prefork: un processus par connexion, sans threads. C'est le plus gourmand en mémoire, mais c'est le seul compatible avecmod_php, car PHP n'était historiquement pas garanti thread-safe.worker: plusieurs processus, chacun avec plusieurs threads. Plus économe en mémoire.event: une évolution deworkerqui confie les connexions keep-alive inactives à un thread dédié, au lieu de bloquer un thread par client. C'est le MPM par défaut sur les distributions récentes quandmod_phpn'est pas installé.
Nginx, lui, lance un petit nombre de processus workers (souvent un par cœur, avec worker_processes auto;). Chacun traite des milliers de connexions en boucle d'événements, grâce à epoll sous Linux. Une connexion inactive ne coûte que quelques kilo-octets de mémoire, ce qui explique sa stabilité face à un grand nombre de clients lents ou de connexions keep-alive.
Performances
# Benchmark avec ab (Apache Bench)
ab -n 10000 -c 100 http://localhost/
# Nginx : ~15000 req/s pour du contenu statique
# Apache : ~5000 req/s pour du contenu statique
Ces chiffres sont des ordres de grandeur, à prendre avec prudence : ils varient énormément selon le matériel, la taille des fichiers, la configuration du MPM et le nombre de connexions simultanées. Un Apache configuré avec le MPM event réduit nettement l'écart. Mesurez toujours sur votre propre infrastructure, idéalement depuis une autre machine que le serveur testé, et avec un outil comme wrk qui génère une charge plus réaliste qu'ab.
Surtout, pour une application PHP, le serveur web est rarement le goulot d'étranglement. Le temps de réponse est dominé par l'exécution du code PHP, les requêtes SQL et les appels réseau. La différence entre Nginx et Apache se voit surtout sur les fichiers statiques et sous forte concurrence.
Configuration PHP
Apache avec mod_php :
<VirtualHost *:80>
DocumentRoot /var/www/html/public
<Directory /var/www/html/public>
AllowOverride All
</Directory>
</VirtualHost>
Avec mod_php, l'interpréteur PHP est chargé dans chaque processus Apache, y compris ceux qui ne servent qu'une image ou un fichier CSS. AllowOverride All active les fichiers .htaccess : pratique, mais Apache doit alors chercher ces fichiers dans chaque répertoire du chemin, à chaque requête.
Nginx avec PHP-FPM :
server {
root /var/www/html/public;
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
}
Nginx n'exécute pas PHP : il transmet les requêtes .php à PHP-FPM via FastCGI, ici par un socket Unix. Les deux services ont des pools de processus indépendants, que l'on dimensionne séparément. L'usage de $realpath_root plutôt que $document_root résout les liens symboliques, ce qui est important avec les déploiements atomiques où current pointe vers une nouvelle release.
Pour une application Symfony, la configuration recommandée va plus loin : toutes les requêtes qui ne correspondent pas à un fichier existant passent par index.php, et aucun autre fichier PHP n'est exécutable :
server {
listen 80;
server_name example.com;
root /var/www/html/public;
location / {
try_files $uri /index.php$is_args$args;
}
location ~ ^/index\.php(/|$) {
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
internal;
}
location ~ \.php$ {
return 404;
}
}
La directive internal empêche d'appeler /index.php directement dans l'URL, et le dernier bloc renvoie une 404 pour tout autre fichier PHP : un script oublié dans public/ ne pourra pas être exécuté.
Apache moderne : event et PHP-FPM
Apache n'est pas condamné au couple prefork + mod_php. Il peut lui aussi déléguer PHP à PHP-FPM via mod_proxy_fcgi, et utiliser le MPM event. Sur Debian ou Ubuntu :
sudo apt install php8.3-fpm
sudo a2dismod php8.3 mpm_prefork
sudo a2enmod mpm_event proxy_fcgi setenvif
sudo a2enconf php8.3-fpm
sudo apachectl configtest && sudo systemctl restart apache2
Le virtual host transmet alors les fichiers PHP au socket de PHP-FPM. Si vous n'avez pas besoin de .htaccess, désactivez-les et placez les règles directement dans la configuration :
<VirtualHost *:80>
ServerName example.com
DocumentRoot /var/www/html/public
<Directory /var/www/html/public>
AllowOverride None
Require all granted
FallbackResource /index.php
</Directory>
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost"
</FilesMatch>
</VirtualHost>
FallbackResource joue le même rôle que le try_files de Nginx : toute URL qui ne correspond pas à un fichier est servie par index.php. Avec cette configuration, Apache consomme beaucoup moins de mémoire et se rapproche de Nginx sur la gestion des connexions.
Comparatif rapide
| Critère | Nginx | Apache |
|---|---|---|
| Modèle | Événementiel, asynchrone | Processus/threads via MPM (prefork, worker, event) |
| PHP | Via PHP-FPM uniquement | mod_php ou PHP-FPM |
| Configuration par répertoire | Non (configuration centrale) | Oui, avec .htaccess |
| Contenu statique | Très efficace | Correct, surtout avec event |
| Reverse proxy, load balancing | Usage natif et très répandu | Possible via mod_proxy |
| Test de la configuration | nginx -t | apachectl configtest |
Quand choisir quoi ?
- Nginx : contenu statique, reverse proxy, haute concurrence, microservices
- Apache : .htaccess requis, modules spécifiques, compatibilité héritée
- Les deux : Nginx en reverse proxy devant Apache pour le meilleur des deux mondes
Le cas « les deux » se rencontre souvent sur les hébergements mutualisés ou lors d'une migration progressive : Nginx écoute sur les ports publics, sert les fichiers statiques et gère TLS, puis transmet le reste à Apache sur un port local :
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:8080;
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_set_header X-Forwarded-Proto $scheme;
}
}
Dans ce montage, activez mod_remoteip côté Apache pour que les logs et l'application voient l'adresse IP réelle du client, et non celle de Nginx. Côté Symfony, déclarez 127.0.0.1 dans framework.trusted_proxies pour que les en-têtes X-Forwarded-* soient pris en compte.
Pièges courants
- Mélanger
mod_phpet le MPMevent: impossible, Apache refuse de démarrer. Passez à PHP-FPM pour utiliserevent. - Traduire un
.htaccessà l'aveugle : lors d'une migration vers Nginx, les règles de réécriture doivent être reprises à la main dans la configuration, sinon des redirections ou des protections disparaissent silencieusement. - Oublier de tester la configuration : lancez toujours
nginx -touapachectl configtestavant de recharger le service. - Dimensionner un seul côté : avec PHP-FPM, c'est souvent
pm.max_childrenqui limite le débit, pas le serveur web.
Dans des contextes à fort trafic comme chez CCM Benchmark, Nginx est privilégié pour sa gestion efficace des connexions concurrentes.
En résumé : pour un nouveau projet PHP ou Symfony, Nginx avec PHP-FPM est un choix par défaut solide et simple. Apache reste pertinent quand des fichiers .htaccess sont indispensables, quand une application dépend de modules spécifiques, ou quand l'équipe maîtrise déjà son écosystème. Dans les deux cas, c'est la configuration, et en particulier celle de PHP-FPM, qui fera la différence en production.