[APACHE DOCUMENTATION]

Apache HTTP Server Version 1.3

Discussion "en profondeur" sur l'adressage d'hôtes virtuels

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.

Analyse du fichier de configuration

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 :

  1. Si l'hôte virtuel ne contient pas de directives de type 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).
  2. Le paramètre "lookup defaults" qui définit les permissions par défaut pour l'accès aux répertoires par l'hôte virtuel est combiné avec celui du serveur principal. Ceci inclut toute information de configuration "répertoire par répertoire" et ce pour tout les modules.
  3. Les configurations "serveur par serveur" dans chaque module du serveur principal sont combinées pour former celles de l'hôte virtuel.

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_

Routage vers les hôtes virtuels

Lorsqu'une requête est reçue, le serveur principal détermine quel est l'hôte virtuel à activer de la façon suivante :

Recherche de la table associative correspondante

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.

Hôte virtuel basé sur l'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.

Hôte virtuel nommé

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).

Connexions rémanentes

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.

URI Absolues

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.

Observations

Astuces et trucs

En complément des quelques trucs données en section Apache et DNS, voici quelques recettes supplémentaires.


Apache HTTP Server Version 1.3

Index Home

Adaptation française : Yael Leblanc / Promo 2000
Sous la direction de : Valery Fremaux / EISTI 1998