molitor.photography

VirtualHost Apache 2.4 : héberger plusieurs sites sur un seul serveur

2026-11-13

Héberger plusieurs sites sur une seule machine, c'est l'un des premiers gestes qu'on fait quand on administre Apache. Et c'est aussi l'un des premiers endroits où l'on se casse les dents. Un site qui s'affiche à la place d'un autre, un domaine qui répond par erreur sur la mauvaise page, une configuration qui « marche en local mais pas en production » : ces symptômes viennent presque toujours de la même chose. Les VirtualHost. Comprendre comment Apache choisit le bon site, et comment structurer sa configuration, c'est gagner des heures de débogage et se donner une base saine pour la suite. Une fois qu'on a compris la logique, tout devient plus simple : ajouter un site prend cinq minutes, et les migrations ne font plus peur.

Dans cet article, je vais vous montrer une configuration complète, avec les cas concrets, les erreurs classiques et les outils de diagnostic. L'objectif n'est pas de réciter la documentation, mais de vous donner un modèle que vous pouvez adapter et déployer avec confiance, en 2026, avec Apache 2.4 et les pratiques actuelles.

Pourquoi les VirtualHost sont la brique de base de tout hébergement

Un serveur Apache écoute sur un port, par exemple 80. Quand une requête arrive, il lit l'en-tête Host pour savoir quel site servir. Le VirtualHost, c'est la déclaration qui associe un nom de domaine à un répertoire. Sans VirtualHost, Apache sert un seul site, défini par le DocumentRoot global. Avec VirtualHost, il peut servir des dizaines, des centaines de sites, sans que ceux-ci se marchent dessus.

Ce que fait réellement un serveur virtuel

Un VirtualHost n'est pas une machine virtuelle, et ce n'est pas un conteneur. C'est un bloc de configuration qui dit : « quand le Host reçu est example.com, sers le contenu du répertoire /var/www/example.com, avec ces règles ». Apache peut ainsi avoir plusieurs sites avec des configurations distinctes, des certificats différents, des restrictions d'accès propres. Chaque site est indépendant, comme s'il avait son propre serveur, alors qu'il partage le même processus et le même port.

Name-based, IP-based et wildcard : trois approches

Il existe plusieurs façons de déclarer un VirtualHost. Le choix dépend de votre contexte.

Type Principe Quand l'utiliser
Name-based Un seul IP, plusieurs domaines distingués par l'en-tête Host Cas le plus courant, il suffit d'un seul IP
IP-based Un IP par site, ou une adresse par domaine Sites nécessitant des certificats distincts sans SNI, ou des contraintes réseau spécifiques
Wildcard Un VirtualHost qui répond pour tous les domaines Configuration de repli, captures génériques

Le name-based est de loin le plus courant, car il ne demande qu'une seule adresse IP. En 2.4, il n'y a plus besoin de NameVirtualHost : Apache détecte automatiquement le mode si plusieurs blocs existent sur le même port. C'est une simplification par rapport à la 2.2, et cela réduit les erreurs de configuration.

Le squelette d'un VirtualHost qui fonctionne

Voici un modèle minimum, qui couvre la majorité des cas. Chaque bloc est important, y compris ceux qu'on oublie souvent. Prenons l'exemple d'un site example.com.

ServerName et ServerAlias : dire à Apache pour qui il répond

ServerName indique le nom de domaine principal. ServerAlias ajoute les variantes, comme www.example.com. Sans ServerAlias, une requête sur www.example.com risque d'être servie par le VirtualHost par défaut, ce qui donne un site incohérent. La bonne pratique consiste à déclarer les deux.

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com/public
</VirtualHost>

DocumentRoot et le piège du slash final

DocumentRoot pointe vers le répertoire racine du site. Pas de slash final, car Apache ajoute déjà les séparateurs. Un slash final peut produire des chemins doubles ou des comportements inattendus selon les directives. Vérifiez aussi les permissions : l'utilisateur Apache doit pouvoir traverser tous les répertoires parents, sinon l'accès est refusé. C'est une erreur classique, qui produit un 403 mystérieux.

Les blocs Directory et Require associés

Un VirtualHost sans bloc <Directory> peut fonctionner, mais il vaut mieux en déclarer un, pour fixer les permissions. En 2.4, une configuration typique :

<Directory /var/www/example.com/public>
    Options -Indexes +FollowSymLinks
    AllowOverride All
    Require all granted
</Directory>

Options -Indexes empêche le listing de répertoire, ce qui est une bonne pratique de sécurité. AllowOverride All autorise les fichiers .htaccess, utile pour un CMS. Si vous contrôlez entièrement la configuration, réduisez plutôt à AllowOverride FileInfo ou None, selon les besoins.

