Apache Virtualhost

Transcription

Apache Virtualhost
Conception détaillée d'hôtes virtuels sous Apache
par Julien Pauli (Tutoriaux, articles et conférences
PHP, développement web open source) (Blog)
Date de publication : 08/12/2009
Dernière mise à jour : 07/03/2011
Souvent peu compris, l'hébergement virtuel est de nos jours un acquis. Un même serveur
physique/logiciel capable d'héberger plusieurs sites parfois très différents, voila ce qu'est
le "virtual hosting" (vhost)
Dans cet article, nous allons voir comment mettre en place un hébergement virtuel sous
Apache, avec le détail de toutes les facettes : types de vhost, sécurité, contrôle d'accès,
DNS...
Conception détaillée d'hôtes virtuels sous Apache par Julien Pauli (Tutoriaux,
articles et conférences PHP, développement web open source) (Blog)
I - Introduction au Virtual Hosting................................................................................................................................3
II - Théorie générale du Virtual Host et d'Apache...................................................................................................... 4
III - Virtual Host par adresse réseau (IP / port TCP).................................................................................................. 5
IV - Virtual Host par noms...........................................................................................................................................8
IV-A - Virtual Host par noms et par IP.................................................................................................................. 9
IV-B - Récapitulatif et considérations de sécurité................................................................................................12
V - Exemple concret - complet..................................................................................................................................15
VI - Les configurations plus complexes et les modules tiers....................................................................................17
-2Copyright © 2009 - Julien PAULI. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,
documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
http://julien-pauli.developpez.com/tutoriels/apache/vhosts/
Conception détaillée d'hôtes virtuels sous Apache par Julien Pauli (Tutoriaux,
articles et conférences PHP, développement web open source) (Blog)
I - Introduction au Virtual Hosting
L'hébergement virtuel (virtual hosting) est le fait de servir plusieurs sites web sur une même instance de serveur.
Ainsi, une machine serveur possède un et un seul serveur Apache et elle pourra servir (virtuellement) une infinité de
sites qui n'ont aucunement besoin de "se connaître" l'un l'autre. La flexibilité d'Apache fait que chaque site pourra être
configuré de manière très différente de son voisin. Aussi, les clients (en grande partie des navigateurs web) n'auront
aucune idée du fait qu'il existe plusieurs sites sur le serveur qu'ils ont contacté. Sauf erreurs de configuration, ils
n'auront aucun moyen de le savoir.
L'hébergement virtuel est très utilisé chez les hébergeurs proposant des serveurs dits
"mutualisés". Dans ce cas là, un même Apache sert un (très) grand nombre de sites
web différents et ses ressources sont donc entièrement partagées entre tous les sites de
manière équitable.
Il est possible de régler la charge par hôte virtuel, mais il faut pour cela compiler un module
externe.
Mais, comment héberge-t-on plusieurs applications webs sur un seul serveur Apache ? Il existe globalement 2
grandes méthodes de multi-hébergement (4 manières réelles) :
1
2
3
tout d'abord, l'hébergement virtuel par adresse : la machine serveur possède plusieurs adresses IP, et
chacune mène vers un site distinct ;
ensuite l'hébergement virtuel par nom : la machine ne possède qu'une seule adresse IP et ce sont les noms
des sites qui vont aiguiller la requête ;
puis enfin des manières qui découlent des deux précédentes : la machine possède une ou plusieurs adresses
IP, mais elle peut différencier les sites par port TCP.
En dernier lieu on peut tout mixer : hébergement par adresse, port et nom. Dans ce cas, la machine possède
plusieurs adresses IP et écoute sur chacune d'elles plusieurs ports TCP, tout en distinguant les noms des
sites web.
Nous allons détailler le processus de routage des hôtes virtuels d'Apache, de manière claire afin qu'aucune confusion
ne puisse être faite.
Ca n'est pas complexe, c'est même simple et totalement logique, mais il faudra bien retenir certains points. La version
d'Apache considérée est 2.2.x, mais il n'existe que très peu de différences avec les versions supérieures ou égales
à 1.3.
Enfin nous parlerons des modules externes, à récupérer et compiler, qui peuvent rendre de gros services.
Dans cet article, nous parlons hôtes virtuels et nous supposons que vous savez déjà
configurer un serveur Apache de manière fonctionnelle. Ainsi, nous n'allons pas à chaque
fois détailler la configuration complète du serveur, mais juste ce qui nous intéressera.
Nous supposerons le reste de la configuration (qui peut demeurer tout à fait "classique"
et minimale néanmoins) présent et fonctionnel.
-3Copyright © 2009 - Julien PAULI. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,
documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
http://julien-pauli.developpez.com/tutoriels/apache/vhosts/
Conception détaillée d'hôtes virtuels sous Apache par Julien Pauli (Tutoriaux,
articles et conférences PHP, développement web open source) (Blog)
II - Théorie générale du Virtual Host et d'Apache
Apache utilise des sockets TCP pour servir ses requêtes. Indépendamment du concept même de l'hébergement
virtuel, il convient de préciser à Apache quelle(s) IP il doit écouter et quel(s) port(s).
Une seule directive entre en jeu pour cela : Listen. Elle est définie pour tout le serveur Apache.
Le cas nous intéressant est "une seule instance d'Apache sert plusieurs sites". Tous les sites tourneront donc avec
le même utilisateur Unix, ce qui peut créer des problèmes de sécurité.
Certains modules peuvent résoudre ceci, l'utilisation de scripts CGI peut aussi être épargnée, sinon il faudra démarrer
autant d'instances d'Apache que de sites. Cette idée est assez idiote, car démarrer X instances d'Apache, c'est
augmenter la charge mémoire de la machine car beaucoup de modules d'Apache sont compilés statiquement, et
auront donc X images en mémoire, gaspillant d'autant plus celle-ci. Le mieux serait qu'une seule instance d'Apache
puisse gérer X sites, chacun sous un utilisateur Unix différent. Certains modules (non officiels) permettent cela, mais
pas Apache par défaut.
L'hébergement par nom se base sur l'en-tête Host: de la requête HTTP, afin de sélectionner le bon site. Cet en-tête
n'existe qu'en HTTP1.1 et aujourd'hui, certains (rares) clients parlent toujours en HTTP1.0 et sont donc en théorie
incompatibles avec l'hébergement virtuel par nom. Apache introduit cependant une directive pour tenter d'enrayer
ce problème.
Les hôtes virtuels sont supportés par défaut par Apache, il n'y a aucun module spécial à préciser à la compilation car
il est compilé statiquement par défaut : il s'agit de mod_core, le module minimal nécessaire à Apache pour tourner.
Apache sait gérer nativement les hôtes virtuels, il n'y a rien de spécial à faire pour ça.
-4Copyright © 2009 - Julien PAULI. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,
documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
http://julien-pauli.developpez.com/tutoriels/apache/vhosts/
Conception détaillée d'hôtes virtuels sous Apache par Julien Pauli (Tutoriaux,
articles et conférences PHP, développement web open source) (Blog)
III - Virtual Host par adresse réseau (IP / port TCP)
L'hébergement par réseau consiste à disposer de plusieurs ports TCP et/ou de plusieurs adresses IP (physiques ou
virtuelles) sur la machine serveur. La commande Linux ifconfig permet de configurer les interfaces réseaux.
Nous allons supposer que la machine utilise 2 adresses IP : 192.168.0.1 et 192.168.0.2.
Dans le cas de plusieurs adresses, il faut spécifier à Apache sur lesquelles écouter, et sur quels ports TCP, ceci
grâce à la directive Listen
httpd.conf, directive Listen
Listen 80
Listen 192.168.0.2:81
Le port est obligatoire, l'adresse est facultative, si on ne la précise pas (en ne précisant qu'un numéro de port), Apache
utilisera toutes les addresses IP disponibles sur la machine, c'est donc plutôt déconseillé pour des raisons de sécurité
(oubli lors de l'ajout d'une interface sur la machine par exemple).
Le port utilisé par HTTP est 80 par défaut, ainsi les navigateurs web et autres clients HTTP l'utilisent sans devoir le
préciser. Si un autre port est employé, il conviendra de le préciser sur le client.
Ici, notre serveur écoute le port 81 mais uniquement sur l'adresse 192.168.0.2. Les commandes Linux netstat et lsof
permettent de vérifier qu'Apache écoute bien les adresses/ports spécifiés.
Rappel : Toute ouverture de socket en écoute sur un port inférieur à 1024 nécessite les
droits root sur les systèmes *nix.
Rappel : Apache doit dans la grande majorité des cas, être démarré par root (à cause du
port qu'il doit écouter, par défaut 80, inférieur à 1024 donc). Cependant, les processus
qu'il va faire naître pour traiter les requêtes des clients tourneront sous un autre utilisateur
ayant beaucoup moins de droits ("www", "httpd" ou encore "daemon", ça dépend de
votre système). Cet utilisateur et son groupe sont à préciser dans la configuration globale
d'Apache, via les directives User et Group. Ces utilisateurs sont globaux à tout Apache,
donc à tous les sites/hôtes virtuels qu'il va servir.
Un hôte virtuel se configure grâce à la directive <VirtualHost>. Cette directive ouvre un bloc, dans lequel toutes les
directives de contexte virtualhost peuvent être écrites.
La liste est grande, voyez le manuel pour plus d'informations. Voyez cette page pour une explication des différents
contextes de configuration Apache
Chaque site se présente sous la forme d'un bloc <VirtualHost> et celui-ci doit préciser un port et éventuellement une
adresse d'écoute, en théorie en correspondance avec la directive Listen ou du moins en corrélation avec.
Exemple d'hôtes virtuels Apache basés sur le réseau : IP/ports
Listen 80
Listen 192.168.0.2:81
<VirtualHost 192.168.0.1:80>
DocumentRoot /var/www1
ServerName server1
</Virtualhost>
<VirtualHost 192.168.0.2:80>
DocumentRoot /var/www2
ServerName server2
</VirtualHost>
<VirtualHost 192.168.0.2:81>
DocumentRoot /var/www3
ServerName server3
</VirtualHost>
-5Copyright © 2009 - Julien PAULI. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,
documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
http://julien-pauli.developpez.com/tutoriels/apache/vhosts/
Conception détaillée d'hôtes virtuels sous Apache par Julien Pauli (Tutoriaux,
articles et conférences PHP, développement web open source) (Blog)
Tant que l'ensemble des blocs <VirtualHost> "attrapent" tout ce qui peut entrer via Listen, tout va bien.
Les directives minimales à préciser sont DocumentRoot et ServerName, c'est à dire la liaison entre cette adresse/
port, et le système de fichiers : c'est la fonction centrale et la définition même du serveur HTTP. Le nom (ServerName)
est ici "facultatif" au niveau du choix du bloc à exécuter, c'est-à-dire que quel que soit le nom de domaine qui pointe
sur l'IP, ServerName n'est pas utilisé pour aiguiller la requête dans le cas d'un hébergement par IP.
Important : seul le couple IP/Port est utilisé pour aiguiller la requête dans le cas d'hôtes
virtuels basés sur le réseau.
Que se passe-t-il si aucun bloc <VirtualHost> ne correspond à la demande ? En effet, imaginons ceci :
Il semble manquer des blocs VirtualHost?
Listen 80
Listen 81
<VirtualHost 192.168.0.1>
DocumentRoot /var/www1
ServerName server1
</VirtualHost>
Qu'advient-il d'une requête vers http://192.168.0.2:81 par exemple ? La règle est simple : toute requête qui ne peut
être satisfaite par un hôte virtuel tombe sur la configuration classique
La configuration classique, c'est tout simplement l'ensemble DocumentRoot/ServerName qui est écrit hors des blocs
<VirtualHost> et qui pour rappel définit ce que l'on appelle le "serveur par défaut" : ces directives sont obligatoires
pour lancer Apache.
le serveur par défaut reçoit la requête que les blocs VirtualHost n'attrapent pas
Listen 80
Listen 81
# attrape tout ce qui échappe aux blocs <VirtualHost>
# dans notre exemple 192.168.0.1:80 sera attrapé ici
DocumentRoot /var/www
ServerName ServerParDefaut
# attrape 192.168.0.1:80 uniquement
<VirtualHost 192.168.0.1:80>
DocumentRoot /var/www1
ServerName server1
</VirtualHost>
# attrape le port 81 de toutes les adresses de la machine
<VirtualHost *:81>
DocumentRoot /var/www2
ServerName server2
</VirtualHost>
Voila, vous venez de comprendre le fonctionnement des hôtes virtuels par IP sous Apache, il n'y a rien à ajouter.
A vous d'écrire dans chaque bloc <VirtualHost> la configuration de votre serveur. Toute directive écrite en dehors
des blocs sera alors écrasée par celle écrite dans le bloc, les autres seront traitées normalement. Voila qui devrait
donner un sens à la notion "d'hôte virtuel".
Attention tout de même, il y a des choses qu'Apache n'aime pas : les situations ambiguës. Son statut est alors indéfini
et il finira souvent par planter.
Voici une situation ambiguë :
une situation ambiguë qu'Apache n'aime pas
Listen 192.168.0.1:80
Listen 81
-6Copyright © 2009 - Julien PAULI. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,
documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
http://julien-pauli.developpez.com/tutoriels/apache/vhosts/
Conception détaillée d'hôtes virtuels sous Apache par Julien Pauli (Tutoriaux,
articles et conférences PHP, développement web open source) (Blog)
une situation ambiguë qu'Apache n'aime pas
DocumentRoot /var/www
ServerName ServerParDefaut
<VirtualHost 192.168.0.1>
DocumentRoot /var/www1
ServerName server1
</VirtualHost>
<VirtualHost *:80>
DocumentRoot /var/www2
ServerName server2
</VirtualHost>
Avec une telle configuration, une requête vers le port 81 mène vers le serveur par défaut car aucun bloc <VirtualHost>
ne peut l'attraper, mais quid d'une requête vers 192.168.0.1:80 ?
Une telle requête peut être attrapée par 2 blocs <VirtualHost> (dans notre cas un précise l'adresse sans port, et
l'autre le port sans adresse), Apache ne sait pas lequel choisir et plantera souvent face à un tel cas.
Veiller toujours à ce qu'il n'y ait aucune ambiguïté lors de la correspondance de la requête
sur la socket d'entrée et les blocs <VirtualHost>.
Si tel est le cas, Apache entre dans un état indéfini. Pour éviter cela, il suffit que les
<VirtualHost> renseignent une IP et un port afin d'être le plus précis possible. Si possible,
évitez le joker *.
-7Copyright © 2009 - Julien PAULI. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,
documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
http://julien-pauli.developpez.com/tutoriels/apache/vhosts/
Conception détaillée d'hôtes virtuels sous Apache par Julien Pauli (Tutoriaux,
articles et conférences PHP, développement web open source) (Blog)
IV - Virtual Host par noms
L'hébergement virtuel par noms a été rendu possible par HTTP1.1. En effet, si vous révisez vos connaissances
d'HTTP (
par ici par exemple), vous remarquerez que HTTP1.1 introduit l'en-tête de requête Host:, qui précise
le nom de l'hôte que le client souhaite contacter. Apache va utiliser ce nom pour aiguiller la requête sur le bon bloc
<VirtualHost> grâce à ServerName.
Important : la directive ServerName va servir à aiguiller la requête sur le bon hôte. Le DNS
est donc important dans un tel cas. Nous allons y revenir.
Prenons un exemple simple. Notre serveur dispose d'une seule adresse IP et n'écoute qu'un seul port :
192.168.0.1:80. Le serveur DNS a été configuré pour relier à cette adresse IP 2 noms de domaines différents : server1
et server2.
La configuration va alors ressembler à ceci :
Listen 192.168.0.1:80
ServerName DefaultServer
DocumentRoot /var/www
NameVirtualHost 192.168.0.1:80
<VirtualHost 192.168.0.1:80>
ServerName server1
DocumentRoot /var/www1
</VirtualHost>
<VirtualHost 192.168.0.1:80>
ServerName server2
DocumentRoot /var/www2
</VirtualHost>
Important : dans le cas d'un hébergement virtuel par noms, la directive NameVirtualHost
est obligatoire.
Inversement : la présence d'une directive NameVirtualHost signifie qu'Apache va utiliser
l'en-tête Host: de la requête, dans une partie du routage vers le bon hôte virtuel. Les
adresses renseignées dans les blocs <VirtualHost> doivent être exactement les mêmes
que celles écrites dans NameVirtualHost
Dans notre exemple, une requête vers http://server1 mènera dans le premier bloc, une requête vers http://server2
vers le deuxième.
Rappelons le schéma d'une requête HTTP :
Exemple simple d'une requête HTTP1.1
GET /foo/bar HTTP/1.1
Host: server1
{autres en-têtes ici}
C'est bien la valeur de Host: qui va déterminer le bloc <VirtualHost> à choisir, en fonction de la directive ServerName
logée à l'intérieur
A quoi peut bien servir cette directive NameVirtualHost ? C'est très simple : elle sert à router l'IP et le port dans le
cas où le serveur en écoute plusieurs.
Apache effectue donc un double routage de la requête, ce qui nous amène à la section immédiatement suivante
de cet article.
-8Copyright © 2009 - Julien PAULI. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,
documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
http://julien-pauli.developpez.com/tutoriels/apache/vhosts/
Conception détaillée d'hôtes virtuels sous Apache par Julien Pauli (Tutoriaux,
articles et conférences PHP, développement web open source) (Blog)
IV-A - Virtual Host par noms et par IP
Ce chapitre nécessite que vous aiyez compris le principe de l'hébergement virtuel par
réseau (IP/port). Relisez le chapitre si nécessaire.
Un serveur Apache peut à la fois écouter plusieurs IP/ports et différencier les noms des serveurs. Il s'agit alors d'un
hébergement virtuel par IP et par noms.
Prenons l'exemple d'un serveur qui écoute 192.168.0.1:80 et 192.168.0.2:80. Il doit servir les noms server1, server2,
server3 et server4. En jouant avec NameVirtualHost, on va indiquer à Apache le premier aiguillage : celui de l'IP/
port. Une fois cet aiguillage effectué, Apache va analyser le nom dans l'en-tête Host:, et l'aiguiller dans le bloc
<VirtualHost> qui le précise avec la directive ServerName
Exemple de virtual host par IP et par nom en même temps
Listen 192.168.0.1:80
Listen 192.168.0.2:80
ServerName DefaultServer
DocumentRoot /var/www
# Voici les hôtes virtuels à considérer si la requête arrive
# sur 192.168.0.1:80
NameVirtualHost 192.168.0.1:80
<VirtualHost 192.168.0.1:80>
ServerName server1
DocumentRoot /var/www1
</VirtualHost>
<VirtualHost 192.168.0.1:80>
ServerName server2
DocumentRoot /var/www2
</VirtualHost>
# Voici les hôtes virtuels à considérer si la requête arrive
# sur 192.168.0.2:80
NameVirtualHost 192.168.0.2:80
<VirtualHost 192.168.0.2:80>
ServerName server3
DocumentRoot /var/www3
</VirtualHost>
# server4 n'est pas précisé, nous allons voir ce qui se passe
Dans cet exemple, http://server1 est supposé être routé dans le DNS vers 192.168.0.1. La requête arrive donc vers
192.168.0.1:80 et Apache entre donc dans la première section NameVirtualHost. Une fois dedans, il analyse l'hôte
demandé dans la requête : il s'agit de server1. server1 est bien précisé dans le premier bloc <VirtualHost>, il sera
donc choisi comme second aiguillage, et /var/www1 sera servi.
la valeur de NameVirtualHost doit être systématiquement la même que celle de tous les
blocs <VirtualHost> qui vont suivre.
la valeur de NameVirtualHost doit être un couple IP (* possible) et port.
L'ensemble des directives NameVirtualHost se comportent comme dans le cas de
l'hébergement par IP : il ne doit pas y avoir ambiguïté pour Apache.
Continuons sur le même exemple. Imaginons que server4 soit routé dans le DNS vers 192.168.0.2. Comme dans la
section NameVirtualHost 192.168.0.2:80 il n'existe aucun bloc dont ServerName vaut "server4", une telle requête
sera aiguillée vers le serveur par défaut qui sera server3.
Voici les règles du choix du serveur par défaut lorsque des noms interviennent :
-9Copyright © 2009 - Julien PAULI. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,
documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
http://julien-pauli.developpez.com/tutoriels/apache/vhosts/
Conception détaillée d'hôtes virtuels sous Apache par Julien Pauli (Tutoriaux,
articles et conférences PHP, développement web open source) (Blog)
1
2
3
dans le cas d'un serveur faisant intervenir des noms (NameVirtualHost), le serveur par défaut n'est pas celui
déclaré hors des blocs <VirtualHost> (comme c'est le cas pour l'hébergement virtuel par IP) si et seulement
si une directive NameVirtualHost a déjà aiguillé la requête ;
le serveur par défaut dans un hébergement virtuel par noms est le premier bloc <VirtualHost> qui suit le
premier filtre : NameVirtualHost si et seulement si celui-ci a déjà pu aiguiller la requête par son IP/port ;
dans le cas d'un hébergement virtuel par noms, le serveur déclaré hors des blocs <VirtualHost>
est le serveur par défaut si aucun couple IP/port n'a trouvé de correspondance dans les directives
NameVirtualHost déclarées.
Nous avons vu dans la partie "Virtual Host par réseau (IP/ports)" qu'il ne faut pas
créer de situation ambiguë. Dans les hébergements virtuels par noms, plusieurs blocs
<VirtualHost> possèdent exactement la même syntaxe, ce qui a première vue crée une
confusion pour Apache. Il n'en est rien, car ces blocs ne seront interrogés que lorsque
la directive NameVirtualHost du même nom qu'eux aura trouvé une correspondance vis
à vis de la requête en entrée. Cette directive est donc indispensable dans le cas d'un
hébergement virtuel se basant sur les noms et elle ne doit pas amener à des situations
ambiguës car elle est testée dès l'entrée de la requête.
Une ou plusieurs IP, un ou plusieurs ports, peu importe : si un hébergement basé sur le
nom d'hôte est utilisé, NameVirtualHost est indispensable.
Même avec une seule IP, on peut aussi parler "d'hébergement par IP et par nom", une IP,
il en existe de toute façon toujours au moins une.
Voyons un dernier exemple plus complexe d'un serveur disposant de deux adresses IP : 192.168.0.1 et 192.168.0.2.
En appliquant les principes décrits auparavant, tout est clair :
Exemple plus complexe d'hébergement virtuel à plusieurs IP/ports et plusieurs noms
Listen 80
Listen 81
# Le serveur DefaultServer sera utilisé si et seulement si
# aucune des directives NameVirtualHost futures ne trouvent correspondance
# par rapport au couple IP/port de la requête en entrée
ServerName DefaultServer
DocumentRoot /var/www
# Si la requête arrive sur 192.168.0.1:80
NameVirtualHost 192.168.0.1:80
# premier site : server1, *mais aussi* le site qui sera servi par défaut
# pour le couple 192.168.0.1:80 si un nom mène dessus sans être déclaré dans un VirtualHost
<VirtualHost 192.168.0.1:80>
ServerName server1
DocumentRoot /var/www1
</VirtualHost>
# deuxième site : server2, le DNS devrait alors le faire pointer vers 192.168.0.1,
# sinon il ne sera jamais atteignable à moins de le deviner
<VirtualHost 192.168.0.1:80>
ServerName server2
DocumentRoot /var/www2
</VirtualHost>
# Si la requête arrive sur 192.168.0.1:81
NameVirtualHost 192.168.0.1:81
# premier site : server3, *mais aussi* le site qui sera servi par défaut
# pour le couple 192.168.0.1:81 si un nom mène dessus sans être déclaré dans un VirtualHost
<VirtualHost 192.168.0.1:81>
ServerName server3
DocumentRoot /var/www3
</VirtualHost>
<VirtualHost 192.168.0.1:81>
- 10 Copyright © 2009 - Julien PAULI. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,
documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
http://julien-pauli.developpez.com/tutoriels/apache/vhosts/
Conception détaillée d'hôtes virtuels sous Apache par Julien Pauli (Tutoriaux,
articles et conférences PHP, développement web open source) (Blog)
Exemple plus complexe d'hébergement virtuel à plusieurs IP/ports et plusieurs noms
ServerName server4
DocumentRoot /var/www4
</VirtualHost>
# Si la requête arrive sur 192.168.0.2:81
NameVirtualHost 192.168.0.2:81
# premier site : server5, *mais aussi* le site qui sera servi par défaut
# pour le couple 192.168.0.2:81 si un nom mène dessus sans être déclaré dans un VirtualHost
<VirtualHost 192.168.0.2:81>
ServerName server5
DocumentRoot /var/www5
</VirtualHost>
Suivons le guide : http://server1 mène vers /var/www1 à condition que le domaine server1 soit routé vers 192.168.0.1
dans le DNS.
http://server2 mène vers /var/www2 à condition que le domaine server2 soit routé vers 192.168.0.1 dans le DNS.
http://server3:81 mène vers /var/www3 à condition que le domaine server3 soit routé vers 192.168.0.1 dans le DNS.
http://server3 mène vers /var/www1 (server1) car server3 est pointé par le DNS sur 192.168.0.1 menant à la requête
"192.168.0.1:80", c'est donc cette directive NameVirtualHost qui la prend en charge http://server4:81 mène vers /
var/www4 à condition que le domaine server4 soit routé vers 192.168.0.1 dans le DNS.
http://server5:81 mène vers /var/www5 à condition que le domaine server5 soit routé 192.168.0.2 dans le DNS.
http://server5 mène vers /var/www (DefaultServer) car le couple IP/port 192.168.0.2:80 n'a aucune correspondance
NameVirtualHost
etc etc. C'est tout à la fois simple et logique.
Un fichier "hosts" (ou un enregistrement dans le DNS) comme le suivant est donc correct :
un fichier hosts en accord avec la configuration d'Apache
192.168.0.1 server1 server2 server3 server4
192.168.0.2 server5
Dès que le nom d'hôte intervient (hébergement virtuel basé sur les noms), le DNS possède
une place primordiale. Il doit être en toute logique en corrélation avec le mapping que fait
Apache. Pour le "simuler" lors de tests, le fichier /etc/hosts peut être édité en conséquence.
Si le DNS ne pointe pas comme il faut, rappelez vous qu'Apache aiguille d'abord l'IP/port
via NameVirtualHost puis cherche un bloc <VirtualHost> en regardant les ServerName,
si aucun ne correpond : le premier bloc <VirtualHost> est sélectionné.
Dans cet exemple-là, une requête vers http://une_ip_que_le_serveur_ecoute mène
systématiquement vers le serveur par défaut, car même si une des directives
NameVirutalHost va aiguiller cette IP, aucun bloc <VirtualHost> sous-jacent ne déclare
un ServerName correspondant exactement à cette IP.
Rappelons qu'une requête HTTP utilisant l'IP directement, possède comme en-tête Host:
(donc comme "nom de serveur") l'IP elle-même.
- 11 Copyright © 2009 - Julien PAULI. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,
documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
http://julien-pauli.developpez.com/tutoriels/apache/vhosts/
Conception détaillée d'hôtes virtuels sous Apache par Julien Pauli (Tutoriaux,
articles et conférences PHP, développement web open source) (Blog)
IV-B - Récapitulatif et considérations de sécurité
Schéma de routage des hôtes virtuels d'Apache
Une erreur de DNS, ou l'oubli du fait que quelqu'un peut accéder à http://une_adresse_ip
et non pas http://un_nom_de_domaine peut mener à des catastrophes.
N'oubliez jamais qu'une simple session telnet permet d'écrire à la main la requête HTTP
et donc de forger n'importe quel "Host:" pour toute IP
Regardez cette configuration :
un exemple peu sécurisé, sauf si on sait parfaitement ce que l'on fait
Listen *:80
ServerName DefaultServer
DocumentRoot /var/www
NameVirtualHost 192.168.0.1:80
<VirtualHost 192.168.0.1:80>
ServerName server1
DocumentRoot /var/www1
</VirtualHost>
<VirtualHost 192.168.0.1:80>
- 12 Copyright © 2009 - Julien PAULI. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,
documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
http://julien-pauli.developpez.com/tutoriels/apache/vhosts/
Conception détaillée d'hôtes virtuels sous Apache par Julien Pauli (Tutoriaux,
articles et conférences PHP, développement web open source) (Blog)
un exemple peu sécurisé, sauf si on sait parfaitement ce que l'on fait
ServerName server2
DocumentRoot /var/www2
</VirtualHost>
NameVirtualHost 192.168.0.2:80
<VirtualHost 192.168.0.2:80>
ServerName server3
DocumentRoot /var/www3
</VirtualHost>
L'administrateur doit clairement se focaliser sur le paramètre IP/port et supposer que le DNS peut tomber, être modifié,
ou que la requête HTTP peut être forgée. Ce qui suit n'est pas une bizarrerie : http://server2, dont le reverse DNS
donne comme IP 192.168.0.1 mènera sur server2, mais http://192.168.0.1 mènera sur server1, elle. On peut aussi
écrire la requête suivante:
Requête HTTP forgée
# telnet 192.168.0.1 80
HEAD / HTTP/1.1
Host: foo
Et on arrive sur server1 aussi, puisqu'aucun site n'a comme nom "foo".
Plus brutal : si helloworld.server2 existe dans le DNS et pointe vers 192.168.0.1, http://helloworld.server2 mènera
vers server1.
Pensez aussi HTTP1.0. Cette version du protocole (parlée très très rarement mais à prendre en compte), n'inclut pas
l'en-tête Host: nécessaire au fonctionnement des hôtes virtuels par noms. Apache définit ServerPath pour pallier ce
problème, mod_rewrite peut aussi jouer de sa magie dans une moindre mesure.
L'exemple que l'on traite possède aussi une grosse faiblesse : la directive Listen écoute toutes les IP. Si la machine
venait à changer d'IP pour une raison quelconque, c'est DefaultServer qui sera interrogé ! (Aucun NameVirtualHost
ne matche autre chose que 192.168.0.1). Attention là encore.
Ces "petites faiblesses" du système d'hébergement virtuel par noms peuvent être compensées par Apache via la
directive ServerAlias qui permet de donner d'autres noms au serveur. Corrigeons notre exemple :
exemple plus sécurisé
# Nous déclarons clairement le mapping réseau
# utilisé par Apache, pas d'embrouille ou de "magie" possible,
# pas de caractère * assez risqué
Listen 192.168.0.1:80
Listen 192.168.0.2:80
ServerName DefaultServer
DocumentRoot /var/www
NameVirtualHost 192.168.0.1:80
# catchall : celui-ci attrape l'accès par "http://192.168.0.1"
# et le redirige vers une page 403 (directive order)
<VirtualHost 192.168.0.1:80>
ServerName 192.168.0.1
DocumentRoot /var/www
<Directory /var/www>
order allow, deny
</Directory>
</VirtualHost>
#server1 mais aussi "nimporte-quoi.server1"
<VirtualHost 192.168.0.1:80>
ServerName server1
ServerAlias *.server1
- 13 Copyright © 2009 - Julien PAULI. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,
documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
http://julien-pauli.developpez.com/tutoriels/apache/vhosts/
Conception détaillée d'hôtes virtuels sous Apache par Julien Pauli (Tutoriaux,
articles et conférences PHP, développement web open source) (Blog)
exemple plus sécurisé
DocumentRoot /var/www1
</VirtualHost>
#server2 mais aussi "nimporte-quoi.server2"
<VirtualHost 192.168.0.1:80>
ServerName server2
ServerAlias *.server2
DocumentRoot /var/www2
</VirtualHost>
NameVirtualHost 192.168.0.2:80
# catchall
<VirtualHost 192.168.0.2:80>
ServerName 192.168.0.2
DocumentRoot /var/www
<Directory /var/www>
order allow, deny
</Directory>
</VirtualHost>
<VirtualHost 192.168.0.2:80>
ServerName server3
ServerAlias *.server3
DocumentRoot /var/www3
</VirtualHost>
On s'assure que les sous-domaines sont interprétés comme il faut et aussi que les accès par l'adresse IP mènent
vers une page d'erreur (403).
- 14 Copyright © 2009 - Julien PAULI. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,
documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
http://julien-pauli.developpez.com/tutoriels/apache/vhosts/
Conception détaillée d'hôtes virtuels sous Apache par Julien Pauli (Tutoriaux,
articles et conférences PHP, développement web open source) (Blog)
V - Exemple concret - complet
Exemple pratique concret. Le serveur considéré doit se comporter différemment selon qu'il soit interrogé en local ou
via le réseau. Aussi, il est serveur Web et proxy sur le port 8080.
L'exemple n'est pas si complet que cela : la configuration Apache prend rapidement beaucoup de pages, cet exemple
est simplement un peu plus détaillé.
N'oubliez pas que tout ne doit pas se trouver dans le fichier global httpd.conf, la directive Include permet de tout
séparer et de tout ranger convenablement.
# le serveur n'écoute 81 que pour des requêtes locales
Listen 127.0.0.1:81
Listen 80
Listen 8080
# PHP est configuré de manière globale
LoadModule php5_module modules/libphp5.so
AddType application/x-httpd-php .php
# catch-all server
NameVirtualHost *:80
<VirtualHost *:80>
ServerName julien
DocumentRoot /media/www/external
# PHP n'est pas interprété
AddType text/plain .php
DirectoryIndex none
ReadmeName /apache/footerext.shtml
HeaderName /apache/headerext.shtml
</VirtualHost>
# server pour 127.0.0.1 : accès local
NameVirtualHost 127.0.0.1:80
<VirtualHost 127.0.0.1:80>
ServerName jp
DocumentRoot /media/www
setEnv APP_MODE dev
Alias /sql /media/data/phpmyadmin
Script PUT /put.php
ReadmeName /apache/footer.shtml
HeaderName /apache/header.shtml
<Location /server-status>
SetHandler server-status
Order deny,allow
Deny from all
# 2 sécurités valent mieux qu'une
Allow from 127.0.0.1
</Location>
<Location /server-info>
SetHandler server-info
Order deny,allow
Deny from all
# 2 sécurités valent mieux qu'une
Allow from 127.0.0.1
</Location>
</VirtualHost>
# serveur pour 127.0.0.1 port 81
NameVirtualHost 127.0.0.1:81
<VirtualHost 127.0.0.1:81>
- 15 Copyright © 2009 - Julien PAULI. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,
documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
http://julien-pauli.developpez.com/tutoriels/apache/vhosts/
Conception détaillée d'hôtes virtuels sous Apache par Julien Pauli (Tutoriaux,
articles et conférences PHP, développement web open source) (Blog)
ServerName jp
DocumentRoot /media/www
# PHP5.3 tourne en CGI sur ce serveur
ScriptAlias /php/ "/usr/local/php53/bin/"
Action php5-fastcgi "/php/php-cgi53"
AddHandler php5-fastcgi .php
ReadmeName /apache/footer.shtml
HeaderName /apache/header.shtml
</VirtualHost>
# server sur le port 8080 : un proxy forward
NameVirtualHost *:8080
<VirtualHost *:8080>
ServerName proxy.jp
ProxyRequests On
ProxyVia On
AllowCONNECT 443 563
<Proxy *>
Order deny,allow
Allow from 192.168
Allow from 127.0.0.1
Deny from all
</Proxy>
# l'interrogation directe mènera vers un accès interdit
<directory />
Order allow,deny
Deny from all
</directory>
</VirtualHost>
- 16 Copyright © 2009 - Julien PAULI. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,
documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
http://julien-pauli.developpez.com/tutoriels/apache/vhosts/
Conception détaillée d'hôtes virtuels sous Apache par Julien Pauli (Tutoriaux,
articles et conférences PHP, développement web open source) (Blog)
VI - Les configurations plus complexes et les modules tiers
Apache propose un module : mod_vhost_alias, dont le but est de créer des VirtualHosts dynamiques en fonction
de paramètres dans l'URL.
Pour aller plus loin, il faudra se tourner vers des modules tiers. Au plus simple, mod_vhost_limit définit une seule
directive : MaxVhostClients dont le nom est plus qu'explicite. Si le nombre de clients par virtualhost est dépassé,
une erreur 503 est retournée.
Pour des besoins plus pointus, je vous invite à lire les documentations de
mod_qos ou
mod_cband qui
permettent notamment de contrôler très finement les ressources que chaque VirtualHost consomme.
D'autres modules existent encore "dans la nature", vous n'avez qu'à les télécharger, les compiler et les tester, ils ne
demandent que cela ;-) Rappelons aussi que leurs codes sources sont ouverts.
Remerciements à Hédhili Jaïdane pour ses relectures.
- 17 Copyright © 2009 - Julien PAULI. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,
documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
http://julien-pauli.developpez.com/tutoriels/apache/vhosts/