Skip to Content

Chapitre 7.5 — Vhosts multi-sites

⏱️ TL;DR — Un VPS, une IP, un port 443 — mais plusieurs sites. La magie s’appelle virtual host (vhost) : Nginx lit le server_name de chaque server block et aiguille la requête selon le domaine demandé. formacampus.fr va vers le front, api.formacampus.fr vers l’API Symfony, www.formacampus.fr redirige vers l’apex. On voit un fichier par site dans sites-available/ (activé par lien), le rôle du default_server (qui répond aux domaines non reconnus), et la redirection www → apex (ou l’inverse) — un petit server block dédié qui ne fait que rediriger. À la fin : un exemple multi-vhost complet pour FormaCampus.

🎯 Objectifs

  • Comprendre comment Nginx distingue plusieurs sites par le server_name.
  • Organiser un site par fichier dans sites-available/, activé par lien.
  • Configurer le default_server pour les domaines non reconnus.
  • Écrire une redirection www → apex propre.
  • Router un sous-domaine (api.) vers une app différente.
  • Assembler un multi-vhost front + API sur un seul VPS.

Comment Nginx distingue plusieurs sites

Toutes les requêtes arrivent sur la même IP et le même port 443. Comment Nginx sait-il si formacampus.fr doit aller vers le front et api.formacampus.fr vers l’API ? Grâce à l’en-tête HTTP Host que le navigateur envoie : il contient le domaine tapé. Nginx compare ce Host au server_name de chacun de ses server blocks et choisit celui qui correspond. C’est le principe du virtual host (ou name-based virtual hosting).

Chaque server block déclare pour qui il répond via server_name. Un seul Nginx, plusieurs sites, aiguillage par le nom.

# le front, sur le domaine principal (apex) server { listen 80; server_name formacampus.fr; location / { proxy_pass http://127.0.0.1:3000; # + les en-têtes du chapitre 7.4 } } # l'API, sur un sous-domaine server { listen 80; server_name api.formacampus.fr; location / { proxy_pass http://127.0.0.1:8000; # + les en-têtes } }

💡 Réflexe — Le server_name peut lister plusieurs noms (server_name formacampus.fr www.formacampus.fr;) et accepter des jokers (*.formacampus.fr pour tous les sous-domaines). Mais pour rester lisible et maîtriser chaque cas (redirections, certificats), on préfère un server block par rôle : un pour l’apex, un pour www (qui redirige), un par sous-domaine applicatif.

Un site par fichier, activé par lien

La convention Debian/Ubuntu (chapitre 7.2) prend tout son sens ici : un fichier par site dans sites-available/, activé par un lien symbolique dans sites-enabled/.

/etc/nginx/sites-available/ ├── formacampus # apex : le front Next (+ redirection www dedans ou à part) ├── api.formacampus # le sous-domaine API Symfony └── autre-projet # un autre site, désactivé pour l'instant
# activer front et API, laisser "autre-projet" inactif sudo ln -s /etc/nginx/sites-available/formacampus /etc/nginx/sites-enabled/ sudo ln -s /etc/nginx/sites-available/api.formacampus /etc/nginx/sites-enabled/ sudo nginx -t && sudo systemctl reload nginx

Avantage : chaque site est isolé dans son fichier (on le lit, le modifie, le désactive sans risque pour les autres), et l’activation est un simple lien à créer ou supprimer. La source de vérité reste dans sites-available/.

Le default_server : répondre à l’inconnu

Que se passe-t-il si quelqu’un pointe un domaine que tu ne gères pas vers ton IP, ou tape directement http://TON_IP/ ? Sans consigne, Nginx répond avec le premier server block venu — souvent pas celui que tu veux exposer. Tu peux désigner explicitement un server comme default_server : c’est lui qui répond quand aucun server_name ne correspond.

# attrape-tout : répond aux domaines non reconnus et aux accès par IP nue server { listen 80 default_server; server_name _; # "_" ne matche rien : ce bloc n'est là que par défaut return 444; # ferme la connexion sans répondre (444 = non standard Nginx) }

