
Apache HTTP Server est le serveur web historique du Web. Si vous devez héberger plusieurs sites sur un serveur, activer HTTPS, configurer un reverse proxy ou diagnostiquer une erreur 403, ce guide vous donne les recettes essentielles en quelques minutes.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »Niveau : Débutant → Intermédiaire · Durée : 35-50 min
À la fin de ce guide, vous saurez :
- Créer un Virtual Host pour héberger un site
- Activer HTTPS avec Let's Encrypt (Certbot)
- Configurer un reverse proxy vers une application
- Choisir le bon MPM (prefork, worker, event)
- Diagnostiquer les erreurs courantes (403, 404, 500)
Choisissez votre parcours
Section intitulée « Choisissez votre parcours »Ce guide se lit dans l'ordre, mais chaque bloc est autonome. Si vous partez d'un serveur vierge, commencez par le Virtual Host : tout le reste (TLS, reverse proxy, réglages de performance) se greffe dessus. Si Apache tourne déjà et qu'une page renvoie une erreur, sautez directement au dépannage, la méthode de diagnostic y est donnée avant les causes.
Apache en 60 secondes
Section intitulée « Apache en 60 secondes »Le rôle d'Apache tient en une phrase : il écoute sur un port TCP, interprète les requêtes HTTP qui arrivent, et décide pour chacune s'il renvoie un fichier du disque ou s'il transmet la demande à un autre programme. Tout le reste (Virtual Hosts, TLS, réécriture d'URL, compression) n'est que du réglage autour de cette boucle.
Apache (prononcé « a-pa-tchi ») est un serveur web qui :
- Sert des fichiers statiques (HTML, CSS, JS, images)
- Héberge plusieurs sites sur une seule machine (Virtual Hosts)
- Proxyfie des applications backend (Node.js, Python, PHP)
- Gère les modules dynamiquement (TLS, réécriture, cache)
Scénario : que se passe-t-il quand vous tapez une URL ?
Section intitulée « Scénario : que se passe-t-il quand vous tapez une URL ? »Le schéma ci-dessous décompose le trajet d'une requête. Retenez surtout l'ordre des trois décisions qu'Apache prend, parce que c'est exactement l'ordre dans lequel vous devrez chercher une panne : il sélectionne d'abord le Virtual Host à partir de l'en-tête Host:, puis il résout le chemin demandé dans le DocumentRoot de ce vhost, puis il applique les blocs <Directory> qui décident d'autoriser ou de refuser la lecture.
Une erreur 404 signale un échec à la deuxième étape, une 403 un échec à la troisième. Cette distinction évite de perdre du temps à corriger un DocumentRoot qui était correct depuis le début.
Pour la culture : historique d'Apache
Apache a été créé en 1995 par un groupe de développeurs qui ont pris le code du serveur NCSA HTTPd et l'ont "patché" (d'où le nom "A Patchy Server" → Apache). Il est rapidement devenu le serveur web le plus utilisé au monde.
En 2019, Nginx l'a dépassé en parts de marché, mais Apache reste très présent, notamment dans les environnements PHP traditionnels et les hébergements mutualisés.
L'architecture modulaire d'Apache et sa documentation exhaustive en font toujours un choix pertinent pour de nombreux cas d'usage.
Comprendre avant d'agir : les 3 concepts clés
Section intitulée « Comprendre avant d'agir : les 3 concepts clés »Avant de plonger dans les commandes, assurez-vous de comprendre ces 3 concepts. Si vous les maîtrisez, tout le reste devient logique.
1. Le Virtual Host (VHost)
Section intitulée « 1. Le Virtual Host (VHost) »Question qu'on se pose tous : "Comment Apache sait quel site afficher quand j'ai plusieurs domaines ?"
Réponse : Grâce aux Virtual Hosts. Chaque VHost est un fichier de configuration qui dit :
- ServerName : "Si le visiteur demande CE domaine..."
- DocumentRoot : "...alors sers les fichiers de CE dossier"
# Traduction humaine de ce VHost :# "Si quelqu'un demande www.boutique.com, envoie-lui le contenu de /var/www/boutique"<VirtualHost *:80> ServerName www.boutique.com # ← Le domaine DocumentRoot /var/www/boutique # ← Le dossier des fichiers</VirtualHost>2. Les modules (a2enmod)
Section intitulée « 2. Les modules (a2enmod) »Question : "Pourquoi je dois 'activer' des trucs comme SSL ou rewrite ?"
Réponse : Apache est modulaire. Par défaut, il ne charge que le minimum pour économiser la RAM. Vous activez les fonctionnalités dont vous avez besoin :
| Module | Ce qu'il fait | Quand l'activer |
|---|---|---|
ssl | HTTPS | Dès que vous voulez du chiffrement |
rewrite | Réécriture d'URLs | WordPress, redirections, URLs propres |
proxy | Reverse proxy | Quand Apache est devant une app Node/Python |
headers | Modifier les headers HTTP | Sécurité, cache, CORS |
deflate | Compression gzip | Toujours (gain de bande passante) |
3. La différence Debian vs RHEL
Section intitulée « 3. La différence Debian vs RHEL »Question : "Pourquoi les tutos marchent jamais du premier coup ?"
Réponse : Parce que Debian et RHEL ont des conventions différentes :
| Aspect | Debian/Ubuntu | RHEL/Rocky/Fedora |
|---|---|---|
| Nom du paquet | apache2 | httpd |
| Nom du service | apache2 | httpd |
| Config principale | /etc/apache2/apache2.conf | /etc/httpd/conf/httpd.conf |
| Activer un site | a2ensite monsite.conf | Mettre le fichier dans /etc/httpd/conf.d/ |
| Activer un module | a2enmod ssl | Décommenter dans les fichiers .conf |
| User qui exécute Apache | www-data | apache |
Installation
Section intitulée « Installation »Le paquet et le service ne portent pas le même nom selon la famille de distribution : apache2 côté Debian, httpd côté RHEL. Choisissez l'onglet correspondant à votre système, sinon chaque commande échouera avec un « Unit not found » déroutant. L'installation par le gestionnaire de paquets de la distribution est la bonne méthode : elle apporte les unités systemd, l'utilisateur de service et l'arborescence de configuration déjà en place.
# Installer Apachesudo apt update && sudo apt install apache2
# Démarrer et activer au bootsudo systemctl enable --now apache2
# Vérifier le statutsudo systemctl status apache2# doit afficher : active (running)# Installer Apache (appelé httpd sur RHEL)sudo dnf install httpd
# Démarrer et activer au bootsudo systemctl enable --now httpd
# Vérifier le statutsudo systemctl status httpd# doit afficher : active (running)Vérification : ouvrez http://votre-ip dans un navigateur, vous devez voir la page par défaut d'Apache.
Ouvrir le pare-feu
Section intitulée « Ouvrir le pare-feu »Apache écoute sur le port 80 dès son démarrage, mais le pare-feu local filtre le trafic avant qu'il atteigne le processus. C'est la cause numéro un des « le service tourne mais le navigateur ne répond pas » depuis une autre machine : le test curl -I http://localhost passe (la boucle locale n'est pas filtrée) alors que l'accès distant échoue en timeout. Ouvrez les deux ports d'un coup, 80 pour le HTTP et 443 pour le HTTPS que vous activerez plus bas.
sudo ufw allow 'Apache Full'sudo ufw statussudo firewall-cmd --permanent --add-service=httpsudo firewall-cmd --permanent --add-service=httpssudo firewall-cmd --reloadServir un site statique
Section intitulée « Servir un site statique »Les quatre étapes suivantes produisent un site accessible sur un domaine dédié, sans toucher au vhost par défaut. L'ordre compte : le répertoire et son propriétaire d'abord, la configuration ensuite, l'activation en dernier. Si vous écrivez le Virtual Host avant de créer le DocumentRoot, apache2ctl configtest répondra tout de même « Syntax OK » puisqu'il ne vérifie pas l'existence des chemins, et vous récolterez une 403 à la première requête.
-
Créer le répertoire et les fichiers
Fenêtre de terminal sudo mkdir -p /var/www/monsiteecho '<h1>Mon site Apache</h1>' | sudo tee /var/www/monsite/index.html# Permissions : propriétaire = www-data (Debian) ou apache (RHEL)sudo chown -R www-data:www-data /var/www/monsite # Debian# sudo chown -R apache:apache /var/www/monsite # RHEL -
Créer le Virtual Host
Fenêtre de terminal sudo tee /etc/apache2/sites-available/monsite.conf << 'EOF'<VirtualHost *:80>ServerName monsite.localDocumentRoot /var/www/monsite<Directory /var/www/monsite>Options -Indexes +FollowSymLinksAllowOverride NoneRequire all granted</Directory>ErrorLog ${APACHE_LOG_DIR}/monsite-error.logCustomLog ${APACHE_LOG_DIR}/monsite-access.log combined</VirtualHost>EOFFenêtre de terminal sudo tee /etc/httpd/conf.d/monsite.conf << 'EOF'<VirtualHost *:80>ServerName monsite.localDocumentRoot /var/www/monsite<Directory /var/www/monsite>Options -Indexes +FollowSymLinksAllowOverride NoneRequire all granted</Directory>ErrorLog /var/log/httpd/monsite-error.logCustomLog /var/log/httpd/monsite-access.log combined</VirtualHost>EOF -
Activer le site et tester
Fenêtre de terminal # Activer le sitesudo a2ensite monsite.conf# Désactiver le site par défaut (optionnel)sudo a2dissite 000-default.conf# Tester la configurationsudo apache2ctl configtest# Syntax OK# Recharger Apachesudo systemctl reload apache2Fenêtre de terminal # Tester la configurationsudo httpd -t# Syntax OK# Recharger Apachesudo systemctl reload httpd -
Vérifier
Fenêtre de terminal curl -I http://localhost# HTTP/1.1 200 OK
Virtual Hosts multi-sites
Section intitulée « Virtual Hosts multi-sites »Apache peut héberger plusieurs sites sur la même machine grâce aux Name-based Virtual Hosts.
Pourquoi c'est possible ?
Section intitulée « Pourquoi c'est possible ? »Quand votre navigateur envoie une requête HTTP, il inclut un header Host: qui contient le domaine demandé :
GET /index.html HTTP/1.1Host: www.site1.com ← C'est ça qu'Apache utiliseUser-Agent: Mozilla/5.0...Apache lit cet en-tête et cherche le Virtual Host correspondant. Le protocole HTTP/1.1 rend le champ Host: obligatoire précisément pour cette raison : la couche TCP ne transporte qu'une adresse IP et un port, ce qui ne suffit pas à distinguer deux sites hébergés au même endroit. Le nom du domaine ne circule donc que dans l'en-tête applicatif, et c'est la seule information dont Apache dispose pour trancher.
Cas concret : 2 sites sur 1 serveur
Section intitulée « Cas concret : 2 sites sur 1 serveur »Imaginons que vous avez :
www.boutique.com→ votre e-commercewww.blog.com→ votre blog
Les deux domaines pointent vers la même IP (votre serveur). Comment Apache fait la différence ?
Configuration multi-sites
Section intitulée « Configuration multi-sites »Un site égale un fichier. Cette séparation n'est pas une coquetterie : elle permet d'activer ou de désactiver un site avec a2ensite / a2dissite sans toucher aux autres, et de repérer immédiatement quel fichier recharger après une modification. Dans les deux exemples ci-dessous, notez le couple ServerName / ServerAlias : le premier est le nom canonique, le second capte la variante sans www. Sans lui, site1.com tomberait sur le vhost par défaut au lieu du bon site. Les logs sont séparés par site, ce qui rend le diagnostic d'un site donné exploitable.
# /etc/apache2/sites-available/site1.conf (Debian)# ou /etc/httpd/conf.d/site1.conf (RHEL)
<VirtualHost *:80> ServerName www.site1.com ServerAlias site1.com DocumentRoot /var/www/site1
<Directory /var/www/site1> Options -Indexes +FollowSymLinks AllowOverride None Require all granted </Directory>
ErrorLog ${APACHE_LOG_DIR}/site1-error.log CustomLog ${APACHE_LOG_DIR}/site1-access.log combined</VirtualHost><VirtualHost *:80> ServerName www.site2.com ServerAlias site2.com DocumentRoot /var/www/site2
<Directory /var/www/site2> Options -Indexes +FollowSymLinks AllowOverride None Require all granted </Directory>
ErrorLog ${APACHE_LOG_DIR}/site2-error.log CustomLog ${APACHE_LOG_DIR}/site2-access.log combined</VirtualHost>Activer HTTPS avec Let's Encrypt
Section intitulée « Activer HTTPS avec Let's Encrypt »Pourquoi HTTPS est indispensable
Section intitulée « Pourquoi HTTPS est indispensable »La ligne qui compte vraiment dans le tableau est la première : sans TLS, tout ce qui transite (mots de passe, cookies de session, contenu des formulaires) est lisible par n'importe quel équipement traversé. Les autres lignes sont des conséquences. Google traite le HTTPS comme un signal de classement depuis 2014, et les navigateurs marquent désormais les pages en clair comme non sécurisées dès qu'un champ de saisie est présent. Let's Encrypt rend l'argument du coût caduc : le certificat est gratuit, valable 90 jours, et Certbot automatise le renouvellement.
| Sans HTTPS | Avec HTTPS |
|---|---|
| Données en clair sur le réseau | Tout est chiffré |
| Google pénalise votre SEO | Bonus de classement |
| Navigateurs affichent "Non sécurisé" | Cadenas vert |
| Vulnérable au man-in-the-middle | Communication sécurisée |
-
Installer Certbot
Fenêtre de terminal sudo apt install certbot python3-certbot-apacheFenêtre de terminal sudo dnf install epel-releasesudo dnf install certbot python3-certbot-apache -
Obtenir le certificat
Fenêtre de terminal sudo certbot --apache -d exemple.com -d www.exemple.comCertbot :
- Vérifie que vous contrôlez le domaine
- Obtient un certificat Let's Encrypt
- Modifie automatiquement votre Virtual Host
- Configure la redirection HTTP → HTTPS
-
Vérifier le renouvellement automatique
Fenêtre de terminal sudo certbot renew --dry-runLe timer systemd gère le renouvellement automatique (environ 30 jours avant expiration).
Configuration TLS sécurisée (production)
Section intitulée « Configuration TLS sécurisée (production) »Certbot produit une configuration fonctionnelle, pas une configuration durcie. Les directives ci-dessous ferment les protocoles obsolètes et ajoutent HSTS. Deux points méritent votre attention avant de copier ce bloc. D'abord SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1 : la syntaxe soustractive part de tout ce que la bibliothèque OpenSSL propose et retire les versions cassées, ce qui laisse TLS 1.2 et 1.3. Ensuite Strict-Transport-Security avec un max-age d'un an : cet en-tête indique au navigateur de ne plus jamais tenter le HTTP en clair sur ce domaine, et il est irréversible côté client pendant toute la durée annoncée. Ne l'activez qu'une fois le HTTPS confirmé fonctionnel, sinon vous rendez le site inaccessible aux visiteurs déjà venus.
<VirtualHost *:443> ServerName exemple.com DocumentRoot /var/www/exemple
SSLEngine On SSLCertificateFile /etc/letsencrypt/live/exemple.com/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/exemple.com/privkey.pem
# TLS moderne uniquement SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1 SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256 SSLHonorCipherOrder off
# HSTS (activer seulement quand HTTPS fonctionne) Header always set Strict-Transport-Security "max-age=31536000"
<Directory /var/www/exemple> Options -Indexes +FollowSymLinks AllowOverride None Require all granted </Directory></VirtualHost>
# Redirection HTTP → HTTPS<VirtualHost *:80> ServerName exemple.com Redirect permanent / https://exemple.com/</VirtualHost>Configurer un reverse proxy
Section intitulée « Configurer un reverse proxy »Qu'est-ce qu'un reverse proxy ?
Section intitulée « Qu'est-ce qu'un reverse proxy ? »Un reverse proxy est un intermédiaire entre les visiteurs et vos applications. Au lieu que votre app Node.js ou Python écoute directement sur le port 80, c'est Apache qui reçoit les requêtes et les transmet à votre app.
Pourquoi c'est une bonne idée ?
Section intitulée « Pourquoi c'est une bonne idée ? »Le tableau suivant part des questions que se posent réellement les développeurs au moment de mettre une application en ligne. Le fil conducteur est toujours le même : le port 80 et le port 443 sont des ports privilégiés, qu'un processus non root ne peut pas ouvrir sous Linux. Faire tourner une application Node.js ou Python en root pour y accéder est un risque inutile ; Apache démarre en root, ouvre les ports, puis abandonne ses privilèges vers www-data ou apache, et parle à votre application sur un port haut en loopback.
| Question | Réponse |
|---|---|
| "Mon app Node écoute sur 3000, comment la mettre sur le port 80 ?" | Le reverse proxy redirige 80 → 3000 |
| "Je veux du HTTPS mais mon framework ne le gère pas bien" | Apache gère TLS, votre app reste en HTTP local |
| "J'ai 3 apps sur un serveur, comment les exposer ?" | Un VHost par app, chacun proxyfie vers un port différent |
| "Je veux des logs Apache standardisés" | Le proxy loggue tout, votre app n'a pas à s'en occuper |
Tableau comparatif
Section intitulée « Tableau comparatif »Résumé des trois différences structurantes. La deuxième est celle qui a le plus d'impact sur votre travail quotidien : en déportant le TLS vers Apache, vous n'avez plus qu'un seul endroit où gérer les certificats, quel que soit le nombre d'applications derrière. Ce schéma porte le nom de terminaison TLS, et il implique que le trafic entre Apache et l'application circule en clair. C'est acceptable sur 127.0.0.1, pas entre deux machines distinctes.
| Sans reverse proxy | Avec reverse proxy (Apache) |
|---|---|
| Votre app écoute sur le port 80 | Apache écoute sur 80/443, votre app sur 3000 |
| Pas de HTTPS (ou config manuelle) | Apache gère TLS |
| Une seule app par serveur | Plusieurs apps sur le même serveur |
Activer les modules proxy
Section intitulée « Activer les modules proxy »Le proxy d'Apache se découpe en plusieurs modules qui se complètent. proxy apporte le socle, proxy_http ajoute le dialogue HTTP avec le backend, proxy_balancer et lbmethod_byrequests ne servent qu'à répartir la charge sur plusieurs backends. Pour une seule application, les deux premiers suffisent. Après activation, un httpd -M | grep proxy doit lister les modules chargés : si la sortie est vide, inutile de chercher plus loin dans la configuration, la directive ProxyPass sera simplement inconnue et configtest échouera.
sudo a2enmod proxy proxy_http proxy_balancer lbmethod_byrequestssudo systemctl restart apache2# Les modules sont généralement activés par défaut# Vérifier avec :httpd -M | grep proxyConfiguration reverse proxy
Section intitulée « Configuration reverse proxy »Trois directives portent tout le comportement. ProxyPass envoie les requêtes vers le backend ; ProxyPassReverse fait le trajet inverse en réécrivant les en-têtes Location, Content-Location et URI des réponses, sans quoi une redirection émise par l'application renverrait le navigateur vers http://127.0.0.1:3000/, une adresse qui n'existe pas chez le visiteur. ProxyPreserveHost On transmet le Host: d'origine au lieu de le remplacer par celui de la cible, ce dont dépendent la plupart des frameworks pour construire leurs URL absolues.
<VirtualHost *:80> ServerName api.exemple.com
ProxyPreserveHost On ProxyPass / http://127.0.0.1:3000/ ProxyPassReverse / http://127.0.0.1:3000/
# mod_proxy_http ajoute déjà X-Forwarded-For, X-Forwarded-Host # et X-Forwarded-Server (ProxyAddHeaders est On par défaut). # Seul le protocole d'origine reste à déclarer : RequestHeader set X-Forwarded-Proto "http"
ErrorLog ${APACHE_LOG_DIR}/api-error.log CustomLog ${APACHE_LOG_DIR}/api-access.log combined</VirtualHost>N'écrivez pas de X-Real-IP à la main : mod_proxy_http renseigne déjà X-Forwarded-For avec l'IP du client, ainsi que X-Forwarded-Host et X-Forwarded-Server, tant que ProxyAddHeaders reste à sa valeur par défaut On. En revanche X-Forwarded-Proto n'est pas ajouté automatiquement : c'est à vous de le poser, avec la valeur http dans un vhost sur le port 80 et https dans le vhost sur le port 443. Une valeur figée à http recopiée dans le vhost TLS fait générer des liens en clair par l'application et déclenche des boucles de redirection.
Reverse proxy avec chemin spécifique
Section intitulée « Reverse proxy avec chemin spécifique »Le cas le plus fréquent en production : un front statique servi par Apache et une API proxyfiée sous un préfixe. Surveillez les barres obliques finales, elles ne sont pas décoratives. Avec ProxyPass /api/ http://127.0.0.1:3000/, une requête sur /api/clients arrive au backend en /clients : le préfixe est retiré. Si votre application attend au contraire de recevoir /api/clients, la cible doit s'écrire http://127.0.0.1:3000/api/. Mélanger une source avec barre finale et une cible sans barre produit des chemins concaténés de travers et des 404 côté backend alors qu'Apache, lui, répond correctement.
<VirtualHost *:80> ServerName exemple.com DocumentRoot /var/www/frontend
# L'API sur /api/* ProxyPass /api/ http://127.0.0.1:3000/ ProxyPassReverse /api/ http://127.0.0.1:3000/
# Le reste en statique <Directory /var/www/frontend> Options -Indexes +FollowSymLinks AllowOverride None Require all granted </Directory></VirtualHost>Optimisation des performances
Section intitulée « Optimisation des performances »Choisir le bon MPM
Section intitulée « Choisir le bon MPM »MPM signifie Multi-Processing Module. C'est la façon dont Apache gère les requêtes en parallèle.
Question fréquente : "Pourquoi Apache est lent / consomme trop de RAM ?"
Réponse courte : Vous utilisez probablement le mauvais MPM.
Les 3 MPM expliqués simplement
Section intitulée « Les 3 MPM expliqués simplement »Un seul MPM est actif à la fois, il se choisit au chargement des modules et impose un redémarrage complet pour en changer (systemctl reload ne suffit pas). La colonne de droite décrit le modèle d'exécution, et c'est lui qui détermine la consommation mémoire : prefork duplique un processus entier par connexion simultanée, là où worker et event partagent un processus entre plusieurs threads. Sur les distributions récentes, event est le MPM installé par défaut.
| MPM | Comment ça marche |
|---|---|
| prefork | 1 processus par requête. Simple mais gourmand en RAM. |
| worker | Processus + threads. Plus efficace. |
| event | Comme worker, mais gère mieux les connexions keepalive. |
Prefork et event côte à côte
Section intitulée « Prefork et event côte à côte »Le schéma compare les deux extrêmes. À gauche, prefork : chaque connexion mobilise un processus complet, avec sa propre copie de la mémoire, ce qui plafonne vite le nombre de clients simultanés sur une machine modeste. À droite, event : un petit nombre de processus héberge des threads, et un thread dédié conserve les connexions keep-alive inactives sans immobiliser de worker. C'est ce dernier point qui fait la différence sur un site réel, où la majorité des connexions ouvertes ne transportent aucune donnée à un instant donné.
Quel MPM choisir ?
Section intitulée « Quel MPM choisir ? »La décision se prend en une question : est-ce que quelque chose dans votre pile impose des processus séparés ? Une seule réponse le fait vraiment, mod_php, dont les extensions ne sont pas toutes sûres en environnement multithread. Dans tous les autres cas, y compris PHP-FPM qui exécute PHP hors d'Apache, event est le bon choix. La colonne « Pourquoi » donne le critère technique à vérifier chez vous plutôt qu'une règle à appliquer aveuglément.
| Situation | MPM recommandé | Pourquoi |
|---|---|---|
| PHP avec mod_php | prefork | mod_php n'est pas thread-safe |
| PHP-FPM / proxy_fcgi | event | Meilleure gestion des connexions |
| Reverse proxy | event | Gère mieux les connexions keepalive |
| Beaucoup de connexions | event | Plus efficace en mémoire |
| Compatibilité maximale | prefork | Fonctionne avec tout |
Activer le MPM event
Section intitulée « Activer le MPM event »Sur Debian 12 et Ubuntu récents, mpm_event est déjà le MPM par défaut : apache2ctl -V | grep MPM le confirme avant toute manipulation. La bascule ci-dessous ne concerne donc que les serveurs passés à prefork par une installation de libapache2-mod-php. Un point de vigilance : les deux MPM sont mutuellement exclusifs, il faut désactiver l'ancien avant d'activer le nouveau, sinon a2enmod refuse l'opération. Et le changement exige un restart, pas un reload.
# Désactiver prefork, activer eventsudo a2dismod mpm_preforksudo a2enmod mpm_eventsudo systemctl restart apache2# Éditer /etc/httpd/conf.modules.d/00-mpm.conf# Commenter LoadModule mpm_prefork_module# Décommenter LoadModule mpm_event_modulesudo systemctl restart httpdCompression (mod_deflate)
Section intitulée « Compression (mod_deflate) »La compression gzip s'applique à la volée aux réponses textuelles et réduit typiquement leur taille de 60 à 80 %, ce qui se voit surtout sur les gros fichiers CSS et JavaScript. La sélection se fait par type MIME et pas par extension : c'est l'en-tête Content-Type de la réponse qui décide. N'ajoutez jamais les images JPEG, PNG ou WebP à cette liste, elles sont déjà compressées et le passage par mod_deflate consomme du CPU pour un gain nul, voire négatif. Vérification après rechargement : curl -sI -H 'Accept-Encoding: gzip' https://exemple.com/style.css doit afficher Content-Encoding: gzip.
<IfModule mod_deflate.c> AddOutputFilterByType DEFLATE text/html text/plain text/xml AddOutputFilterByType DEFLATE text/css application/javascript AddOutputFilterByType DEFLATE application/json application/xml</IfModule>sudo a2enmod deflatesudo systemctl restart apache2# Généralement activé par défauthttpd -M | grep deflateHeaders de cache
Section intitulée « Headers de cache »mod_expires ajoute un en-tête Cache-Control: max-age aux réponses, ce qui autorise le navigateur à réutiliser un fichier sans réinterroger le serveur. Les durées ci-dessous sont volontairement asymétriques : un an pour les images, qui changent rarement, un mois pour le CSS et le JavaScript, plus souvent retouchés. Le piège arrive à la mise en production suivante : un visiteur qui a déjà le fichier en cache ne verra pas votre correction avant l'expiration. La parade standard consiste à faire varier le nom du fichier à chaque build (app.4f2c1a.css), technique que la plupart des outils de packaging appliquent d'office.
<IfModule mod_expires.c> ExpiresActive On ExpiresByType image/jpeg "access plus 1 year" ExpiresByType image/png "access plus 1 year" ExpiresByType text/css "access plus 1 month" ExpiresByType application/javascript "access plus 1 month"</IfModule>Sécurisation (production)
Section intitulée « Sécurisation (production) »Configuration minimale sécurisée
Section intitulée « Configuration minimale sécurisée »Ce bloc regroupe le strict nécessaire, à poser une fois pour toutes au niveau global. ServerTokens Prod réduit l'en-tête Server: au seul mot Apache, sans numéro de version : cela ne bloque aucune attaque mais retire de la liste des cibles faciles des scanners qui filtrent par version. Les trois en-têtes de sécurité protègent les visiteurs, pas le serveur : nosniff empêche le navigateur de deviner un type MIME et d'exécuter comme script un fichier téléversé, SAMEORIGIN bloque l'inclusion de vos pages dans une iframe tierce, Referrer-Policy limite la fuite d'URL vers les sites externes. Le mot-clé always est indispensable : sans lui, les en-têtes disparaissent des réponses d'erreur, précisément celles qu'un attaquant cherche à provoquer.
# Dans /etc/apache2/conf-available/security.conf (Debian)# ou /etc/httpd/conf.d/security.conf (RHEL)
# Masquer la version d'ApacheServerTokens ProdServerSignature Off
# Headers de sécurité<IfModule mod_headers.c> Header always set X-Content-Type-Options "nosniff" Header always set X-Frame-Options "SAMEORIGIN" Header always set Referrer-Policy "strict-origin-when-cross-origin"</IfModule>
# Désactiver le listing des répertoires (global)<Directory /> Options -Indexes</Directory>sudo a2enmod headerssudo a2enconf securitysudo systemctl restart apache2# Créer le fichier puis :sudo systemctl restart httpdLimiter les méthodes HTTP
Section intitulée « Limiter les méthodes HTTP »Un site statique n'a besoin que de trois méthodes HTTP. Tout le reste (PUT, DELETE, TRACE, les verbes WebDAV) n'a aucune raison d'être accepté et constitue une surface d'attaque gratuite. La directive <LimitExcept> applique la restriction à toutes les méthodes sauf celles qu'elle énumère, ce qui la rend robuste : une méthode exotique ajoutée par un futur module reste refusée sans que vous ayez à mettre la liste à jour. C'est l'inverse de <Limit>, qui n'agit que sur les verbes explicitement nommés et laisse passer tous les autres : une liste noire oubliée reste ouverte, une liste blanche non.
<Directory /var/www/monsite> <LimitExcept GET POST HEAD> Require all denied </LimitExcept></Directory>Dépannage express
Section intitulée « Dépannage express »La méthode de diagnostic (toujours la même)
Section intitulée « La méthode de diagnostic (toujours la même) »Quand Apache ne fonctionne pas, suivez toujours cet ordre. 90% des problèmes se résolvent en moins de 2 minutes :
Tester la configuration avant de recharger
Section intitulée « Tester la configuration avant de recharger »Toujours tester la configuration avant de recharger :
# Debian/Ubuntusudo apache2ctl configtest
# RHEL/Rockysudo httpd -tPourquoi ? Contrairement à une idée répandue, un systemctl reload sur une configuration cassée ne tue pas le serveur : la commande se traduit par apachectl graceful, qui lance un contrôle de syntaxe avant d'envoyer le signal et refuse le rechargement si la configuration est invalide. Le processus continue de tourner avec l'ancienne configuration, et vous ne voyez rien passer côté visiteurs.
Le vrai danger est le systemctl restart, qui arrête le processus avant de le relancer : si la configuration est fautive, le redémarrage échoue et le site est hors ligne jusqu'à correction. D'où le réflexe : configtest d'abord, action ensuite. Le test rend en prime la ligne et le fichier exacts de l'erreur, ce que le journal systemd ne montre pas toujours.
Diagnostic en 30 secondes
Section intitulée « Diagnostic en 30 secondes »Enchaînez ces cinq commandes dans l'ordre, elles vont du plus général au plus précis. La cinquième, apache2ctl -S, est la plus sous-estimée : elle affiche la table complète des Virtual Hosts telle qu'Apache l'a réellement construite, avec pour chaque domaine le fichier et la ligne d'origine. C'est le seul moyen fiable de voir qu'un vhost oublié capte le trafic à la place du vôtre, ou qu'un ServerName est en double. Gardez la sortie sous les yeux avant de modifier quoi que ce soit.
# 1. Apache tourne-t-il ?systemctl status apache2 # ou httpd
# 2. La config est-elle valide ?sudo apache2ctl configtest # ou httpd -t
# 3. Quels modules sont actifs ?apache2ctl -M # ou httpd -M
# 4. Logs d'erreur récentssudo tail -20 /var/log/apache2/error.log # Debiansudo tail -20 /var/log/httpd/error_log # RHEL
# 5. Quel Virtual Host répond ?sudo apache2ctl -S # ou httpd -SErreurs courantes et solutions
Section intitulée « Erreurs courantes et solutions »Erreur 403 Forbidden
Section intitulée « Erreur 403 Forbidden »Ce que ça veut dire : Apache a trouvé le fichier, mais refuse de le servir.
Causes possibles (dans l'ordre de fréquence) :
-
Permissions fichiers : Apache (user
www-dataouapache) ne peut pas lire le fichierFenêtre de terminal # Vérifierls -la /var/www/monsite/# Corrigersudo chown -R www-data:www-data /var/www/monsite # Debiansudo chmod -R 755 /var/www/monsite -
Directive
Require all denieddans la config (ou absence deRequire all granted) -
SELinux (RHEL/Rocky) bloque l'accès
Fenêtre de terminal # Vérifiergetenforce# Si "Enforcing", corriger les contextes :sudo restorecon -Rv /var/www/monsite
Erreur 404 Not Found
Section intitulée « Erreur 404 Not Found »Ce que ça veut dire : Apache ne trouve pas le fichier demandé.
Causes possibles :
- DocumentRoot incorrect : le dossier dans le VHost ne correspond pas à la réalité
- Fichier absent :
index.htmln'existe pas - Typo dans l'URL :
/inex.htmlau lieu de/index.html
# Vérifier que le fichier existe vraimentls -la /var/www/monsite/index.htmlErreur 500 Internal Server Error
Section intitulée « Erreur 500 Internal Server Error »Ce que ça veut dire : Apache a planté en essayant de répondre.
Causes possibles :
- Erreur dans
.htaccess: syntaxe invalide, module manquant - Script PHP/Python qui plante
Solution : Toujours regarder le log d'erreur :
sudo tail -30 /var/log/apache2/error.log"It works" mais pas mon site
Section intitulée « "It works" mais pas mon site »Ce que ça veut dire : Apache affiche la page par défaut au lieu de votre site.
Causes possibles :
- VHost non activé :
a2ensite monsite.confoublié - ServerName incorrect : ne correspond pas au domaine demandé
# Voir quel VHost répond pour quel domaineapache2ctl -STableau récapitulatif
Section intitulée « Tableau récapitulatif »À garder sous la main pendant une astreinte. La dernière ligne mérite une précision : AH00558 n'est pas une erreur mais un avertissement au démarrage, émis quand aucun ServerName global n'est défini. Apache démarre malgré tout en devinant un nom à partir de l'adresse IP. Il vaut mieux le faire taire en posant un ServerName explicite, sinon ce message parasite chaque lecture du journal et masque les vraies erreurs.
| Erreur | Cause probable | Solution |
|---|---|---|
| 403 Forbidden | Permissions ou Require all denied | Voir ci-dessus |
| 404 Not Found | DocumentRoot ou fichier absent | Vérifier le chemin |
| 500 Internal Server Error | .htaccess ou script cassé | Regarder error.log |
| "It works" | VHost non activé | a2ensite + apache2ctl -S |
| AH00558: Could not reliably... | ServerName global absent | Ajouter ServerName localhost |
Déboguer un 403
Section intitulée « Déboguer un 403 »Une 403 vient de l'une de trois couches, à éliminer dans cet ordre parce que la première est la plus fréquente et la plus rapide à vérifier. Détail que beaucoup ratent : Apache a besoin du droit de traversée (x) sur tous les répertoires parents, pas seulement sur le fichier. Un /var/www/monsite en 750 appartenant à votre compte utilisateur renverra une 403 même si index.html est en 644.
# 1. Vérifier les permissions, y compris celles des dossiers parentsnamei -l /var/www/monsite/index.html# Le user www-data (ou apache) doit pouvoir traverser chaque niveau
# 2. Vérifier la config Directorygrep -A5 "Directory /var/www/monsite" /etc/apache2/sites-enabled/*
# 3. SELinux (RHEL) ?getenforce# Si "Enforcing", relire les refus plutôt que désactiver :sudo ausearch -m avc -ts recent# Puis corriger les contextes :sudo restorecon -Rv /var/www/monsiteAide-mémoire
Section intitulée « Aide-mémoire »Les quatre tableaux qui suivent sont faits pour être consultés en cours de manipulation, pas lus d'affilée. La séparation par famille de distribution est volontaire : les commandes a2* sont des scripts fournis par Debian, absents de RHEL, où l'activation d'un site ou d'un module passe par le placement d'un fichier ou l'édition d'un LoadModule.
Debian/Ubuntu
Section intitulée « Debian/Ubuntu »Ces sept commandes couvrent l'essentiel du quotidien. Toutes les commandes a2* se contentent de gérer des liens symboliques entre sites-available et sites-enabled (idem pour les modules), ce qui explique qu'elles réclament ensuite un reload pour prendre effet : elles ne parlent jamais au processus Apache.
| Commande | Description |
|---|---|
a2ensite monsite.conf | Activer un site |
a2dissite monsite.conf | Désactiver un site |
a2enmod rewrite | Activer un module |
a2dismod rewrite | Désactiver un module |
apache2ctl configtest | Tester la configuration |
apache2ctl -M | Lister les modules actifs |
apache2ctl -S | Lister les Virtual Hosts |
RHEL/Rocky
Section intitulée « RHEL/Rocky »Côté RHEL, il n'y a pas d'outillage d'activation : c'est le binaire httpd lui-même qui rend ces services, avec les mêmes options que apache2ctl. Notez qu'il n'existe pas d'équivalent à a2ensite : tout fichier .conf déposé dans /etc/httpd/conf.d/ est chargé au prochain démarrage, sans étape supplémentaire. Désactiver un site revient donc à renommer ou déplacer son fichier.
| Commande | Description |
|---|---|
httpd -t | Tester la configuration |
httpd -M | Lister les modules actifs |
httpd -S | Lister les Virtual Hosts |
Chemins importants
Section intitulée « Chemins importants »La ligne à mémoriser est celle des logs, parce que c'est là que vous irez à chaque incident. Attention au nom du fichier, il diffère : error.log avec un point sur Debian, error_log avec un tiret bas sur RHEL. Un tail qui répond « No such file or directory » sur un serveur qui tourne vient presque toujours de cette confusion.
| Élément | Debian/Ubuntu | RHEL/Rocky |
|---|---|---|
| Config principale | /etc/apache2/apache2.conf | /etc/httpd/conf/httpd.conf |
| Sites disponibles | /etc/apache2/sites-available/ | - |
| Sites activés | /etc/apache2/sites-enabled/ | /etc/httpd/conf.d/ |
| Modules | /etc/apache2/mods-available/ | /etc/httpd/conf.modules.d/ |
| Logs | /var/log/apache2/ | /var/log/httpd/ |
| DocumentRoot par défaut | /var/www/html | /var/www/html |
Directives essentielles
Section intitulée « Directives essentielles »Six directives suffisent à écrire un Virtual Host correct. Deux d'entre elles se placent à l'intérieur d'un bloc <Directory> et nulle part ailleurs, Options et AllowOverride ; les autres vivent au niveau du <VirtualHost>. Se tromper de niveau produit soit un « Syntax OK » suivi d'un comportement inattendu, soit une erreur explicite de contexte au configtest.
| Directive | Description |
|---|---|
ServerName www.exemple.com | Nom du site |
ServerAlias exemple.com | Alias (sans www) |
DocumentRoot /var/www/site | Racine des fichiers |
Options -Indexes | Désactiver le listing |
AllowOverride None | Ignorer les .htaccess |
Require all granted | Autoriser l'accès |
Pièges à éviter
Section intitulée « Pièges à éviter »Ces six erreurs représentent l'essentiel des tickets ouverts sur des serveurs Apache mal réglés. Les deux dernières lignes sont les plus coûteuses en temps parce qu'elles ne produisent aucun message clair : SELinux renvoie une 403 identique à celle d'un problème de permissions, et l'association mod_php avec le MPM event provoque des plantages intermittents impossibles à reproduire à la demande. Prenez le réflexe de vérifier getenforce et apache2ctl -M | grep php avant d'entamer une recherche longue.
| Erreur | Conséquence | Solution |
|---|---|---|
AllowOverride All partout | Perf dégradée, sécurité réduite | AllowOverride None + config centrale |
Oublier a2enmod ssl | HTTPS ne fonctionne pas | Activer le module avant Certbot |
| Permissions 777 | Faille de sécurité majeure | 755 pour dossiers, 644 pour fichiers |
| Confondre Debian et RHEL | Chemins et commandes différents | Vérifier la distribution |
| SELinux non configuré | 403 mystérieux sur RHEL | setsebool -P httpd_can_network_connect 1 |
| mod_php + MPM event | Crash ou comportement erratique | Utiliser prefork avec mod_php |
À retenir
Section intitulée « À retenir »apache2ctl configtest: toujours tester avant de recharger- Virtual Host = un site, avec son
ServerNameetDocumentRoot AllowOverride None: la règle en production- MPM event : pour les perfs (sauf mod_php)
- Certbot : HTTPS en une commande
- Logs : votre meilleur ami pour débugger
Prochaines étapes
Section intitulée « Prochaines étapes »Ressources
Section intitulée « Ressources »- Documentation officielle : httpd.apache.org/docs/
- Modules Apache : httpd.apache.org/docs/current/mod/
- Mozilla SSL Config : ssl-config.mozilla.org
- GitHub : github.com/apache/httpd
FAQ - Questions Fréquemment Posées
Section intitulée « FAQ - Questions Fréquemment Posées »Définition
Apache HTTP Server est un serveur web open-source créé en 1995 par la fondation Apache Software Foundation. C'est le serveur web historique du Web.Fonctions principales
| Fonction | Description |
|---|---|
| Fichiers statiques | Sert HTML, CSS, JS, images |
| Virtual Hosts | Héberge plusieurs sites sur une machine |
| HTTPS | Chiffrement TLS via mod_ssl |
| Reverse proxy | Transmet requêtes vers backend |
| Modules | Fonctionnalités activables à la demande |
Installation
# Installer Apache
sudo apt update && sudo apt install apache2
# Démarrer et activer au boot
sudo systemctl enable --now apache2
# Vérifier le statut
sudo systemctl status apache2
Ouvrir le pare-feu
sudo ufw allow 'Apache Full'
sudo ufw status
Vérification
Ouvrezhttp://votre-ip dans un navigateur. Vous devez voir la page par défaut d'Apache.Fichiers importants
| Fichier | Description |
|---|---|
/etc/apache2/apache2.conf |
Config principale |
/etc/apache2/sites-available/ |
Sites disponibles |
/etc/apache2/sites-enabled/ |
Sites activés |
/var/log/apache2/ |
Logs |
Installation
# Installer Apache (appelé httpd sur RHEL)
sudo dnf install httpd
# Démarrer et activer au boot
sudo systemctl enable --now httpd
# Vérifier le statut
sudo systemctl status httpd
Ouvrir le pare-feu
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
Différences avec Debian
| Aspect | Debian/Ubuntu | RHEL/Rocky |
|---|---|---|
| Paquet | apache2 |
httpd |
| Service | apache2 |
httpd |
| Config | /etc/apache2/ |
/etc/httpd/ |
| User | www-data |
apache |
Définition
Un Virtual Host permet d'héberger plusieurs sites sur une seule instance Apache. Chaque VHost a sa propre configuration.Configuration minimale
<VirtualHost *:80>
ServerName www.exemple.com
DocumentRoot /var/www/exemple
<Directory /var/www/exemple>
Options -Indexes +FollowSymLinks
AllowOverride None
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/exemple-error.log
CustomLog ${APACHE_LOG_DIR}/exemple-access.log combined
</VirtualHost>
Activer le site (Debian)
sudo a2ensite exemple.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
Comment Apache choisit le bon site
Quand une requête arrive, Apache compare le headerHost: avec les ServerName de chaque Virtual Host. Le premier qui matche gagne.Commandes Debian/Ubuntu
| Commande | Action |
|---|---|
a2ensite exemple.conf |
Activer un site |
a2dissite exemple.conf |
Désactiver un site |
a2enmod ssl |
Activer un module |
a2dismod ssl |
Désactiver un module |
Fonctionnement
Ces commandes créent des liens symboliques :- Sites :
sites-available/→sites-enabled/ - Modules :
mods-available/→mods-enabled/
Sur RHEL/Rocky
Ces commandes n'existent pas. À la place :- Sites : placer directement dans
/etc/httpd/conf.d/ - Modules : décommenter dans les fichiers
.conf
Toujours tester avant de recharger
sudo apache2ctl configtest # Debian
sudo httpd -t # RHEL
Installation de Certbot
# Debian/Ubuntu
sudo apt install certbot python3-certbot-apache
# RHEL/Rocky
sudo dnf install epel-release
sudo dnf install certbot python3-certbot-apache
Obtenir le certificat
sudo certbot --apache -d exemple.com -d www.exemple.com
Certbot automatiquement :- Vérifie que vous contrôlez le domaine
- Obtient un certificat Let's Encrypt
- Modifie le Virtual Host
- Configure la redirection HTTP → HTTPS
Vérifier le renouvellement
sudo certbot renew --dry-run
Prérequis
| Condition | Pourquoi |
|---|---|
| DNS pointe vers le serveur | Let's Encrypt vérifie |
| Ports 80/443 ouverts | Challenge HTTP |
Activer les modules
# Debian/Ubuntu
sudo a2enmod proxy proxy_http
sudo systemctl restart apache2
Configuration
<VirtualHost *:80>
ServerName api.exemple.com
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/
# Headers pour le backend
RequestHeader set X-Forwarded-Proto "http"
RequestHeader set X-Real-IP "%{REMOTE_ADDR}s"
</VirtualHost>
Avantages du reverse proxy
| Sans proxy | Avec proxy |
|---|---|
| App sur port 80 | Apache sur 80/443, app sur 3000 |
| Pas de HTTPS | Apache gère TLS |
| Une app/serveur | Plusieurs apps |
SELinux (RHEL)
sudo setsebool -P httpd_can_network_connect 1
Les 3 MPM expliqués
| MPM | Usage |
|---|---|
| prefork | PHP mod_php |
| worker | Apps threadsafe |
| event | Reverse proxy, PHP-FPM |
Consommation mémoire
prefork : 100 requêtes = 100 processus = 3 Go RAM
event : 100 requêtes = quelques processus = 200 Mo RAM
Quel MPM choisir ?
| Situation | MPM |
|---|---|
| PHP mod_php | prefork (obligatoire) |
| PHP-FPM | event |
| Reverse proxy | event |
| Beaucoup de connexions | event |
Changer de MPM (Debian)
sudo a2dismod mpm_prefork
sudo a2enmod mpm_event
sudo systemctl restart apache2
Causes et solutions
| Cause | Solution |
|---|---|
| Permissions fichiers | chown -R www-data:www-data /var/www/site |
Require all denied |
Ajouter Require all granted |
| SELinux (RHEL) | restorecon -Rv /var/www/site |
Diagnostic
# 1. Vérifier les permissions
ls -la /var/www/monsite/
# 2. Vérifier la config Directory
grep -A5 "Directory /var/www/monsite" /etc/apache2/sites-enabled/*
# 3. Regarder les logs
sudo tail -30 /var/log/apache2/error.log
SELinux (RHEL/Rocky)
# Vérifier si SELinux bloque
getenforce
# Tester temporairement
sudo setenforce 0
# Corriger les contextes
sudo restorecon -Rv /var/www/monsite
Commandes de diagnostic
| Action | Debian | RHEL |
|---|---|---|
| Tester config | apache2ctl configtest |
httpd -t |
| Lister modules | apache2ctl -M |
httpd -M |
| Lister VHosts | apache2ctl -S |
httpd -S |
Workflow sécurisé
# 1. Modifier la configuration
sudo nano /etc/apache2/sites-available/monsite.conf
# 2. TOUJOURS tester avant
sudo apache2ctl configtest
# Syntax OK
# 3. Recharger (sans interruption)
sudo systemctl reload apache2
Pourquoi tester avant ?
Si la config a une erreur de syntaxe et que vous faitesreload, Apache peut planter. En testant avant, vous évitez de casser un serveur en production.Définition
AllowOverride définit si Apache lit les fichiers .htaccess dans les répertoires.Options
| Valeur | Comportement |
|---|---|
None |
Ignore tous les .htaccess |
All |
Active toutes les directives .htaccess |
FileInfo |
Uniquement directives de fichiers |
Pourquoi None en production ?
| AllowOverride All | AllowOverride None |
|---|---|
| Apache cherche .htaccess à chaque requête | Pas de recherche = plus rapide |
| Config distribuée | Config centralisée |
| Risques de sécurité | Gouvernance maîtrisée |
Recommandation
<Directory /var/www/monsite>
AllowOverride None # Production
# AllowOverride All # Uniquement si WordPress/CMS l'exige
</Directory>
Activer le module
# Debian/Ubuntu
sudo a2enmod deflate
sudo systemctl restart apache2
# RHEL (généralement activé par défaut)
httpd -M | grep deflate
Configuration
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/plain text/xml
AddOutputFilterByType DEFLATE text/css application/javascript
AddOutputFilterByType DEFLATE application/json application/xml
</IfModule>
Gains
| Type | Compression |
|---|---|
| HTML | 60-70% |
| CSS | 70-80% |
| JavaScript | 60-70% |
| JSON | 70-80% |
Vérifier
curl -H "Accept-Encoding: gzip" -I https://exemple.com
# Chercher : Content-Encoding: gzip