Catch-all DNS, VirtualHost et on fait mumuse avec les noms de sous-domaines

closeCet article a été publié il y a 12 ans , il est donc possible qu’il ne soit plus à jour. Les informations proposées sont donc peut-être expirées.

Salut lecteur,

Un bail que je n’ai rien écrit sur ce blog, la faute à un petit projet perso qui me prend un peu de temps chez moi, semble-t-il.

L’idée

Ceci dit, je voulais laisser une trace de cette manip’ qui consiste à autoriser n’importe quel nom de sous-domaine d’un domaine que vous possédez, exemple le fameux « mon_domaine.com » en ayant la possibilité d’envoyer vers un site ou un autre (au sens, un VirtualHost/DocumentRoot ou un autre) suivant le nom de sous-domaine appelé, la liste de ces sous-domaines étant potentiellement illimitée.

Bon, OK, pour la formulation, c’est pas forcément limpide. Un exemple concret : mon_domaine.com est une société qui propose un service web personnalisé pour ses clients. Le gérant de la chose décide de mettre en place les sous-domaines suivants :

  • www.mon_domaine.com
  • demo.mon_domaine.com ; même mieux : une liste de plusieurs instances de démo : demo1, demo2 etc
  • une série infinie de clientXXX.mon_domaine.com, exemples : http://client.mon_domaine.com, http://autreclient.mon_domaine.com

On voudrait que le « www » renvoie vers le site « commerçant », que les « demoX » renvoient vers le service en mode démo (chacun étant une instance différente, une base de données différente, par exemple) et que chaque « clientXXX » pointe vers le vrai outil, dont le code est commun pour tous les clients, là aussi avec une peut-être une base de donnée différente par client.
Pourquoi ne pas juste passer un paramètre dans l’URL pour indiquer le client ? car dans mon cas, je préférais faire des sous-domaines différents, ça enlève un tas d’épines du pied en ce qui concerne la gestion des sessions, gestion qui est liée au nom complet du domaine, pas à ce qu’il y a après le « .com », comme un http://….com/?client=xxx

On a toujours la possibilité de faire n’importe quelle crassouillerie pour avoir un script d’index[.php] qui dirige vers tel ou tel code/outil suivant l’URL appelée. Pourquoi pas. Mais lorsque l’un des outils est par exemple un outil dont on ne veut pas modifier l’index[.php], ça peut poser problème. Exemple, le « www » est un wordpress, le reste un outil maison. Je ne veux pas avoir à jouer avec le htaccess du WordPress, ce genre de choses. Bref, je scinde les mondes avant et je limite les risques de passage de l’un à l’autre.

Bon, ça y est ? le contexte est clair ?
Voici la solution que je trouve la plus élégante.

Côté DNS : catch-all

Si le gérant de votre nom de domaine le permet, créez d’abord un enregistrement DNS type A ou CNAME nommé « * » et pointant vers votre serveur. Exemple : « *.mon_domaine.com CNAME mon_domaine.com« .
Tous ne le permettent sûrement pas. Je sais au moins que OVH le tolère, il suffit de mettre « * » comme nom de sous-domaine.
Ensuite, on peut tester avec la commande « host/nslookup nimportequoi.mon_domaine.com« .

Côté Apache : identification du sous-domaine demandé

Avec la manip’ DNS, on est sûr que nimportequoi.mon_domaine.com renvoie bien vers le serveur. Reste à trier au niveau Apache (plutôt qu’au niveau code derrière, comme j’ai expliqué plus haut).
Déjà pour être sûr que ça marche, une conf simpliste consiste à créer un unique VirtualHost comme ceci :

< VirtualHost *>
        ServerName mon_domaine.com
        ServerAlias *.mon_domaine.com
        ServerAdmin webmaster@mon_domaine.com
        ...
        DocumentRoot /quelque/part/
        ...
< /VirtualHost>

Avec ça, vous pouvez appeler http://peu_importe.mon_domaine.com ou http://www.mon_domaine.com et atterrir sur le même VirtualHost/DocumentRoot, le même « site ».

Ensuite, on améliore pour scinder les 3 jeux de sous-domaines. Supprimez le VirtualHost d’avant et mettez :

< VirtualHost *>
        ServerName www.mon_domaine.com
        ServerAdmin webmaster@mon_domaine.com
        ...
        DocumentRoot /quelque/part/le/site/www/
        ...
