Migration Cloudflare vers Bunny CDN : les Page Rules oubliées qui ont transformé 1 247 redirections 301 en 302 pendant 63 jours
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.
Lundi 17 mars, 9h12 — "C'est juste Google qui re-crawle"
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.
Semaine 2. Le trafic organique recule de 7 %. L'équipe attribue la baisse au core update de mai 2026 qui commençait à peine son déploiement. L'hypothèse est confortable. Elle tient huit jours.
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.
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à.
Deuxième réflexe : tester une URL en curl.
curl -I -L "https://www.exemple-comparateur.fr/categorie/ancienne-url"
Résultat :
HTTP/2 302
location: https://www.exemple-comparateur.fr/categorie/nouvelle-url
server: BunnyCDN-...
Le 302 ne vient pas du serveur origin. Il vient du CDN.
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.
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.
Le Lead SEO sort les chiffres de Search Console sur 21 jours :
- Impressions catégories : −22 %
- Clics catégories : −31 %
- Pages en "Redirection" dans le rapport de couverture : +1 189
Le CTO comprend que la facture CDN réduite vient de coûter bien plus cher en trafic perdu.
Le bug : Cloudflare Page Rules vs Bunny Edge Rules — ce que le CDN voit, ce que Google reçoit
Pour comprendre l'incident, il faut décomposer la chaîne de requête avant et après la migration.
Avant : architecture Cloudflare
Sous Cloudflare, le flux d'une URL redirigée ressemblait à ceci :
- Le navigateur (ou Googlebot) requête
https://www.exemple-comparateur.fr/ancienne-url - Cloudflare intercepte la requête au niveau edge
- Une Page Rule matche le pattern et renvoie un 301 directement, sans jamais toucher le serveur origin
- Le client reçoit un
301 Moved Permanentlyavec le headerLocation
La config Cloudflare ressemblait à ceci dans l'export JSON des Page Rules :
{
"targets": [
{
"target": "url",
"constraint": {
"operator": "matches",
"value": "www.exemple-comparateur.fr/categorie/smartphones/*"
}
}
],
"actions": [
{
"id": "forwarding_url",
"value": {
"url": "https://www.exemple-comparateur.fr/categorie/telephones/$1",
"status_code": 301
}
}
]
}
47 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.
Le 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.
Après : architecture Bunny CDN
Bunny CDN utilise un système différent : les Edge Rules. Elles ne sont pas compatibles avec le format Page Rules de Cloudflare. Il n'existe aucun outil d'import automatique.
Lors de la migration, l'équipe infra a :
- Configuré le Pull Zone Bunny pointant vers le serveur origin
- Mis à jour les DNS
- Activé le certificat SSL via Bunny
- Testé le TTFB, le cache hit ratio, et la disponibilité
Personne n'a audité les Page Rules Cloudflare.
Après migration, le flux d'une URL redirigée devenait :
- Le navigateur (ou Googlebot) requête
https://www.exemple-comparateur.fr/ancienne-url - Bunny CDN ne trouve aucune Edge Rule correspondante
- Bunny forward la requête au serveur origin
- Nginx matche la règle (quand elle existe) et renvoie un 301
- Bunny reçoit le 301 du origin
- Bunny, avec la configuration par défaut du Pull Zone, suit la redirection en interne et renvoie le contenu final avec un 302
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.
La preuve dans les headers HTTP reçus par Googlebot :
HTTP/2 302
location: https://www.exemple-comparateur.fr/categorie/telephones/samsung-galaxy
cache-control: public, max-age=86400
cdn-requestid: abc123def456
server: BunnyCDN-FR1-789
x-bunny-origin-status: 301
Le 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.
Pourquoi un 302 au lieu d'un 301 change tout
La différence entre 301 et 302 pour Google est documentée sur Google Search Central :
- 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.
- 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.
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é).
L'impact mesuré dans Search Console après 9 semaines :
- Pages "Redirections" dans le rapport de couverture : 1 189
- Impressions globales : −28 %
- Clics organiques : −34 % (de 410K/mois à 271K/mois)
- Positions moyennes sur les mots-clés catégories : recul de 4.2 positions en moyenne
Pourquoi les tests n'ont rien détecté
L'équipe avait testé trois choses avant de basculer les DNS :
- Disponibilité : monitoring Uptime Robot, toutes les URLs principales répondaient 200. ✓
- Performance : TTFB amélioré, cache hit ratio à 94 % après warm-up. ✓
- SSL : certificat Let's Encrypt via Bunny, pas de mixed content. ✓
Ce qui n'a pas été testé :
- Le code de statut HTTP des URLs redirigées (pas celles qui répondent 200)
- La parité entre les Page Rules Cloudflare et les Edge Rules Bunny
- Le comportement de Bunny face aux redirections origin
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 migration WordPress vers headless où 4 000 règles htaccess avaient été oubliées lors du changement d'architecture.
Le fix : Edge Rules Bunny + purge des mauvais signaux
Le correctif a nécessité trois actions distinctes, déployées en 48 heures.
Action 1 : Désactiver "Follow Redirects" sur le Pull Zone
Dans le dashboard Bunny CDN → Pull Zone → General → Routing :
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.
Vérification immédiate :
curl -I "https://www.exemple-comparateur.fr/categorie/smartphones/samsung" \
-H "User-Agent: Googlebot"
HTTP/2 301
location: https://www.exemple-comparateur.fr/categorie/telephones/samsung
server: BunnyCDN-FR1-789
Action 2 : Porter les Page Rules Cloudflare manquantes en Edge Rules Bunny
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 :
curl -X POST "https://api.bunny.net/pullzone/ZONE_ID/edgerules" \
-H "AccessKey: BUNNY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ActionType": 4,
"ActionParameter1": "https://www.exemple-comparateur.fr/categorie/telephones/$1",
"ActionParameter2": "301",
"Triggers": [
{
"Type": 0,
"PatternMatches": ["https://www.exemple-comparateur.fr/categorie/smartphones/*"],
"PatternMatchingType": 0
}
],
"TriggerMatchingType": 0,
"Description": "301 smartphones vers telephones - ex Page Rule CF #12",
"Enabled": true
}'
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.
Action 3 : Purge du cache Bunny et forcer le re-crawl
# Purge globale du cache Bunny
curl -X POST "https://api.bunny.net/pullzone/ZONE_ID/purgeCache" \
-H "AccessKey: BUNNY_API_KEY"
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.
Temps de récupération
La chronologie de récupération observée :
- J+2 : 100 % des URLs répondent à nouveau en 301. Confirmé par un crawl Screaming Frog complet.
- J+7 : Google commence à re-crawler les URLs corrigées. Le rapport de couverture Search Console montre une baisse des pages en "Redirection".
- J+14 : les anciennes URLs commencent à sortir de l'index. Les nouvelles URLs récupèrent des positions.
- J+28 : 78 % du trafic perdu est récupéré.
- J+42 : retour à 96 % du niveau pré-incident.
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.
Gardes-fous mis en place
L'équipe a ajouté trois contrôles au processus de déploiement :
-
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.
-
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.
# .github/workflows/check-redirects.yml
name: Verify 301 redirects
on:
deployment_status:
types: [completed]
jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Check redirect status codes
run: |
while IFS=, read -r source target; do
status=$(curl -o /dev/null -s -w "%{http_code}" -I "$source")
if [ "$status" != "301" ]; then
echo "FAIL: $source returned $status (expected 301)"
exit 1
fi
done < redirects.csv
echo "All redirects OK"
- 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.
Le même type de vigilance aurait évité l'incident décrit lors d'une migration de www vers non-www où Google avait indexé les deux versions pendant trois mois.
Pour les équipes qui gèrent des transitions HTTP vers HTTPS, le principe est identique : chaque couche de l'infrastructure qui peut modifier un code de statut HTTP doit être auditée indépendamment.
Ce qu'on en retient
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.
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.
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. Stress-tester un environnement de staging avant la bascule aurait également permis de repérer la divergence.
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.