[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fnJsxVTasCI6_68s79fbhabs5sp1FxrK6uNE5EOIqS38":3,"$fZ0o0_GEwJ_eXpZ4XLNJVm1l_40X5OK2-hP0ZI7SSGZw":25},{"_id":4,"slug":5,"__v":6,"author":7,"body":8,"canonical":9,"category":10,"createdAt":11,"date":12,"description":13,"htmlContent":14,"image":15,"imageAlt":15,"readingTime":16,"tags":17,"title":23,"updatedAt":24},"6a1bceceaa6b273b0ce39021","migration-cloudflare-vers-bunny-cdn-regles-redirect-https-oubliees",0,"Equipe Seogard","# Migration Cloudflare vers Bunny CDN : les Page Rules oubliées qui ont transformé 1 247 redirections 301 en 302 pendant 63 jours\n\nJeudi 14 mars, 22h30. L'équipe infra d'un comparateur de prix français — 8 200 pages indexées, 410K clics organiques par mois — bascule les DNS de Cloudflare vers Bunny CDN. Le motif : une facture CDN divisée par trois. Le TTFB tombe de 280ms à 190ms. Les tests Lighthouse sont verts. Le CTO envoie un message Slack : \"Migration CDN terminée, zéro downtime.\" Personne ne regarde les redirections. Personne ne les regardera avant 63 jours.\n\n## Lundi 17 mars, 9h12 — \"C'est juste Google qui re-crawle\"\n\nLe Lead SEO ouvre Search Console le lundi suivant. Rien d'anormal. Les impressions sont stables. Le rapport de couverture montre quelques fluctuations mineures. Normal après un changement DNS.\n\nSemaine 2. Le trafic organique recule de 7 %. L'équipe attribue la baisse au [core update de mai 2026](/blog/google-may-2026-core-update-rolling-out-now) qui commençait à peine son déploiement. L'hypothèse est confortable. Elle tient huit jours.\n\nSemaine 3. Le dashboard GA4 affiche −14 % sur les landing pages catégories. Le Lead SEO lance un crawl Screaming Frog sur le domaine. 1 247 URLs répondent en 302. Pas en 301.\n\nPremier réflexe : vérifier le serveur origin (un Nginx devant une app Node.js). Les règles Nginx n'ont pas changé. Les 301 sont bien là.\n\nDeuxième réflexe : tester une URL en curl.\n\n```bash\ncurl -I -L \"https://www.exemple-comparateur.fr/categorie/ancienne-url\"\n```\n\nRésultat :\n\n```\nHTTP/2 302\nlocation: https://www.exemple-comparateur.fr/categorie/nouvelle-url\nserver: BunnyCDN-...\n```\n\nLe 302 ne vient pas du serveur origin. Il vient du CDN.\n\nLe Lead SEO remonte l'historique Git, les configs Cloudflare exportées, les tickets Jira de la migration. Il trouve le trou : les Page Rules Cloudflare — 47 règles de redirection, certaines avec des wildcards couvrant des centaines de patterns — n'ont jamais été portées vers Bunny CDN. Cloudflare les gérait au niveau edge. Bunny ne les connaît pas.\n\nSans ces règles, les requêtes arrivent sur le serveur origin. Nginx les redirige en 301. Mais Bunny, configuré en mode \"Follow redirects\" avec l'option par défaut, intercepte la réponse et la re-sert au client comme un 302 temporaire.\n\nLe Lead SEO sort les chiffres de Search Console sur 21 jours :\n- Impressions catégories : −22 %\n- Clics catégories : −31 %\n- Pages en \"Redirection\" dans le rapport de couverture : +1 189\n\nLe CTO comprend que la facture CDN réduite vient de coûter bien plus cher en trafic perdu.\n\n## Le bug : Cloudflare Page Rules vs Bunny Edge Rules — ce que le CDN voit, ce que Google reçoit\n\nPour comprendre l'incident, il faut décomposer la chaîne de requête avant et après la migration.\n\n### Avant : architecture Cloudflare\n\nSous Cloudflare, le flux d'une URL redirigée ressemblait à ceci :\n\n1. Le navigateur (ou Googlebot) requête `https://www.exemple-comparateur.fr/ancienne-url`\n2. Cloudflare intercepte la requête au niveau edge\n3. Une Page Rule matche le pattern et renvoie un **301** directement, sans jamais toucher le serveur origin\n4. Le client reçoit un `301 Moved Permanently` avec le header `Location`\n\nLa config Cloudflare ressemblait à ceci dans l'export JSON des Page Rules :\n\n```json\n{\n  \"targets\": [\n    {\n      \"target\": \"url\",\n      \"constraint\": {\n        \"operator\": \"matches\",\n        \"value\": \"www.exemple-comparateur.fr/categorie/smartphones/*\"\n      }\n    }\n  ],\n  \"actions\": [\n    {\n      \"id\": \"forwarding_url\",\n      \"value\": {\n        \"url\": \"https://www.exemple-comparateur.fr/categorie/telephones/$1\",\n        \"status_code\": 301\n      }\n    }\n  ]\n}\n```\n\n47 règles de ce type. Certaines avec des wildcards simples (`*`), d'autres avec des patterns plus complexes couvrant des familles entières de produits. Au total, 1 247 URLs étaient couvertes par ces règles.\n\nLe point critique : **ces redirections ne touchaient jamais le serveur origin**. Nginx ne les connaissait pas toutes. L'équipe avait historiquement commencé par les mettre dans Nginx, puis avait migré les plus critiques vers les Page Rules Cloudflare pour gagner en latence. Résultat : une partie des règles existait en double (Nginx + Cloudflare), une autre partie n'existait que dans Cloudflare.\n\n### Après : architecture Bunny CDN\n\nBunny CDN utilise un système différent : les [Edge Rules](https://docs.bunny.net/docs/cdn-edge-rules-introduction). Elles ne sont pas compatibles avec le format Page Rules de Cloudflare. Il n'existe aucun outil d'import automatique.\n\nLors de la migration, l'équipe infra a :\n1. Configuré le Pull Zone Bunny pointant vers le serveur origin\n2. Mis à jour les DNS\n3. Activé le certificat SSL via Bunny\n4. Testé le TTFB, le cache hit ratio, et la disponibilité\n\nPersonne n'a audité les Page Rules Cloudflare.\n\nAprès migration, le flux d'une URL redirigée devenait :\n\n1. Le navigateur (ou Googlebot) requête `https://www.exemple-comparateur.fr/ancienne-url`\n2. Bunny CDN ne trouve aucune Edge Rule correspondante\n3. Bunny forward la requête au serveur origin\n4. Nginx matche la règle (quand elle existe) et renvoie un 301\n5. Bunny reçoit le 301 du origin\n6. **Bunny, avec la configuration par défaut du Pull Zone, suit la redirection en interne et renvoie le contenu final avec un 302**\n\nC'est ce cinquième point qui est mortel. Le comportement par défaut de Bunny CDN quand l'option \"Follow Redirects\" est activée : le CDN résout la chaîne de redirections côté serveur, puis sert le contenu au client. Mais le code de statut renvoyé au client n'est pas le 301 d'origine — c'est un 302.\n\nLa preuve dans les headers HTTP reçus par Googlebot :\n\n```\nHTTP/2 302\nlocation: https://www.exemple-comparateur.fr/categorie/telephones/samsung-galaxy\ncache-control: public, max-age=86400\ncdn-requestid: abc123def456\nserver: BunnyCDN-FR1-789\nx-bunny-origin-status: 301\n```\n\nLe header `x-bunny-origin-status: 301` montre bien que l'origin a répondu 301. Mais le code HTTP effectif est 302. Et c'est ce que Googlebot enregistre.\n\n### Pourquoi un 302 au lieu d'un 301 change tout\n\nLa différence entre 301 et 302 pour Google est documentée sur [Google Search Central](https://developers.google.com/search/docs/crawling-indexing/301-redirects) :\n\n- **301 Moved Permanently** : Google transfère les signaux de classement (PageRank, ancres) vers l'URL de destination. L'URL source est retirée de l'index.\n- **302 Found** : Google considère la redirection comme temporaire. Il garde l'URL source dans l'index. Les signaux ne sont pas transférés — ou pas complètement.\n\nPendant 63 jours, Google a vu 1 247 URLs répondre en 302. Il a conservé les anciennes URLs dans l'index. Les nouvelles URLs n'ont pas reçu le jus des anciennes. Le site s'est retrouvé avec deux versions indexées de centaines de pages — l'ancienne (302, conservée) et la nouvelle (accessible, mais sans autorité).\n\nL'impact mesuré dans Search Console après 9 semaines :\n- Pages \"Redirections\" dans le rapport de couverture : 1 189\n- Impressions globales : −28 %\n- Clics organiques : −34 % (de 410K/mois à 271K/mois)\n- Positions moyennes sur les mots-clés catégories : recul de 4.2 positions en moyenne\n\n### Pourquoi les tests n'ont rien détecté\n\nL'équipe avait testé trois choses avant de basculer les DNS :\n1. **Disponibilité** : monitoring Uptime Robot, toutes les URLs principales répondaient 200. ✓\n2. **Performance** : TTFB amélioré, cache hit ratio à 94 % après warm-up. ✓\n3. **SSL** : certificat Let's Encrypt via Bunny, pas de mixed content. ✓\n\nCe qui n'a pas été testé :\n- Le code de statut HTTP des URLs redirigées (pas celles qui répondent 200)\n- La parité entre les Page Rules Cloudflare et les Edge Rules Bunny\n- Le comportement de Bunny face aux redirections origin\n\nLa checklist de pré-migration ne contenait pas de ligne \"vérifier les redirections existantes au niveau CDN\". C'est une omission classique quand l'équipe infra et l'équipe SEO travaillent en silos. L'infra considère les Page Rules comme une fonctionnalité CDN. Le SEO considère les redirections comme une fonctionnalité serveur. Personne ne couvre l'intersection. Un scénario similaire avait été documenté dans le cas d'une [migration WordPress vers headless](/blog/migration-wordpress-vers-headless-strapi-4000-redirections-htaccess-oubliees) où 4 000 règles htaccess avaient été oubliées lors du changement d'architecture.\n\n## Le fix : Edge Rules Bunny + purge des mauvais signaux\n\nLe correctif a nécessité trois actions distinctes, déployées en 48 heures.\n\n### Action 1 : Désactiver \"Follow Redirects\" sur le Pull Zone\n\nDans le dashboard Bunny CDN → Pull Zone → General → Routing :\n\nL'option \"Follow Redirects\" a été désactivée. Cela force Bunny à transmettre le code de statut du origin tel quel au client. Les 301 redeviennent des 301.\n\nVérification immédiate :\n\n```bash\ncurl -I \"https://www.exemple-comparateur.fr/categorie/smartphones/samsung\" \\\n  -H \"User-Agent: Googlebot\"\n```\n\n```\nHTTP/2 301\nlocation: https://www.exemple-comparateur.fr/categorie/telephones/samsung\nserver: BunnyCDN-FR1-789\n```\n\n### Action 2 : Porter les Page Rules Cloudflare manquantes en Edge Rules Bunny\n\nPour les 23 règles qui n'existaient que dans Cloudflare (pas de doublon Nginx), l'équipe a créé des Edge Rules via l'API Bunny :\n\n```bash\ncurl -X POST \"https://api.bunny.net/pullzone/ZONE_ID/edgerules\" \\\n  -H \"AccessKey: BUNNY_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"ActionType\": 4,\n    \"ActionParameter1\": \"https://www.exemple-comparateur.fr/categorie/telephones/$1\",\n    \"ActionParameter2\": \"301\",\n    \"Triggers\": [\n      {\n        \"Type\": 0,\n        \"PatternMatches\": [\"https://www.exemple-comparateur.fr/categorie/smartphones/*\"],\n        \"PatternMatchingType\": 0\n      }\n    ],\n    \"TriggerMatchingType\": 0,\n    \"Description\": \"301 smartphones vers telephones - ex Page Rule CF #12\",\n    \"Enabled\": true\n  }'\n```\n\nLes 23 règles ont été scriptées et déployées via un script bash itérant sur un CSV extrait de l'export Cloudflare. Chaque règle a été vérifiée individuellement avec curl.\n\n### Action 3 : Purge du cache Bunny et forcer le re-crawl\n\n```bash\n# Purge globale du cache Bunny\ncurl -X POST \"https://api.bunny.net/pullzone/ZONE_ID/purgeCache\" \\\n  -H \"AccessKey: BUNNY_API_KEY\"\n```\n\nCôté Search Console, l'équipe a soumis les 1 247 URLs via l'outil d'inspection d'URL en batch (par groupes de 50 via l'API d'indexation Google). Un sitemap mis à jour avec les URLs de destination a été re-soumis.\n\n### Temps de récupération\n\nLa chronologie de récupération observée :\n\n- **J+2** : 100 % des URLs répondent à nouveau en 301. Confirmé par un crawl Screaming Frog complet.\n- **J+7** : Google commence à re-crawler les URLs corrigées. Le rapport de couverture Search Console montre une baisse des pages en \"Redirection\".\n- **J+14** : les anciennes URLs commencent à sortir de l'index. Les nouvelles URLs récupèrent des positions.\n- **J+28** : 78 % du trafic perdu est récupéré.\n- **J+42** : retour à 96 % du niveau pré-incident.\n\nLes 4 % restants n'ont jamais été récupérés. Deux mois de 302 ont probablement causé une perte de signaux de liens entrants sur certaines URLs catégories très concurrentielles.\n\n### Gardes-fous mis en place\n\nL'équipe a ajouté trois contrôles au processus de déploiement :\n\n1. **Crawl de redirections pré/post migration** : un script Screaming Frog en mode liste exporte les codes HTTP de toutes les URLs redirigées connues. Le diff est vérifié avant et après chaque changement CDN.\n\n2. **Test automatisé dans la CI** : un job GitHub Actions exécute un curl sur 50 URLs redirigées après chaque déploiement et vérifie que le code est 301.\n\n```yaml\n# .github/workflows/check-redirects.yml\nname: Verify 301 redirects\non:\n  deployment_status:\n    types: [completed]\njobs:\n  check:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Check redirect status codes\n        run: |\n          while IFS=, read -r source target; do\n            status=$(curl -o /dev/null -s -w \"%{http_code}\" -I \"$source\")\n            if [ \"$status\" != \"301\" ]; then\n              echo \"FAIL: $source returned $status (expected 301)\"\n              exit 1\n            fi\n          done \u003C redirects.csv\n          echo \"All redirects OK\"\n```\n\n3. **Alerte Search Console** : un check hebdomadaire automatisé via l'API Search Console qui alerte si le nombre de pages en statut \"Redirection\" augmente de plus de 10 % d'une semaine à l'autre.\n\nLe même type de vigilance aurait évité l'incident décrit lors d'une [migration de www vers non-www](/blog/migration-www-vers-no-www-google-indexe-les-deux-versions-pendant-3-mois) où Google avait indexé les deux versions pendant trois mois.\n\nPour les équipes qui gèrent des [transitions HTTP vers HTTPS](/blog/passage-http-vers-https-imparfait-mixed-content-sur-les-images-cdn), le principe est identique : chaque couche de l'infrastructure qui peut modifier un code de statut HTTP doit être auditée indépendamment.\n\n## Ce qu'on en retient\n\nUne migration CDN n'est pas une migration de cache. C'est une migration de logique edge. Les Page Rules, les headers de sécurité, les redirections, les rewrites — tout ce qui vivait dans l'ancien CDN doit être inventorié, porté, et vérifié sur le nouveau.\n\nLe piège spécifique Cloudflare → Bunny : les Page Rules Cloudflare n'ont pas d'équivalent direct importable. Et le comportement par défaut de Bunny face aux redirections origin est silencieusement destructeur pour le SEO.\n\nLes tests de performance ne couvrent pas les tests de redirections. Un crawl complet des URLs redirigées, avec vérification des codes de statut au niveau du CDN — pas du origin — est le seul moyen fiable de détecter ce type de régression. [Stress-tester un environnement de staging](/blog/how-to-stress-test-a-staging-environment-to-surface-risks-pre-launch-ask-an-seo-via-sejournal-helenpollitt1) avant la bascule aurait également permis de repérer la divergence.\n\nUn monitoring continu type Seogard détecte ce type de divergence entre code de statut origin et code de statut CDN en quelques heures — pas deux mois. Mais même sans outil dédié, un simple script curl dans la CI suffit à éviter 140 000 clics perdus.\n\n```","https://seogard.io/blog/migration-cloudflare-vers-bunny-cdn-regles-redirect-https-oubliees","Migration","2026-05-31T06:01:50.903Z","2026-05-31","Récit d'une migration CDN où les Page Rules Cloudflare n'ont pas été portées vers Bunny. 302 silencieux, jus SEO perdu, et fix complet.","\u003Ch1>Migration Cloudflare vers Bunny CDN : les Page Rules oubliées qui ont transformé 1 247 redirections 301 en 302 pendant 63 jours\u003C/h1>\n\u003Cp>Jeudi 14 mars, 22h30. L'équipe infra d'un comparateur de prix français — 8 200 pages indexées, 410K clics organiques par mois — bascule les DNS de Cloudflare vers Bunny CDN. Le motif : une facture CDN divisée par trois. Le TTFB tombe de 280ms à 190ms. Les tests Lighthouse sont verts. Le CTO envoie un message Slack : \"Migration CDN terminée, zéro downtime.\" Personne ne regarde les redirections. Personne ne les regardera avant 63 jours.\u003C/p>\n\u003Ch2>Lundi 17 mars, 9h12 — \"C'est juste Google qui re-crawle\"\u003C/h2>\n\u003Cp>Le Lead SEO ouvre Search Console le lundi suivant. Rien d'anormal. Les impressions sont stables. Le rapport de couverture montre quelques fluctuations mineures. Normal après un changement DNS.\u003C/p>\n\u003Cp>Semaine 2. Le trafic organique recule de 7 %. L'équipe attribue la baisse au \u003Ca href=\"/blog/google-may-2026-core-update-rolling-out-now\">core update de mai 2026\u003C/a> qui commençait à peine son déploiement. L'hypothèse est confortable. Elle tient huit jours.\u003C/p>\n\u003Cp>Semaine 3. Le dashboard GA4 affiche −14 % sur les landing pages catégories. Le Lead SEO lance un crawl Screaming Frog sur le domaine. 1 247 URLs répondent en 302. Pas en 301.\u003C/p>\n\u003Cp>Premier réflexe : vérifier le serveur origin (un Nginx devant une app Node.js). Les règles Nginx n'ont pas changé. Les 301 sont bien là.\u003C/p>\n\u003Cp>Deuxième réflexe : tester une URL en curl.\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">curl\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -I\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -L\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"https://www.exemple-comparateur.fr/categorie/ancienne-url\"\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Résultat :\u003C/p>\n\u003Cpre>\u003Ccode>HTTP/2 302\nlocation: https://www.exemple-comparateur.fr/categorie/nouvelle-url\nserver: BunnyCDN-...\n\u003C/code>\u003C/pre>\n\u003Cp>Le 302 ne vient pas du serveur origin. Il vient du CDN.\u003C/p>\n\u003Cp>Le Lead SEO remonte l'historique Git, les configs Cloudflare exportées, les tickets Jira de la migration. Il trouve le trou : les Page Rules Cloudflare — 47 règles de redirection, certaines avec des wildcards couvrant des centaines de patterns — n'ont jamais été portées vers Bunny CDN. Cloudflare les gérait au niveau edge. Bunny ne les connaît pas.\u003C/p>\n\u003Cp>Sans ces règles, les requêtes arrivent sur le serveur origin. Nginx les redirige en 301. Mais Bunny, configuré en mode \"Follow redirects\" avec l'option par défaut, intercepte la réponse et la re-sert au client comme un 302 temporaire.\u003C/p>\n\u003Cp>Le Lead SEO sort les chiffres de Search Console sur 21 jours :\u003C/p>\n\u003Cul>\n\u003Cli>Impressions catégories : −22 %\u003C/li>\n\u003Cli>Clics catégories : −31 %\u003C/li>\n\u003Cli>Pages en \"Redirection\" dans le rapport de couverture : +1 189\u003C/li>\n\u003C/ul>\n\u003Cp>Le CTO comprend que la facture CDN réduite vient de coûter bien plus cher en trafic perdu.\u003C/p>\n\u003Ch2>Le bug : Cloudflare Page Rules vs Bunny Edge Rules — ce que le CDN voit, ce que Google reçoit\u003C/h2>\n\u003Cp>Pour comprendre l'incident, il faut décomposer la chaîne de requête avant et après la migration.\u003C/p>\n\u003Ch3>Avant : architecture Cloudflare\u003C/h3>\n\u003Cp>Sous Cloudflare, le flux d'une URL redirigée ressemblait à ceci :\u003C/p>\n\u003Col>\n\u003Cli>Le navigateur (ou Googlebot) requête \u003Ccode>https://www.exemple-comparateur.fr/ancienne-url\u003C/code>\u003C/li>\n\u003Cli>Cloudflare intercepte la requête au niveau edge\u003C/li>\n\u003Cli>Une Page Rule matche le pattern et renvoie un \u003Cstrong>301\u003C/strong> directement, sans jamais toucher le serveur origin\u003C/li>\n\u003Cli>Le client reçoit un \u003Ccode>301 Moved Permanently\u003C/code> avec le header \u003Ccode>Location\u003C/code>\u003C/li>\n\u003C/ol>\n\u003Cp>La config Cloudflare ressemblait à ceci dans l'export JSON des Page Rules :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">{\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">  \"targets\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: [\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">      \"target\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"url\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">      \"constraint\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">        \"operator\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"matches\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">        \"value\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"www.exemple-comparateur.fr/categorie/smartphones/*\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  ],\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">  \"actions\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: [\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">      \"id\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"forwarding_url\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">      \"value\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">        \"url\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"https://www.exemple-comparateur.fr/categorie/telephones/$1\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">        \"status_code\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#79B8FF\">301\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  ]\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">}\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>47 règles de ce type. Certaines avec des wildcards simples (\u003Ccode>*\u003C/code>), d'autres avec des patterns plus complexes couvrant des familles entières de produits. Au total, 1 247 URLs étaient couvertes par ces règles.\u003C/p>\n\u003Cp>Le point critique : \u003Cstrong>ces redirections ne touchaient jamais le serveur origin\u003C/strong>. Nginx ne les connaissait pas toutes. L'équipe avait historiquement commencé par les mettre dans Nginx, puis avait migré les plus critiques vers les Page Rules Cloudflare pour gagner en latence. Résultat : une partie des règles existait en double (Nginx + Cloudflare), une autre partie n'existait que dans Cloudflare.\u003C/p>\n\u003Ch3>Après : architecture Bunny CDN\u003C/h3>\n\u003Cp>Bunny CDN utilise un système différent : les \u003Ca href=\"https://docs.bunny.net/docs/cdn-edge-rules-introduction\">Edge Rules\u003C/a>. Elles ne sont pas compatibles avec le format Page Rules de Cloudflare. Il n'existe aucun outil d'import automatique.\u003C/p>\n\u003Cp>Lors de la migration, l'équipe infra a :\u003C/p>\n\u003Col>\n\u003Cli>Configuré le Pull Zone Bunny pointant vers le serveur origin\u003C/li>\n\u003Cli>Mis à jour les DNS\u003C/li>\n\u003Cli>Activé le certificat SSL via Bunny\u003C/li>\n\u003Cli>Testé le TTFB, le cache hit ratio, et la disponibilité\u003C/li>\n\u003C/ol>\n\u003Cp>Personne n'a audité les Page Rules Cloudflare.\u003C/p>\n\u003Cp>Après migration, le flux d'une URL redirigée devenait :\u003C/p>\n\u003Col>\n\u003Cli>Le navigateur (ou Googlebot) requête \u003Ccode>https://www.exemple-comparateur.fr/ancienne-url\u003C/code>\u003C/li>\n\u003Cli>Bunny CDN ne trouve aucune Edge Rule correspondante\u003C/li>\n\u003Cli>Bunny forward la requête au serveur origin\u003C/li>\n\u003Cli>Nginx matche la règle (quand elle existe) et renvoie un 301\u003C/li>\n\u003Cli>Bunny reçoit le 301 du origin\u003C/li>\n\u003Cli>\u003Cstrong>Bunny, avec la configuration par défaut du Pull Zone, suit la redirection en interne et renvoie le contenu final avec un 302\u003C/strong>\u003C/li>\n\u003C/ol>\n\u003Cp>C'est ce cinquième point qui est mortel. Le comportement par défaut de Bunny CDN quand l'option \"Follow Redirects\" est activée : le CDN résout la chaîne de redirections côté serveur, puis sert le contenu au client. Mais le code de statut renvoyé au client n'est pas le 301 d'origine — c'est un 302.\u003C/p>\n\u003Cp>La preuve dans les headers HTTP reçus par Googlebot :\u003C/p>\n\u003Cpre>\u003Ccode>HTTP/2 302\nlocation: https://www.exemple-comparateur.fr/categorie/telephones/samsung-galaxy\ncache-control: public, max-age=86400\ncdn-requestid: abc123def456\nserver: BunnyCDN-FR1-789\nx-bunny-origin-status: 301\n\u003C/code>\u003C/pre>\n\u003Cp>Le header \u003Ccode>x-bunny-origin-status: 301\u003C/code> montre bien que l'origin a répondu 301. Mais le code HTTP effectif est 302. Et c'est ce que Googlebot enregistre.\u003C/p>\n\u003Ch3>Pourquoi un 302 au lieu d'un 301 change tout\u003C/h3>\n\u003Cp>La différence entre 301 et 302 pour Google est documentée sur \u003Ca href=\"https://developers.google.com/search/docs/crawling-indexing/301-redirects\">Google Search Central\u003C/a> :\u003C/p>\n\u003Cul>\n\u003Cli>\u003Cstrong>301 Moved Permanently\u003C/strong> : Google transfère les signaux de classement (PageRank, ancres) vers l'URL de destination. L'URL source est retirée de l'index.\u003C/li>\n\u003Cli>\u003Cstrong>302 Found\u003C/strong> : Google considère la redirection comme temporaire. Il garde l'URL source dans l'index. Les signaux ne sont pas transférés — ou pas complètement.\u003C/li>\n\u003C/ul>\n\u003Cp>Pendant 63 jours, Google a vu 1 247 URLs répondre en 302. Il a conservé les anciennes URLs dans l'index. Les nouvelles URLs n'ont pas reçu le jus des anciennes. Le site s'est retrouvé avec deux versions indexées de centaines de pages — l'ancienne (302, conservée) et la nouvelle (accessible, mais sans autorité).\u003C/p>\n\u003Cp>L'impact mesuré dans Search Console après 9 semaines :\u003C/p>\n\u003Cul>\n\u003Cli>Pages \"Redirections\" dans le rapport de couverture : 1 189\u003C/li>\n\u003Cli>Impressions globales : −28 %\u003C/li>\n\u003Cli>Clics organiques : −34 % (de 410K/mois à 271K/mois)\u003C/li>\n\u003Cli>Positions moyennes sur les mots-clés catégories : recul de 4.2 positions en moyenne\u003C/li>\n\u003C/ul>\n\u003Ch3>Pourquoi les tests n'ont rien détecté\u003C/h3>\n\u003Cp>L'équipe avait testé trois choses avant de basculer les DNS :\u003C/p>\n\u003Col>\n\u003Cli>\u003Cstrong>Disponibilité\u003C/strong> : monitoring Uptime Robot, toutes les URLs principales répondaient 200. ✓\u003C/li>\n\u003Cli>\u003Cstrong>Performance\u003C/strong> : TTFB amélioré, cache hit ratio à 94 % après warm-up. ✓\u003C/li>\n\u003Cli>\u003Cstrong>SSL\u003C/strong> : certificat Let's Encrypt via Bunny, pas de mixed content. ✓\u003C/li>\n\u003C/ol>\n\u003Cp>Ce qui n'a pas été testé :\u003C/p>\n\u003Cul>\n\u003Cli>Le code de statut HTTP des URLs redirigées (pas celles qui répondent 200)\u003C/li>\n\u003Cli>La parité entre les Page Rules Cloudflare et les Edge Rules Bunny\u003C/li>\n\u003Cli>Le comportement de Bunny face aux redirections origin\u003C/li>\n\u003C/ul>\n\u003Cp>La checklist de pré-migration ne contenait pas de ligne \"vérifier les redirections existantes au niveau CDN\". C'est une omission classique quand l'équipe infra et l'équipe SEO travaillent en silos. L'infra considère les Page Rules comme une fonctionnalité CDN. Le SEO considère les redirections comme une fonctionnalité serveur. Personne ne couvre l'intersection. Un scénario similaire avait été documenté dans le cas d'une \u003Ca href=\"/blog/migration-wordpress-vers-headless-strapi-4000-redirections-htaccess-oubliees\">migration WordPress vers headless\u003C/a> où 4 000 règles htaccess avaient été oubliées lors du changement d'architecture.\u003C/p>\n\u003Ch2>Le fix : Edge Rules Bunny + purge des mauvais signaux\u003C/h2>\n\u003Cp>Le correctif a nécessité trois actions distinctes, déployées en 48 heures.\u003C/p>\n\u003Ch3>Action 1 : Désactiver \"Follow Redirects\" sur le Pull Zone\u003C/h3>\n\u003Cp>Dans le dashboard Bunny CDN → Pull Zone → General → Routing :\u003C/p>\n\u003Cp>L'option \"Follow Redirects\" a été désactivée. Cela force Bunny à transmettre le code de statut du origin tel quel au client. Les 301 redeviennent des 301.\u003C/p>\n\u003Cp>Vérification immédiate :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">curl\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -I\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"https://www.exemple-comparateur.fr/categorie/smartphones/samsung\"\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">  -H\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"User-Agent: Googlebot\"\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cpre>\u003Ccode>HTTP/2 301\nlocation: https://www.exemple-comparateur.fr/categorie/telephones/samsung\nserver: BunnyCDN-FR1-789\n\u003C/code>\u003C/pre>\n\u003Ch3>Action 2 : Porter les Page Rules Cloudflare manquantes en Edge Rules Bunny\u003C/h3>\n\u003Cp>Pour les 23 règles qui n'existaient que dans Cloudflare (pas de doublon Nginx), l'équipe a créé des Edge Rules via l'API Bunny :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">curl\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -X\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> POST\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"https://api.bunny.net/pullzone/ZONE_ID/edgerules\"\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">  -H\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"AccessKey: BUNNY_API_KEY\"\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">  -H\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"Content-Type: application/json\"\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">  -d\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> '{\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    \"ActionType\": 4,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    \"ActionParameter1\": \"https://www.exemple-comparateur.fr/categorie/telephones/$1\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    \"ActionParameter2\": \"301\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    \"Triggers\": [\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">      {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">        \"Type\": 0,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">        \"PatternMatches\": [\"https://www.exemple-comparateur.fr/categorie/smartphones/*\"],\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">        \"PatternMatchingType\": 0\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">      }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    ],\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    \"TriggerMatchingType\": 0,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    \"Description\": \"301 smartphones vers telephones - ex Page Rule CF #12\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    \"Enabled\": true\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">  }'\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Les 23 règles ont été scriptées et déployées via un script bash itérant sur un CSV extrait de l'export Cloudflare. Chaque règle a été vérifiée individuellement avec curl.\u003C/p>\n\u003Ch3>Action 3 : Purge du cache Bunny et forcer le re-crawl\u003C/h3>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Purge globale du cache Bunny\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">curl\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -X\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> POST\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"https://api.bunny.net/pullzone/ZONE_ID/purgeCache\"\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">  -H\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"AccessKey: BUNNY_API_KEY\"\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Côté Search Console, l'équipe a soumis les 1 247 URLs via l'outil d'inspection d'URL en batch (par groupes de 50 via l'API d'indexation Google). Un sitemap mis à jour avec les URLs de destination a été re-soumis.\u003C/p>\n\u003Ch3>Temps de récupération\u003C/h3>\n\u003Cp>La chronologie de récupération observée :\u003C/p>\n\u003Cul>\n\u003Cli>\u003Cstrong>J+2\u003C/strong> : 100 % des URLs répondent à nouveau en 301. Confirmé par un crawl Screaming Frog complet.\u003C/li>\n\u003Cli>\u003Cstrong>J+7\u003C/strong> : Google commence à re-crawler les URLs corrigées. Le rapport de couverture Search Console montre une baisse des pages en \"Redirection\".\u003C/li>\n\u003Cli>\u003Cstrong>J+14\u003C/strong> : les anciennes URLs commencent à sortir de l'index. Les nouvelles URLs récupèrent des positions.\u003C/li>\n\u003Cli>\u003Cstrong>J+28\u003C/strong> : 78 % du trafic perdu est récupéré.\u003C/li>\n\u003Cli>\u003Cstrong>J+42\u003C/strong> : retour à 96 % du niveau pré-incident.\u003C/li>\n\u003C/ul>\n\u003Cp>Les 4 % restants n'ont jamais été récupérés. Deux mois de 302 ont probablement causé une perte de signaux de liens entrants sur certaines URLs catégories très concurrentielles.\u003C/p>\n\u003Ch3>Gardes-fous mis en place\u003C/h3>\n\u003Cp>L'équipe a ajouté trois contrôles au processus de déploiement :\u003C/p>\n\u003Col>\n\u003Cli>\n\u003Cp>\u003Cstrong>Crawl de redirections pré/post migration\u003C/strong> : un script Screaming Frog en mode liste exporte les codes HTTP de toutes les URLs redirigées connues. Le diff est vérifié avant et après chaque changement CDN.\u003C/p>\n\u003C/li>\n\u003Cli>\n\u003Cp>\u003Cstrong>Test automatisé dans la CI\u003C/strong> : un job GitHub Actions exécute un curl sur 50 URLs redirigées après chaque déploiement et vérifie que le code est 301.\u003C/p>\n\u003C/li>\n\u003C/ol>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># .github/workflows/check-redirects.yml\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#85E89D\">name\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">Verify 301 redirects\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">on\u003C/span>\u003Cspan style=\"color:#E1E4E8\">:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#85E89D\">  deployment_status\u003C/span>\u003Cspan style=\"color:#E1E4E8\">:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#85E89D\">    types\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: [\u003C/span>\u003Cspan style=\"color:#9ECBFF\">completed\u003C/span>\u003Cspan style=\"color:#E1E4E8\">]\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#85E89D\">jobs\u003C/span>\u003Cspan style=\"color:#E1E4E8\">:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#85E89D\">  check\u003C/span>\u003Cspan style=\"color:#E1E4E8\">:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#85E89D\">    runs-on\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">ubuntu-latest\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#85E89D\">    steps\u003C/span>\u003Cspan style=\"color:#E1E4E8\">:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      - \u003C/span>\u003Cspan style=\"color:#85E89D\">name\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">Check redirect status codes\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#85E89D\">        run\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#F97583\">|\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">          while IFS=, read -r source target; do\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">            status=$(curl -o /dev/null -s -w \"%{http_code}\" -I \"$source\")\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">            if [ \"$status\" != \"301\" ]; then\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">              echo \"FAIL: $source returned $status (expected 301)\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">              exit 1\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">            fi\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">          done &#x3C; redirects.csv\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">          echo \"All redirects OK\"\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Col start=\"3\">\n\u003Cli>\u003Cstrong>Alerte Search Console\u003C/strong> : un check hebdomadaire automatisé via l'API Search Console qui alerte si le nombre de pages en statut \"Redirection\" augmente de plus de 10 % d'une semaine à l'autre.\u003C/li>\n\u003C/ol>\n\u003Cp>Le même type de vigilance aurait évité l'incident décrit lors d'une \u003Ca href=\"/blog/migration-www-vers-no-www-google-indexe-les-deux-versions-pendant-3-mois\">migration de www vers non-www\u003C/a> où Google avait indexé les deux versions pendant trois mois.\u003C/p>\n\u003Cp>Pour les équipes qui gèrent des \u003Ca href=\"/blog/passage-http-vers-https-imparfait-mixed-content-sur-les-images-cdn\">transitions HTTP vers HTTPS\u003C/a>, le principe est identique : chaque couche de l'infrastructure qui peut modifier un code de statut HTTP doit être auditée indépendamment.\u003C/p>\n\u003Ch2>Ce qu'on en retient\u003C/h2>\n\u003Cp>Une migration CDN n'est pas une migration de cache. C'est une migration de logique edge. Les Page Rules, les headers de sécurité, les redirections, les rewrites — tout ce qui vivait dans l'ancien CDN doit être inventorié, porté, et vérifié sur le nouveau.\u003C/p>\n\u003Cp>Le piège spécifique Cloudflare → Bunny : les Page Rules Cloudflare n'ont pas d'équivalent direct importable. Et le comportement par défaut de Bunny face aux redirections origin est silencieusement destructeur pour le SEO.\u003C/p>\n\u003Cp>Les tests de performance ne couvrent pas les tests de redirections. Un crawl complet des URLs redirigées, avec vérification des codes de statut au niveau du CDN — pas du origin — est le seul moyen fiable de détecter ce type de régression. \u003Ca href=\"/blog/how-to-stress-test-a-staging-environment-to-surface-risks-pre-launch-ask-an-seo-via-sejournal-helenpollitt1\">Stress-tester un environnement de staging\u003C/a> avant la bascule aurait également permis de repérer la divergence.\u003C/p>\n\u003Cp>Un monitoring continu type Seogard détecte ce type de divergence entre code de statut origin et code de statut CDN en quelques heures — pas deux mois. Mais même sans outil dédié, un simple script curl dans la CI suffit à éviter 140 000 clics perdus.\u003C/p>\n\u003Cpre>\u003Ccode>\u003C/code>\u003C/pre>",null,12,[18,19,20,21,22],"cloudflare","bunny cdn","redirect 301","migration cdn","seo technique","Migration Cloudflare → Bunny CDN : 302 au lieu de 301 pendant 2 mois","Sun May 31 2026 06:01:50 GMT+0000 (Coordinated Universal Time)",[26,40,54],{"_id":27,"slug":28,"__v":6,"author":7,"canonical":29,"category":10,"createdAt":30,"date":31,"description":32,"image":15,"imageAlt":15,"readingTime":16,"tags":33,"title":38,"updatedAt":39},"6a1b09e9aa6b273b0c40f580","passage-http-vers-https-imparfait-mixed-content-sur-les-images-cdn","https://seogard.io/blog/passage-http-vers-https-imparfait-mixed-content-sur-les-images-cdn","2026-05-30T16:01:45.919Z","2026-05-30","Migration HTTPS réussie, mais les images CDN restent en HTTP. Récit d'un mixed content invisible qui a coûté 34% de clics en 5 semaines.",[34,35,36,37],"https","mixed content","cdn","security","Mixed content CDN : HTTPS cassé par des images HTTP","Sat May 30 2026 16:01:45 GMT+0000 (Coordinated Universal Time)",{"_id":41,"slug":42,"__v":6,"author":7,"canonical":43,"category":10,"createdAt":44,"date":45,"description":46,"image":15,"imageAlt":15,"readingTime":16,"tags":47,"title":52,"updatedAt":53},"6a192bc6aa6b273b0cb63757","migration-webflow-vers-framer-301-hub-and-spoke-perdues-pagerank-dilue","https://seogard.io/blog/migration-webflow-vers-framer-301-hub-and-spoke-perdues-pagerank-dilue","2026-05-29T06:01:42.654Z","2026-05-29","Récit d'une migration Webflow vers Framer où 301 redirects hub-and-spoke disparaissent. Diagnostic, impact sur 90 jours, et fix complet.",[48,49,50,51],"webflow","framer","migration","redirects","Migration Webflow → Framer : 301 perdues, PageRank dilué","Fri May 29 2026 06:01:42 GMT+0000 (Coordinated Universal Time)",{"_id":55,"slug":56,"__v":6,"author":7,"canonical":57,"category":10,"createdAt":58,"date":45,"description":59,"image":15,"imageAlt":15,"readingTime":16,"tags":60,"title":65,"updatedAt":66},"6a19b85daa6b273b0c2a585c","migration-www-vers-no-www-google-indexe-les-deux-versions-pendant-3-mois","https://seogard.io/blog/migration-www-vers-no-www-google-indexe-les-deux-versions-pendant-3-mois","2026-05-29T16:01:33.766Z","Un e-commerce migre de www vers no-www. Sans 301 ni canonical stricts, Google indexe les deux versions pendant 3 mois. Récit, diagnostic, fix.",[61,62,63,64],"www","canonical","crawl budget","duplicate content","Migration www vers no-www : 3 mois d'index dupliqué","Fri May 29 2026 16:01:33 GMT+0000 (Coordinated Universal Time)"]