Les fichiers de log par site

Il est très utile de déclarer des logs par VirtualHost, pour analyser un site indépendamment des autres. La configuration :

CustomLog /var/log/apache2/example.com.access.log combined
ErrorLog /var/log/apache2/example.com.error.log

Cette séparation facilite le diagnostic, la rotation et l'analyse. Sur un serveur avec plusieurs sites, ne pas le faire revient à chercher une aiguille dans une botte de foin. Prenez l'habitude de déclarer ces deux directives pour chaque site.

Comprendre la sélection : comment Apache choisit le bon site

La sélection du VirtualHost n'est pas magique, et la comprendre évite bien des maux de tête. Apache parcourt les blocs dans l'ordre de la configuration, en appliquant des règles précises. Le premier bloc qui correspond gagne, ou plutôt le plus spécifique, selon la nature de la correspondance.

L'ordre des blocs et le VirtualHost par défaut

Le premier VirtualHost déclaré pour un port donné devient le VirtualHost par défaut. Cela signifie que si une requête ne correspond à aucun autre bloc, elle est servie par ce premier bloc. C'est une source d'erreur fréquente : on croit avoir un site « invisible », alors qu'il est servi par défaut à la place de toutes les URL inconnues. Un test avec curl -H "Host: un-domaine-inexistant" montre quel site répond. Le résultat est souvent instructif.

L'algorithme expliqué par un cas concret

Imaginez trois VirtualHost : example.com, www.example.com et un wildcard *. Une requête sur www.example.com matche le deuxième. Une requête sur foo.example.com matche le wildcard. Une requête sur other.com matcherait aussi le wildcard, ou le premier bloc si les deux n'existent pas. Pour maîtriser cette logique, il faut savoir qu'Apache compare d'abord les adresses IP (si spécifiées), puis le port, puis le nom. C'est cette hiérarchie qui détermine le résultat.

apachectl -S : la commande qui évite les surprises

apachectl -S affiche la liste des VirtualHost avec leur ordre, leur port et leur ServerName. C'est la commande à exécuter après chaque modification, car elle montre précisément ce qu'Apache voit. Si un site n'apparaît pas, ou si l'ordre est surprenant, vous avez identifié la cause. Utilisez -S avant tout redémarrage, c'est un réflexe.

Organiser sa configuration proprement

Sur un serveur avec plusieurs sites, la structure des fichiers compte autant que le contenu. Une organisation claire permet de trouver rapidement le bloc à modifier, et d'ajouter un site sans tout casser. Les distributions ont leurs conventions, il faut les connaître.

Un fichier par site sur Debian : sites-available, sites-enabled

Sur Debian et Ubuntu, la structure est claire : /etc/apache2/sites-available/ contient les fichiers de configuration, et /etc/apache2/sites-enabled/ contient des liens symboliques vers ceux qui sont actifs. Un site est activé avec a2ensite example.com, désactivé avec a2dissite. Cette séparation permet de garder un site désactivé sans supprimer sa configuration, ce qui est pratique pour un staging ou une sauvegarde. Un fichier par site, c'est la règle d'or.

Le cas RHEL : conf.d et la structure propre à RedHat

Sur RHEL, CentOS et Fedora, la configuration est dans /etc/httpd/, avec des fichiers dans conf.d/. Il n'y a pas de notion d'activation par lien symbolique : un site est actif dès que son fichier est présent. Cette différence peut surprendre quand on migre entre distributions, et il faut adapter sa méthode. Le principe reste le même : un fichier par site, avec un nom explicite.

Comment nommer ses fichiers pour s'y retrouver

Un nom de fichier explicite vaut mieux qu'un site1.conf et un site2.conf. Utilisez le domaine principal, éventuellement avec un préfixe numérique pour l'ordre de chargement. Par exemple 010-example.com.conf et 020-www.example.com.conf. L'ordre alphabétique devient l'ordre de chargement, ce qui aide à comprendre le comportement. Et un fichier bien nommé est un fichier qu'on retrouve vite.

Le cas HTTPS : VirtualHost sur le port 443

HTTPS ajoute une couche de complexité, mais la logique reste la même. Il faut avoir un VirtualHost sur le port 443, avec un certificat. Comme SNI est aujourd'hui supporté par la quasi-totalité des clients, un seul IP suffit pour plusieurs sites. C'est la norme en 2026.

Déclarer le certificat pour chaque domaine

Un VirtualHost HTTPS contient les directives SSL :

<VirtualHost *:443>
    ServerName example.com
    DocumentRoot /var/www/example.com/public
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
</VirtualHost>