< /VirtualHost>
< VirtualHost *>
        ServerAlias demo*.mon_domaine.com
        ServerAdmin webmaster@mon_domaine.com
        ...
        DocumentRoot /quelque/part/le/code/des/sites/de/demo/
        ...
< /VirtualHost>
< VirtualHost *>
        ServerName mon_domaine.com
        ServerAlias *.mon_domaine.com
        ServerAdmin webmaster@mon_domaine.com
        ...
        DocumentRoot /quelque/part/le/code/des/sites/de/production/
        ...
< /VirtualHost>

Bah voilà, c’est tout, les 3 répertoires mentionnés dans les DocumentRoot sont indépendants.
Il ne resterait plus que dans l’outil, à récupérer le nom du sous-domaine (exemple à partir de $_SERVER['SERVER_NAME'] en PHP) et faire le traitement adéquat.

En espérant que ça serve à quelqu’un,

A la prochaine !

12 comments

  1. P*****! Merci.
    Ça fait longtemps que j’attendais une explication simple de la gestion des sous domaine. Mille Mercis

    1. de rien
      Et ça marche !!!
      (bon au moins chez moi 😉 et pourvu que je n’ai pas fait d’erreur en anonymisant les extraits de conf ; m’enfin le gros de l’idée est là en tout cas)

  2. J’ai juste pas compris la dernière phrase !

    Il ne resterait plus que dans l’outil, à récupérer le nom du sous-domaine (exemple à partir de $_SERVER[‘SERVER_NAME’] en PHP) et faire le traitement adéquat.

    1. Certes, je précise :
      Sur les sites de clients ou démo dans mon exemple, on veut quand même pouvoir probablement présenter le site DU client en question (SON logo, se brancher sur SA base de données etc). On ne fait sûrement pas tout ça pour avoir le même site quel que soit le sousdom.mondomaine.com
      Donc, je dis en gros, si le code PHP derrière les sites demo/client est un code maison, on récupèrera le sous-domaine appelé par exemple :
      $sub = explode (‘.’,$_SERVER[‘SERVER_NAME’], 2);
      switch ($sub[0]) { case ‘client1’…. case ‘autreclient’ } etc … ou une requête basée sur ce nom. Suivant ce qu’on en fait.
      (il faut aussi s’assurer qu’il n’y a pas de sous-sous-domaine, chercher s’il y a un point dans subhost[0])
      Voilà, c’est plus clair ?

  3. Quid du dossier différent par client ?

    Comment se passe la spécification pour dire que :
    machin1.dom.tld renvoie vers /home/machin1/public_html (par exemple)
    machin2.dom.tld renvoie vers /home/machin2/public_html

    et que se passe t il si on appelle machin3 et que le dossier en question n’existe pas ?

    Autre chose, le catch-all est il obligatoire ? Il ne me semble pas avoir utilisé ca sur mon hébergement OVH, et pourtant, j’utilise la gestion de sous domaine (uniquement) via apache/vhost.

    1. Salut,
      Je ne sais pas si on peut mettre un truc dynamique dans DocumentRoot, mais je doute.
      Perso, je ferais plutôt VirtualHost machin*.dom.tld => DocumentRoot /home/machin/public_html
      Et un index.[html|php|whatever] unique dans ce répertoire qui détecte le nom machinX et fait une redirection vers /home/machin/public_html/machinX/ (niveau OS)
      Dans mon cas, le code est le même pour tous les machinX, tout est variabilisé pour refléter les spécificités de chaque X ; l’outil étant un outil commun.
      Tout ça n’est qu’une question dépendant de ce qu’on a à faire pour chaque sous-domaine : un gros script de redirection ? un outil commun personnalisé suivant le nom ? etc

      Pour le catch-all, je dirais que si personne n’est capable de résoudre le nom nimportequoi.com.tld, comment veux-tu que TON apache y réponde. C’est pas pcqu’on est sur un sous-domaine de com.tld qu’il faut aller voir l’IP de com.tld et son Apache.

  4. Je vais regarder ca à tête reposé en rentrant, mais, je fais mes vhosts en fonction de l’IP de mon serveur …

    ServerName machin1.dom.tld
    DocumentRoot /home/machin1/public_html
    ..

    ServerName machin2.dom.tld
    DocumentRoot /home/machin2/public_html
    ..

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.