# Un multisite headless de 500 sites : un frontend, cinq cents configs

> Architecture d'un front unique consommant un multisite WordPress de grande taille, avec la gestion des règles Cloudflare propres à chaque commune desservie.

- Auteur : WordPress Développement
- Publié le : 2024-01-28
- Mis à jour le : 2024-01-28
- Catégorie : Headless &amp; API
- URL : https://www.wpmoderne.fr/headless/multisite-headless-500-sites-un-frontend/

## L’essentiel

- Un frontend unique peut servir des centaines de sous-sites à condition de router dynamiquement par domaine
- Chaque sous-site multisite conserve ses propres réglages sans dupliquer le code du frontend
- Les règles de cache Cloudflare doivent être paramétrées par variable plutôt que réécrites pour chaque site

Cinq cents communes, cinq cents domaines, un seul frontend Next.js à maintenir : voilà le pari architectural retenu pour la refonte du réseau de sites d'une fédération de collectivités locales, jusque-là composé d'installations WordPress indépendantes maintenues au cas par cas par chaque commune adhérente.

Le multisite WordPress permettait déjà de centraliser la gestion de contenu côté back-office, chaque commune disposant de son propre sous-site dans le réseau. La question restait entière côté frontend : fallait-il déployer un frontend distinct par commune, ou un frontend unique capable de s'adapter dynamiquement selon le domaine appelé ?

## Le choix d'un frontend unique multi-tenant

Un frontend unique, capable de déterminer à l'exécution quel sous-site multisite interroger selon le nom de domaine de la requête entrante, a été retenu plutôt que 500 déploiements distincts. Cette approche évite la duplication de code et centralise les mises à jour de sécurité ou de fonctionnalités sur un seul dépôt :

```
arborescence-frontend/
├── middleware.ts          # résolution du domaine vers l'identifiant de sous-site
├── lib/
│   └── resoudre-site.ts   # mapping domaine ↔ sous-site WordPress
├── app/
│   └── [...slug]/
│       └── page.tsx       # page générique, contenu résolu dynamiquement
└── config/
    └── sites.json         # 500 entrées : domaine, sous-site, thème visuel
```

Le fichier `sites.json`, régulièrement synchronisé avec la liste réelle des sous-sites du multisite via l'API REST, associe chaque nom de domaine à l'identifiant numérique du sous-site correspondant, ainsi qu'à un identifiant de thème visuel choisi parmi un nombre restreint de variantes graphiques.

## Router chaque requête vers le bon sous-site

> L'essentiel à retenir : Un frontend unique peut servir des centaines de sous-sites à condition de router dynamiquement par domaine ; Chaque sous-site multisite conserve ses propres réglages sans dupliquer le code du frontend ; Les règles de cache Cloudflare doivent être paramétrées par variable plutôt que réécrites pour chaque site

```
// middleware.ts
export function middleware(request) {
  const hostname = request.headers.get('host');
  const site = configSites.find((s) => s.domaine === hostname);

  if (!site) {
    return NextResponse.rewrite(new URL('/404-domaine-inconnu', request.url));
  }

  request.headers.set('x-site-id', site.id.toString());
  return NextResponse.next({ request });
}
```

Chaque page interroge ensuite l'API REST WordPress en ciblant explicitement le bon sous-site, via son URL propre au réseau multisite (`https://reseau-communes.fr/commune-nom/wp-json/wp/v2/...`), déterminée à partir de l'identifiant résolu dans le middleware.

## Gérer les règles Cloudflare par variable plutôt que par site

Réécrire une règle de cache Cloudflare pour chacune des 500 communes n'était opérationnellement pas envisageable. Les règles ont donc été écrites de façon générique, en s'appuyant sur des expressions qui s'appliquent à l'ensemble des domaines du réseau via une règle de correspondance par motif plutôt que par domaine explicite :

| Règle | Portée | Effet |
| --- | --- | --- |
| Cache Everything | Tous les domaines du compte Cloudflare Enterprise | Mise en cache des pages HTML statiques |
| Bypass sur /api/* | Motif de chemin commun à tous les sites | Jamais de cache sur les routes API internes |
| Purge par tag | Un tag de cache par sous-site | Purge ciblée sans affecter les 499 autres communes |

Le point le plus délicat a été la purge de cache ciblée : publier un contenu sur la commune de Sainte-Radegonde ne doit jamais déclencher une purge globale affectant les 499 autres sites. Chaque requête mise en cache reçoit un tag Cloudflare correspondant à l'identifiant du sous-site, permettant une purge chirurgicale déclenchée par le webhook de publication WordPress propre à ce sous-site précis.

## Ce que cette architecture facilite

- Un correctif de sécurité ou une évolution de fonctionnalité déployés une seule fois pour l'ensemble des 500 sites
- Une cohérence visuelle minimale garantie même si chaque commune personnalise son contenu
- Un onboarding technique simplifié pour une nouvelle commune : ajout d'une ligne dans `sites.json`, sans nouveau déploiement

## Ce que cette architecture ne couvre pas

Ce choix d'architecture s'est concentré sur la question du routage multi-domaine et de la gestion différenciée du cache. Les aspects de sécurité propres à un réseau multisite de cette taille (isolation entre sous-sites, gestion des rôles par commune) ont fait l'objet d'un audit distinct, non traité dans cet article.

## Notre verdict

Un frontend unique pour 500 sites reste tenable à condition d'accepter une contrainte structurante dès la conception : aucune personnalisation ne doit jamais passer par une branche de code spécifique à une commune. Tout ce qui varie d'un site à l'autre doit rester une donnée de configuration, jamais du code, sous peine de retrouver, au bout de quelques mois, 500 variantes divergentes du même frontend.