Chaque site doit avoir son propre certificat, sauf si vous utilisez un certificat multi-domaines. Les chemins doivent être corrects, sinon Apache refuse de démarrer. Vérifiez aussi les permissions des fichiers de clé, qui doivent être accessibles uniquement au serveur. Une clé lisible par tous est un incident de sécurité en soi.

Le SNI et les clients anciens

SNI (Server Name Indication) permet au client d'envoyer le nom du serveur avant le handshake TLS, ce qui permet à Apache de choisir le bon certificat. Sans SNI, le serveur présente un seul certificat, ce qui ne fonctionne pas pour plusieurs sites. Les clients anciens, comme Windows XP ou certains bots, ne supportent pas SNI. C'est un cas de plus en plus rare, mais il existe encore. Si vous devez les servir, il vous faudra un IP dédié.

Le bon réflexe : un bloc 80 qui redirige vers 443

Pour garantir que tout le trafic passe en HTTPS, ajoutez un VirtualHost sur le port 80 qui redirige vers 443. Une règle de réécriture simple suffit :

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    RewriteEngine On
    RewriteRule ^ https://example.com%{REQUEST_URI} [R=301,L]
</VirtualHost>

Cette règle redirige toutes les requêtes HTTP vers HTTPS, en conservant le chemin. C'est une base saine, qui garantit qu'aucun utilisateur ne reste bloqué en clair. Testez avec curl -I pour vérifier la redirection.

Déclarer un site sur un autre port

Tous les sites ne sont pas sur le port 80 ou 443. Une application interne, un staging, une API peuvent être sur un port spécifique. Apache le supporte, à condition de déclarer les Listen correspondants.

Listen et VirtualHost : l'association indispensable

La directive Listen ouvre un port. Un VirtualHost sur ce port peut ensuite être déclaré. Sans Listen, le VirtualHost ne reçoit rien. La configuration typique :

Listen 8080

<VirtualHost *:8080>
    ServerName staging.example.com
    DocumentRoot /var/www/staging
</VirtualHost>

Attention : Listen s'applique globalement, pas par VirtualHost. Un port ouvert est un port exposé, il faut donc limiter l'accès avec un pare-feu ou une ACL selon le contexte. Ce point est souvent négligé.

Les cas d'usage : staging, API interne, panneau d'admin

Un site de staging sur un port dédié permet de tester sans exposer les changements. Une API interne peut être isolée sur un port spécifique, pour séparer les flux. Un panneau d'administration peut être sur un port avec une restriction d'accès. Ces usages sont légitimes, mais ils exigent une attention particulière à la sécurité : un port ouvert est un port visible. Le filtrage par IP et par pare-feu est indispensable.

Le reverse proxy comme VirtualHost

Un VirtualHost peut aussi servir de reverse proxy, c'est-à-dire transmettre les requêtes à un backend. C'est une configuration courante pour les architectures modernes, avec un serveur Node.js, Python ou Java derrière Apache.

ProxyPass et ProxyPassReverse

La configuration de base :

<VirtualHost *:443>
    ServerName app.example.com
    ProxyPreserveHost On
    ProxyPass / http://127.0.0.1:3000/
    ProxyPassReverse / http://127.0.0.1:3000/
</VirtualHost>

ProxyPass transmet la requête, ProxyPassReverse réécrit les en-têtes de redirection du backend pour qu'ils soient cohérents. Sans ProxyPassReverse, une redirection renvoyée par le backend pointe vers l'adresse interne, ce qui casse le site. C'est une erreur fréquente et difficile à diagnostiquer.

Les en-têtes à transmettre : X-Forwarded-For et Forwarded

Le backend voit l'IP du proxy, pas celle du client. Utilisez X-Forwarded-For pour transmettre l'IP réelle, et mod_remoteip pour qu'Apache la prenne en compte. Déclarez aussi X-Forwarded-Proto pour indiquer le schéma, ce qui évite les boucles de redirection. Une configuration cohérente de ces en-têtes évite des problèmes subtils, notamment avec les frameworks qui génèrent des URL absolues.

Le piège du mixed content et des redirections en boucle

Si le backend génère des URL en HTTP alors que la requête est en HTTPS, le navigateur bloque le contenu mixte. Si le backend redirige vers HTTPS en détectant mal le schéma, une boucle apparaît. La solution : configurer le backend pour faire confiance aux en-têtes X-Forwarded-*, et désactiver les redirections automatiques côté backend quand Apache les gère. C'est un réglage précis, qui demande un peu de coordination entre les équipes.

Les erreurs fréquentes qui coûtent des heures

Elles reviennent toujours, et il vaut mieux les connaître. La bonne nouvelle, c'est qu'elles sont simples à corriger une fois identifiées.

Le premier VirtualHost qui avale tout le trafic

