Ceci est la partie 2 de ma série de migration de WordPress en mode headless. Le déploiement de WordPress headless est là que les vrais problèmes commencent, parce que DNS, SSL, les images, les formulaires et les redirections se cassent tous de façons différentes. Dans la partie 1, j’ai reconstruit le frontend en une journée avec Claude Code, Stitch MCP et Next.js. Dans cet article, je montre les problèmes de déploiement que j’ai rencontrés, comment je les ai corrigés, et pourquoi l’IA avait encore besoin d’un jugement humain.
Le problème de déploiement de WordPress headless dont personne ne parle
Construire le frontend, c’est la partie facile. D’après mon expérience, le déploiement de WordPress headless devient difficile dès que vous séparez un site en deux systèmes : Vercel pour le frontend et WordPress pour le backend. Vous n’avez plus une pile simple. Vous avez DNS, des certificats, des URL de médias, des endpoints REST, et un accès admin qui tirent tous dans des directions différentes.
Quand `optagonen.se` est passé sur Vercel, chaque requête qui, auparavant, allait vers WordPress a commencé à atterrir sur le nouveau frontend à la place. Cela a cassé GraphQL, les uploads, Contact Form 7 et l’accès admin d’un seul coup. Si vous prévoyez votre propre déploiement de WordPress headless, vous devez concevoir ces points de rupture avant de changer votre DNS.
J’ai testé cela sur une migration de production réelle, pas dans un bac à sable. La leçon était claire : le code a été fait vite, mais l’infrastructure a pris du temps.
Séparer le DNS pour un déploiement de WordPress headless
La solution la plus propre a été de donner à WordPress son propre sous-domaine : `wp.optagonen.se`. Cela a séparé le frontend et le backend sans m’obliger à tout faire passer en reverse proxy via une seule origine. Cela a aussi rendu l’architecture plus facile à comprendre quand il fallait dépanner SSL et la diffusion des médias.
| Domaine | Pointe vers | But |
|---|---|---|
| --- | --- | --- |
| `optagonen.se` | Vercel | Frontend dans Next.js |
| `wp.optagonen.se` | Serveur d’origine | Backend WordPress |
J’ai ajouté `wp.optagonen.se` comme alias dans Hestia, j’ai pointé l’enregistrement DNS A vers l’IP du serveur d’origine, et j’ai mis à jour la variable d’environnement du frontend :
Cette partie est simple sur le papier. En pratique, le déploiement de WordPress headless a déclenché une réaction en chaîne. Chaque système qui supposait l’ancien domaine avait besoin d’une nouvelle cible.
Déploiement de WordPress headless et échecs de certificats SSL
La première chose qui a cassé, c’était SSL. L’ancien certificat Let's Encrypt ne couvrait que `optagonen.se` et `www.optagonen.se`, donc `https://wp.optagonen.se` a échoué immédiatement. C’est un comportement attendu. Let's Encrypt valide la propriété du domaine par hostname, et le navigateur refusera la connexion si le certificat ne correspond pas.
Le renouvellement intégré de Hestia a échoué parce qu’il essayait encore de valider le domaine principal via HTTP-01, mais le domaine principal pointait désormais vers Vercel. Certbot a échoué pour une autre raison : Hestia a intercepté le défi ACME et a renvoyé sa propre empreinte (thumbprint) au lieu de celle de Certbot. C’est le genre de conflit que l’IA ne peut pas déduire à partir de principes de base. Il faut savoir comment le panneau se comporte.
Je l’ai corrigé en déplaçant temporairement la configuration du défi ACME de Hestia hors du chemin d’inclusion nginx, en émettant un certificat uniquement pour `wp.optagonen.se`, puis en copiant les fichiers renouvelés de nouveau dans le répertoire SSL de Hestia. J’ai aussi ajouté un hook de renouvellement pour que le processus reste automatique.
Pour la confiance, je me suis appuyé sur la documentation officielle de Let's Encrypt et Certbot. Cela a aidé à confirmer le flux ACME avant de toucher à nouveau la production.
Pourquoi le déploiement de WordPress headless a rejeté le sous-domaine
Une fois SSL en place, WordPress n’a toujours pas accepté le nouvel hôte. Au lieu de renvoyer des données GraphQL, il a redirigé vers `/wp-signup.php`. Cela m’a indiqué que WordPress n’aimait pas l’en-tête Host entrant.
La correction a été une seule directive nginx :
Cette ligne a fait en sorte que WordPress se comporte comme si les requêtes venaient encore du domaine principal, tandis que le navigateur restait sur `wp.optagonen.se`. Dans un déploiement de WordPress headless, ce type de normalisation d’hôte compte plus que ce que les gens pensent. WordPress est très opiniâtre au sujet des URLs du site.
J’ai vu cette même catégorie de problème apparaître dans d’autres migrations aussi. Le frontend fonctionne, le backend répond, puis un en-tête Host mal aligné casse silencieusement le flux de session.
Les images ont cassé après le déploiement de WordPress headless
Après le déploiement, chaque image renvoyait une erreur 502. Cela s’est produit parce que les URL de médias de WordPress pointaient encore vers `/wp-content/uploads/...`, et que ces chemins se résolvaient maintenant contre Vercel au lieu du serveur d’origine. Dans ma configuration, le problème venait de deux endroits : des URLs codées en dur dans des fichiers statiques et des URLs dynamiques renvoyées par WPGraphQL.
J’ai d’abord corrigé les URLs codées en dur. J’ai remplacé chaque référence `https://optagonen.se/wp-content/uploads/` par `https://wp.optagonen.se/wp-content/uploads/` sur six fichiers. Cela couvrait environ 70 chemins d’images.
Ensuite, j’ai corrigé les URLs GraphQL dynamiques avec une réécriture Next.js :
Cela a gardé le frontend propre et a évité de réécrire les données médias à l’intérieur de WordPress. Cela a aussi rendu le déploiement de WordPress headless plus maintenable, parce que le navigateur demande toujours le même chemin tandis que le serveur gère le proxying.
Si vous voulez aller plus loin dans ce type de conception de système, je vous recommande de lire mon workflow de migration WordPress alimenté par l’IA→ et mon pipeline de contenu multi-agent→. Ces articles montrent comment je structure l’infrastructure et les systèmes de contenu autour de l’automatisation.
Formulaires de contact, IDs, et le dernier piège de déploiement
Contact Form 7 semblait aller bien au début, mais le formulaire a cessé de fonctionner parce que l’ID dans le frontend était incorrect. L’ID de formulaire par défaut était `1`, mais le vrai formulaire dans WordPress était `8`. Un rapide contrôle via l’API l’a confirmé.
C’était un petit correctif, mais il compte. Dans un déploiement de WordPress headless, un seul ID erroné peut faire paraître un formulaire fonctionnel comme cassé, même quand le backend est sain. J’ai défini `CF7_FORM_ID=8` et le formulaire est revenu en ligne immédiatement.
C’est pour cela que je teste toujours le flux complet manuellement :
Cette séquence détecte les problèmes plus vite que de deviner uniquement à partir des logs.
Ce que l’IA a aidé à faire et ce qu’elle a manqué
Claude Code m’a aidé à aller vite, mais il n’a pas remplacé la compréhension. Il a géré très bien les parties répétitives : chercher dans les fichiers de configuration, générer des snippets nginx, aider avec les commandes certbot, et remplacer les URLs d’images en masse. Il a aussi gardé la chaîne d’erreurs en mémoire, ce qui m’a fait gagner du temps quand un correctif en créait un autre.
Cependant, l’IA ne pouvait pas décider de l’architecture complète. Elle ne savait pas que Hestia allait intercepter les requêtes ACME. Elle ne savait pas quand utiliser un sous-domaine plutôt qu’un reverse proxy. Et elle ne savait pas l’ordre des opérations qui évite un downtime.
C’est là la vraie valeur de l’IA dans un déploiement de WordPress headless : elle accélère le diagnostic, mais il faut toujours l’humain qui comprend la stack. J’utilise le même principe dans mon travail pour construire des systèmes d’automatisation IA pour l’e-commerce→ et dans mon travail de pipeline de contenu.
Architecture finale après le déploiement
Après les correctifs, la stack s’est stabilisée dans une séparation propre :
| Composant | Emplacement | But |
|---|---|---|
| --- | --- | --- |
| Frontend Next.js | Vercel | Sert les pages et gère le routage |
| WordPress + WPGraphQL | `wp.optagonen.se` | API de contenu et stockage des médias |
| Contact Form 7 | `wp.optagonen.se` | Gestion des formulaires |
| Proxy d’images | Règle de réécriture Next.js | Route les uploads vers l’origine |
| SSL frontend | Vercel | Gestion automatique |
| SSL backend | Certbot + hook de renouvellement | Certificats renouvelés automatiquement |
Cette structure est stable et facile à déboguer. Elle garde aussi le frontend rapide tout en préservant le workflow éditorial dans WordPress. Pour un déploiement de WordPress headless, cet équilibre est l’objectif.
Leçons tirées de ce déploiement de WordPress headless
Voici ce que j’ai appris de la migration :
Ces leçons viennent d’un passage en production réel, pas d’un tutoriel. C’est pourquoi j’alloue maintenant autant de temps au déploiement qu’à la construction.
Conclusion
Le déploiement de WordPress headless n’est pas difficile à cause du code. Il est difficile parce que DNS, SSL, les médias et les en-têtes de host dépendent tous les uns des autres. Dans cette migration, j’ai corrigé la séparation en sous-domaine, la validation des certificats, la diffusion des images et Contact Form 7, et j’ai appris exactement où l’IA aide et où elle s’arrête.
Si vous prévoyez votre propre migration, lisez d’abord la reconstruction du frontend, testez tôt votre flux de certificat, et vérifiez chaque chemin de média avant le lancement. Ensuite, vérifiez le site en direct, confirmez les formulaires, et assurez-vous que le backend se comporte toujours comme WordPress s’y attend.
Si vous voulez plus de décompositions de déploiement pratiques, continuez à lire les articles liés et comparez-les avec votre propre stack. C’est le moyen le plus rapide d’éviter des erreurs lors de votre prochain déploiement de WordPress headless.
Texte alternatif suggéré pour l’image :
