Le code des hôtes virtuels a été complètement réécrit dans la version 1.3 d'Apache. Ce document tente d'expliquer exactement ce qu'Apache fait lorsque il décide de servir une requête de tel ou tel hôte virtuel qu'il héberge. Grâce à la nouvelle directive NameVirtualHost, la configuration des hôtes virtuels devrait être beaucoup plus facile et plus sûre que les versions antérieures à la version 1.3 d'Apache.
Si vous désirez simplement exploiter cette fonctionnalité sans entrer dans le détail de son fonctionnement, voici quelques exemples qui vous seront utiles.
Un serveur principal est défini par toutes les définitions apparaissant en
dehors des sections <VirtualHost>
. Les hôtes virtuels,
lorsqu'ils existent, sont définis par les sections <VirtualHost>
Les directives Port, ServerName, ServerPath, et ServerAlias peuvent apparaître à n'importe quel endroit à l'intérieur de la définition d'un serveur virtuel. Quoiqu'il en soit, chaque apparition de ces directives surcharge les apparitions précédentes de ces mêmes directives (à l'intérieur d'une même définition de serveur).
La valeur par défaut du champ Port
est 80 pour le
serveur principal. En revanche, les ServerPath
, ou
ServerAlias
n'ont pas de valeurs par défaut pour le serveur
principal. Le nom du serveur par défaut ( ServerName
) est
déduit de l'adresse de IP des serveurs.
La directive Port
du serveur principal a deux fonctions,
découlant de la compatibilité avec les fichiers de configuration
NCSA. La première fonction consiste en la détermination du port
réseau qu'Apache reconnaît par défaut. Cette valeur par
défaut est surchargée par toute apparition d'une directive Listen
. Le second usage est la
spécification du numéro du port utilisé, pour la
redirection d'URI absolues.
A la différence du serveur principal, les ports d'un hôte virtuel n'affectent pas les ports qu'écoute Apache.
Chaque adresse apparaissant dans la directive Virtual Host
peut optionnellement spécifier un port. Si le port n'est pas
explicitement spécifié, la valeur par défaut choisie est
la valeur la plus récente de la directive Port
du serveur
principal. Le port spécial noté * indique par
l'usage de ce metacaractère une écoute étendue à
n'importe quel port. La liste complète des adresses d'hôtes
virtuels est communément appelée l'espace d'adresses
virtuelles ( incluant les multiples résultats de résolutions
DNS sur le type A).
A moins qu'une directive du type NameVirtualHost soit adjointe à une adresse IP spécifique, le premier hôte virtuel apparaissant avec une adresse particulière est considéré comme l'hôte virtuel basé sur cette même adresse IP.
Si les hôtes virtuels basés sur les noms doivent être
utilisés, une directive telle que NameVirtualHost
doit apparaître avec la liste des adresses IP correspondant
à cet hôte. En d'autres termes, vous devez spécifier les
adresses IP associées à tous les alias des hôtes (CNAMEs),
définis via la directive NameVirtualHost
dans votre fichier
de configuration.
De multiples directives NameVirtualHost
peuvent être
spécifiées avec, pour chacune d'entre elles, une liste de
directives de VirtualHost
.
L'ordre des directives NameVirtualHost
et
VirtualHost
n'est pas important et rend identiques les deux
exemples suivants (seul l'ordre des directives VirtualHost
à l'intérieur d'une même liste d'adresses est
important, voir ci-dessous):
| NameVirtualHost 111.22.33.44 | <VirtualHost 111.22.33.44> <VirtualHost 111.22.33.44> | # server A # server A | </VirtualHost> ... | <VirtualHost 111.22.33.55> </VirtualHost> | # server C <VirtualHost 111.22.33.44> | ... # server B | </VirtualHost> ... | <VirtualHost 111.22.33.44> </VirtualHost> | # server B | ... NameVirtualHost 111.22.33.55 | </VirtualHost> <VirtualHost 111.22.33.55> | <VirtualHost 111.22.33.55> # server C | # server D ... | ... </VirtualHost> | </VirtualHost> <VirtualHost 111.22.33.55> | # server D | NameVirtualHost 111.22.33.44 ... | NameVirtualHost 111.22.33.55 </VirtualHost> | |
(Pour rendre votre configuration plus lisible, utilisez plutôt la variante de gauche).
Après avoir analysé la directive VirtualHost
,
une valeur de Port
égale à celle du port
assigné au premier nom qui y est trouvé pour cet hôte, est
donnée par défaut à ce dernier.
La liste complète de noms dans la directive VirtualHost
est traitée de la même manière que dans une directive
ServerAlias
(bien que ne pouvant être surchargé par
une quelconque directive ServerAlias
) si tous les noms se trouvent
dans le même espace d'adresses virtuelles. Notez que des
redéfinitions ultérieures de la directive Port
pour
ces hôtes virtuels, n'affecteront pas les ports qui sont assignés
dans cette liste d'adresses.
Pendant l'initialisation, une liste est générée et
insérée dans un tableau associatif pour chaque adresse IP. Si
l'adresse IP est mentionnée dans une directive du type
NameVirtualHost
, la liste contiendra tous les hôtes virtuels
nommés correspondant à cette adresse. Si aucun hôte virtuel
n'est défini pour cette adresse, la directive
NameVirtualHost
sera ignorée et une ereur sera
enregistré dans la trace d'erreur. Lorsque l'hôte virtuel n'est
défini que par une adresse IP, le tableau associatif reste vide.
Grâce à un algorithme de "hashage" très rapide, le surcoût demandé par l'utilisation de tableaux associatifs lors du traitement d'une requête est pratiquement nul. De plus, cet algorithme est optimisé pour des adresses IP ne variant que par leur dernier octet.
Pour tous les hôtes virtuels, différentes valeurs par défaut sont établies. En particulier :
ServerAdmin
, ResourceConfig
, AccessConfig
, Timeout
, KeepAliveTimeout
, KeepAlive
, MaxKeepAliveRequests
, ni SendBufferSize
, alors la valeur
par défaut pour chacune de ces directives hérite du serveur
principal. (C'est-à-dire qu'elles sont initialisées avec les
valeurs les plus récentes du serveur principal). Le serveur principal doit être essentiellement considéré comme "défaut" ou "base" sur lequel on peut construire tous les hôtes virtuels. Mais la position des définitions de ce serveur principal dans le fichier de configuration n'est pas significative -- la configuration entière du serveur principal a en principe été lue au moment où cette combinaison finale est faite. De ce fait, même si une définition du serveur principal apparaît après une définition d'hôte virtuel, il se pourrait que cette dernière soit affectée.
Si arrivé à ce point, le serveur principal n'a pas de nom
(ServerName
), alors le nom de l'hôte exécutant httpd
est utilisé à la place. Nous appellerons l'espace d'adresse du
serveur principal, les adresses IP retournées par une
résolution DNS sur le nom ServerName
attribué au
serveur principal.
Tout hôte n'ayant pas de ServerName
défini
reçoit un nom par défaut construit à partir de la
première adresse IP mentionnée dans la section
VirtualHost
définissant ce vhost.
Le nom
du serveur principal est reporté dans l'attribut
ServerName
de tout hôte virtuel qui inclue le meta-attribut
_default_
Lorsqu'une requête est reçue, le serveur principal détermine quel est l'hôte virtuel à activer de la façon suivante :
Quand la connexion est établie par un client, la première opération consiste à vérifier l'adresse IP que demande le client dans la table associative des adresses IP.
Si la recherche n'aboutit pas (c-à-d. que l'adresse IP n'a pas été trouvée), la demande est prise en charge par l'hôte virtuel par défaut _default_ , si ce dernier existe pour le port sur lequel le client a envoyé sa requête. Si aucun hôte virtuel n'est défini comme _default_ pour ce port, la requête est finalement prise en compte par le serveur principal .
Si la recherche réussit (c'est à dire que l'adresse IP demandée a été trouvée dans une table), la prochaine étape consiste à déterminer si l'hôte virtuel visé est un hôte nommé ou basé sur une adresse IP.
Si la table trouvée pour l'adresse IP est vide, alors il s'agit d'un hôte virtuel basé sur une adresse IP, aucune autre action est accomplie et la demande est prise en charge par l'hôte virtuel.
Si la table correspondant à l'adresse IP demandée contient
une ou plusieurs structures de définition de vhost, alors il s'agit d'un
hôte nommé. La table contient alors la définition des tous
les hôtes virtuels associés au nom dans l'ordre ou elles ont
été inscrite dans la section VirtualHost
du fichier
de configuration.
Le premier hôte virtuel dans la liste (c'est à dire le premier
hôte virtuel qui apparaît après la directive
NameVirtualHost
correspondante du fichier de configuration), a la
priorité sur les autres et prend en charge toutes les requêtes
visant un nom de serveur inconnu ou ne mentionnant pas de champ
Host:
dans l'en-tête http.
Si le client mentionne un champ Host:
dans cette en-
tête, on recherche dans la liste un hôte virtuel correspondant
à ce champ. Le premier ServerName
ou
ServerAlias
qui correspond prend en charge la requête
adressée à cet hôte virtuel. Un champ d'en-tête
Host:
peut mentionner un numéro de port, mais Apache ne
recherche la correspondance qu'avec le port réel sur lequel le client a
envoyé sa requête.
Si le client a émis une requête de type HTTP/1.0 sans champ
d'en-tête Host:
, vous ne savez pas à quel serveur le
client essaye de se connecter et l'URI de la requête est comparée
à tous les chemins d'accès ServerPath
existants. Le
premier chemin qui correspond est utilisé et la requête est prise
en charge par l'hôte virtuel qui a défini ce chemin.
Si aucun hôte virtuel ne peut être trouvé, la requête sera prise en charge par le premier hôte virtuel de la liste correspondant à l'adresse IP demandée par le client, et dont le numéro de port correspond au port sur lequel est arrivée la requête (comme nous l'avons déjà mentionné auparavant).
La résolution sur adresse IP décrite ci-dessus n'est
effectuée qu'une seule fois pour une session TCP/IP
donnée, alors que la résolution par nom est systématique
à chaque requête pendant une connexion rémanente
utilisant KeepAlive
. En d'autres termes, un client, pour une
connexion rémanente unique, peut requérir plusieurs pages
hébergées sur différents hôtes virtuels
nommés.
Si l'URI dans la requête est une URI absolue, et le nom d'hôte et le port correspondent au serveur principal ou à l'un des hôtes virtuels configurés ET au couple adresse/port auquel le client a envoyé sa requête, alors le préfixe scheme/hostname/port est ignoré et l'URI relative obtenue est prise en charge par le serveur principal ou l'hôte virtuel correspondant. Si la correspondance n'est pas vérifiée, alors l'URI reste telle quelle et la requête est comprise comme une requête proxy.
NameVirtualHost
.ServerAlias
et ServerPath
ne sont jamais réalisées pour un hôte virtuel basé sur adresse IP. NameVirtualHost
à l'intérieur du fichier de
configuration, ne sont pas significatifs. Seul l'ordre dans lequel les
différents hôtes nommés sont définis pour un ensemble d'adresses donné est
important. L'hôte virtuel nommé en premier dans le fichier de configuration a
priorité sur les autres.ServerPath
explicite est un prédicat d'une
autre directive ServerPath
qui apparaît plus loin dans le fichier
de configuration, alors la correspondance se fera toujours sur la deuxième et
jamais sur la première. (Nous supposons ici qu'aucun champ d'en-tête Host:
n'était lisible dans la requête pour lever l'ambiguïté).NameVirtualHost
), ni l'hôte virtuel par _default_ ni
le serveur principal, ne pourront être atteints lorsque le champ
Host: de l'en-tête HTTP de la requête est vide, ou affiche un nom
d'hôte inconnu.<VirtualHost>
, car cela forcerait votre serveur à compter
sur un serveur DNS pour démarrer. De plus, cela pose un problème de sécurité si
vous ne contrôlez pas le DNS pour tous les domaines auxquels vous faîtes
référence. Vous trouverez dans la section Apache et DNS des informations plus
précises concernant ce point et les deux qui suivent. ServerName
doit toujours être défini pour chaque hôte
virtuel. Autrement, une recherche DNS ne peut être évitée.En complément des quelques trucs données en section Apache et DNS, voici quelques recettes supplémentaires.
NameVirtualHost
et VirtualHost
dans votre configuration pour faciliter et garantir
une bonne fusion.
ServerPath
. Si vous ne pouvez pas l'éviter,
assurez vous que la définition la plus longue (et donc la plus spécifique) d'un
hôte virtuel apparaît dans le fichier de configuration avant la plus courte (la
moins spécifique) ( c'est à dire que PServerPath /abc doit
apparaître après ServerPath /abc/def). Adaptation française : Yael
Leblanc / Promo 2000
Sous la direction de : Valery Fremaux / EISTI
1998