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

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