Détails : listen 80 default_server; marque ce bloc comme celui par défaut pour le port 80. return 444; est un code spécifique à Nginx qui coupe la connexion sans envoyer de réponse — pratique pour ne rien offrir aux scanners qui frappent à l’IP nue avec un Host bidon. Tu pourrais aussi renvoyer une vraie page ou une 404 ; le principe est de contrôler ce qui répond à l’inconnu plutôt que de laisser le hasard décider.

🔒 Sécurité — Sans default_server maîtrisé, ton VPS répond à n’importe quel Host, y compris des domaines que des inconnus font pointer vers ton IP (domain fronting, empoisonnement de cache, apparition dans des listes douteuses). Poser un default_server qui ferme (444) ou renvoie une 404 neutre, c’est refuser de servir ce que tu n’as pas explicitement déclaré. Un vhost par domaine connu, et une porte fermée pour tout le reste.

La redirection www → apex

Tu veux une seule URL canonique : soit formacampus.fr (apex), soit www.formacampus.fr — pas les deux qui servent le même contenu (mauvais pour le SEO, la confusion des cookies, les certificats). La pratique courante : choisir l’apex comme canonique et rediriger www vers lui (ou l’inverse selon ta préférence). On dédie un petit server block qui ne fait que rediriger.

# www -> apex : ce bloc ne sert aucun contenu, il redirige server { listen 80; server_name www.formacampus.fr; return 301 https://formacampus.fr$request_uri; }

Ce que ça fait : ce server répond uniquement pour www.formacampus.fr, et pour toute requête il renvoie un 301 (redirection permanente) vers le même chemin sur l’apex. $request_uri conserve le chemin et la query string d’origine : www.formacampus.fr/cours/42?x=1 redirige vers https://formacampus.fr/cours/42?x=1. On vise directement https:// pour envoyer le visiteur sur l’URL finale sécurisée en une seule redirection.

⚠️ Piège — Servir le même contenu sur formacampus.fr et www.formacampus.fr (deux server blocks identiques, ou un server_name qui liste les deux avec le même root). Résultat : contenu dupliqué (pénalité SEO), cookies qui ne suivent pas entre les deux domaines, et certificats à gérer en double. Choisis un canonique, redirige l’autre en 301. Une seule vérité par contenu.

💡 Réflexe — Le choix apex vs www est surtout une question de cohérence : décide une fois, redirige l’autre, et garde ce choix partout (liens, sitemap, config du framework). Certains préfèrent www car il facilite certains réglages DNS/CDN sur l’apex ; d’autres préfèrent l’apex, plus court. Peu importe lequel — l’important est qu’il n’y en ait qu’un.

Sous-domaine applicatif : api. vers Symfony

Un sous-domaine comme api.formacampus.fr est juste un autre server_name — mais on le proxifie vers une app différente (ici l’API Symfony sur le port 8000, servie via PHP-FPM en Partie 10, ou un proxy simple si l’API expose son propre serveur). Côté DNS, tu auras créé un enregistrement pour api (Partie 6) pointant vers la même IP.

server { listen 80; server_name api.formacampus.fr; location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }

🧭 Sur FormaCampus — Deux stratégies coexistent selon les projets : soit l’API sur un sous-domaine dédié (api.formacampus.fr), soit sur un préfixe de chemin de l’apex (formacampus.fr/api/, avec deux location dans le même server). FormaCampus a choisi le sous-domaine api.formacampus.fr pour l’API Symfony : ça sépare nettement les cookies, simplifie le CORS et permet de gérer front et API indépendamment (certificats, déploiements, logs distincts). L’apex sert le front Next (port 3000), api. sert l’API Symfony (port 8000), www. redirige vers l’apex — trois server blocks, trois fichiers dans sites-available/.

Exemple multi-vhost complet

Voici la config assemblée pour FormaCampus — l’apex avec redirection www, le sous-domaine API, et le default_server qui ferme la porte aux domaines inconnus. (Le TLS/HTTPS arrive en Partie 8 ; ici on reste en HTTP pour se concentrer sur l’aiguillage.)