Si le premier VirtualHost est un bloc de test ou un site oublié, il peut servir par défaut toutes les requêtes non correspondantes. Le symptôme : un site qui s'affiche à la place d'un autre, ou une page d'accueil inattendue. La correction : mettre un VirtualHost de capture en dernier, ou vérifier l'ordre avec apachectl -S. Un VirtualHost de capture, qui renvoie un 404, est souvent une bonne pratique.

DocumentRoot introuvable et 403 silencieux

Un DocumentRoot qui pointe vers un chemin inexistant produit une erreur 403, pas un 404. C'est déroutant, car on s'attend à une erreur « fichier non trouvé ». La cause : Apache considère le répertoire comme non autorisé. Vérifiez le chemin, les permissions et la présence d'un fichier d'index. Et consultez error.log, qui indique le chemin exact.

Le site qui répond sur IP mais pas sur le domaine

Un site accessible via l'IP mais pas via le domaine indique souvent un problème DNS ou un ServerAlias manquant. Testez avec curl -H "Host: example.com" http://adresse-ip pour vérifier que le VirtualHost répond. Si c'est le cas, le problème est dans le DNS, pas dans Apache. Un dig example.com confirme la résolution.

La redirection qui boucle à cause de ServerName

Une redirection HTTPS basée sur ServerName peut entrer en boucle si le nom de domaine ne correspond pas exactement. Par exemple, www.example.com qui redirige vers example.com, et inversement. La solution : tester avec curl -I et vérifier l'en-tête Location. Utilisez un ServerName canonique unique, et redirigez tout le reste vers ce nom.

Tester et valider un VirtualHost

Un VirtualHost bien configuré ne suffit pas, il faut vérifier qu'il fonctionne réellement. Trois commandes font l'essentiel du job, à condition de les utiliser dans le bon ordre.

Le trio configtest, -S et curl

apachectl configtest valide la syntaxe. apachectl -S affiche les VirtualHost. curl -I https://example.com vérifie le comportement réel. Ces trois commandes, utilisées à chaque modification, évitent la majorité des erreurs. C'est simple et rapide, il n'y a aucune raison de s'en passer. Et si un doute persiste, error.log donne la réponse.

Vérifier le certificat avec openssl s_client

openssl s_client -connect example.com:443 -servername example.com affiche le certificat présenté. Utile pour vérifier que c'est bien le bon certificat qui est servi, et non celui d'un autre site. Cette commande est précieuse quand plusieurs sites coexistent, car elle montre le certificat réellement présenté. Un mauvais certificat est un signal d'alarme immédiat.

Les tests à faire après chaque ajout

Après chaque nouveau VirtualHost, testez :

  • L'accès en HTTP et en HTTPS
  • La redirection de HTTP vers HTTPS
  • Le bon certificat avec openssl s_client
  • Les variantes de domaine (www et non-www)
  • Un domaine inconnu, pour vérifier le VirtualHost par défaut

Ces tests prennent quelques minutes et évitent des surprises. Notez-les dans une checklist, vous ne les oublierez pas.

FAQ : les questions les plus fréquentes sur les VirtualHost

Combien de sites peut-on héberger sur un seul serveur ? Il n'y a pas de limite théorique. En pratique, la limite dépend des ressources : mémoire, CPU, bande passante, espace disque. Un serveur modeste peut héberger plusieurs dizaines de sites à faible trafic. Un site à fort trafic peut suffire à saturer un serveur. La supervision est essentielle pour déterminer la limite réelle.

Comment gérer plusieurs domaines pour un même site ? Utilisez ServerAlias pour déclarer les variantes, ou déclarez plusieurs VirtualHost qui pointent vers le même DocumentRoot. La première approche est plus simple, la seconde permet des configurations distinctes. Le choix dépend de votre besoin.

Que faire si un site fonctionne en HTTP mais pas en HTTPS ? Vérifiez que le VirtualHost sur le port 443 existe et qu'il contient les directives SSL. Vérifiez les chemins du certificat et de la clé. Testez avec openssl s_client pour voir le certificat présenté. Et consultez error.log, qui indique souvent la cause exacte.

Conclusion : une architecture claire pour une maintenance sereine

Les VirtualHost ne sont pas compliqués une fois qu'on a compris la logique. Trois éléments suffisent : un bloc par site, une structure claire, et des tests systématiques. Le reste, ce sont des détails qu'on apprend au fil de l'expérience. En 2026, avec des architectures qui multiplient les sites et les environnements, cette discipline n'est plus un luxe. C'est la condition d'un serveur qui reste maintenable. Ajoutez un site, testez-le, documentez-le, et recommencez. Votre serveur vous remerciera, et vos collègues aussi.

← molitor.photography