# --- Attrape-tout : ferme la porte aux domaines non gérés --- server { listen 80 default_server; server_name _; return 444; } # --- www -> apex --- server { listen 80; server_name www.formacampus.fr; return 301 http://formacampus.fr$request_uri; } # --- Apex : le front Next.js --- server { listen 80; server_name formacampus.fr; # médias de cours servis en statique par Nginx location /media/ { alias /var/www/formacampus/media/; expires 1y; add_header Cache-Control "public"; } # tout le reste : proxy vers le front Next location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } # --- Sous-domaine : l'API Symfony --- server { listen 80; server_name api.formacampus.fr; location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }

📚 La doc — Le fonctionnement du choix de server (l’ordre : listen, puis server_name, puis default_server) est décrit dans la page « How nginx processes a request » de nginx.org. Utile quand un site « part au mauvais endroit » : elle explique exactement l’algorithme de sélection du bloc, jokers et priorités compris.

✏️ Exercices

Exercice 1 — Trois rôles, trois blocs. Sur un VPS, tu veux : monsite.fr → app Node sur 3000 ; www.monsite.fr → redirigé vers monsite.fr ; admin.monsite.fr → app d’admin sur 5000. Décris (ou écris) les trois server blocks nécessaires, en une phrase chacun.

✅ Solution

  1. server_name www.monsite.fr; avec return 301 https://monsite.fr$request_uri;redirige www vers l’apex en conservant le chemin. 2. server_name monsite.fr; avec location / { proxy_pass http://127.0.0.1:3000; ... } — sert le site principal. 3. server_name admin.monsite.fr; avec location / { proxy_pass http://127.0.0.1:5000; ... } — sert l’admin depuis une autre app. Chacun dans son fichier sites-available/, activé par lien. (Idéalement, un default_server en plus pour l’inconnu.)

Exercice 2 — L’IP nue répond. Tu tapes http://TON_IP/ (l’IP brute, sans domaine) et tu tombes sur ton site de front. Pourquoi, et comment faire pour qu’une requête sans domaine reconnu ne serve pas le front ?

✅ Solution

Sans default_server explicite, Nginx sert le premier server block (ou celui marqué par défaut) quand aucun server_name ne matche le Host — ici, ton front. Pour l’éviter, ajoute un server { listen 80 default_server; server_name _; return 444; } : il capte tout Host non reconnu (y compris l’IP nue) et ferme la connexion, au lieu de laisser fuiter ton front. Tes vrais sites gardent leur server_name précis et ne sont servis que sur leur domaine.

🧠 Quiz de révision

1. Comment Nginx sait-il quel site servir quand plusieurs partagent la même IP ?

Il lit l’en-tête HTTP Host (le domaine tapé par le visiteur) et le compare au server_name de chaque server block, puis sert celui qui correspond. C’est le name-based virtual hosting.

2. À quoi sert le default_server ?

À désigner le server block qui répond quand aucun server_name ne correspond au Host (domaine inconnu pointé vers l’IP, accès par IP nue). On y met souvent un return 444; (ferme la connexion) ou une 404 neutre pour ne rien servir d’involontaire.

3. Comment rediriger www.monsite.fr vers monsite.fr proprement ?

Un server block dédié server_name www.monsite.fr; avec return 301 https://monsite.fr$request_uri;. Le 301 est une redirection permanente, $request_uri conserve le chemin et la query string. Ce bloc ne sert aucun contenu, il ne fait que rediriger.

4. Pourquoi ne pas servir le même contenu sur l’apex ET sur www ?

Parce que ça crée du contenu dupliqué (pénalité SEO), des cookies qui ne suivent pas entre les deux domaines, et un doublon de certificats à gérer. On choisit un canonique et on redirige l’autre en 301.

5. Comment router api.formacampus.fr vers une app différente de l’apex ?

Avec un server block dont le server_name est api.formacampus.fr et un location / { proxy_pass http://127.0.0.1:8000; ... } pointant vers l’app API (avec les en-têtes X-Forwarded-*). Côté DNS, un enregistrement pour api pointe vers la même IP.


Chapitre suivant : Perf, cache & logs — compression, cache, uploads, et lire les logs pour déboguer les erreurs.

Last updated on