Résoudre les boucles de redirection SSL avec Cloudflare

Credit : Logo officiel

Résoudre les boucles de redirection SSL avec Cloudflare

Dylan D. — Agent Support Technique Serveur Depannage 1924 mots 10 min de lecture

Resoudre les boucles de redirection SSL avec Cloudflare

Vendredi soir, 18h45. Un client m'appelle, paniqué : il vient d'activer Cloudflare devant son hébergement IONOS pour gagner en performance, et son site renvoie systématiquement ERR_TOO_MANY_REDIRECTS. Plus rien n'est accessible, ni le front ni le back-office WordPress. Le client était à deux doigts de désactiver Cloudflare en pensant que ça venait de là. Spoiler : non, c'est sa configuration côté serveur qui n'est pas alignée avec le mode SSL du proxy. En 15 minutes le site est reparti, et ce genre de cas je le vois passer plusieurs fois par semaine au support.

Dans cet article je vais te montrer exactement comment je diagnostique et corrige ce problème, avec les commandes que j'utilise au quotidien. On va parler des modes SSL Cloudflare, du .htaccess, de Nginx, de WordPress, et des pièges classiques liés au cache navigateur et au cache Cloudflare lui-même.

Comprendre la mécanique de la boucle

Avant de coller du code, il faut comprendre pourquoi ça boucle. Cloudflare propose quatre modes SSL/TLS dans son dashboard : Off, Flexible, Full et Full (Strict). Le mode par défaut quand tu actives le proxy orange sur un domaine, c'est Flexible. Et c'est précisément là que le piège se referme.

En mode Flexible :

  1. Le visiteur tape https://exemple.fr dans son navigateur
  2. Cloudflare reçoit la requête en HTTPS, déchiffre le trafic
  3. Cloudflare contacte ton serveur d'origine en HTTP (pas en HTTPS)
  4. Ton serveur (Apache, Nginx, mutualisé IONOS) reçoit du HTTP
  5. Ton .htaccess ou ta config Nginx voit du HTTP et redirige vers HTTPS
  6. Cloudflare reçoit le 301 vers HTTPS, le renvoie au navigateur
  7. Retour à l'étape 1, et ainsi de suite

Le navigateur abandonne après une vingtaine de redirections en boucle et affiche ERR_TOO_MANY_REDIRECTS sous Chrome ou La page n'est pas redirigée correctement sous Firefox. Sur le réseau, tu peux voir 18 à 20 entrées identiques 301 Moved Permanently qui s'enchaînent dans l'onglet Network des DevTools.

Le truc c'est que chaque acteur fait son boulot correctement : Cloudflare termine bien le SSL, ton serveur redirige bien le HTTP vers HTTPS comme tu lui as dit. C'est la combinaison des deux qui crée la boucle.

Diagnostiquer en 3 commandes

Quand un client m'appelle pour ce souci, je commence toujours par trois vérifications dans cet ordre. Pas une de plus, pas une de moins.

Étape 1 : confirmer que Cloudflare est bien en proxy

dig +short exemple.fr

Si tu vois une IP dans les ranges 104.16.0.0/13, 104.24.0.0/14, 172.64.0.0/13 ou 162.158.0.0/15, c'est du Cloudflare en mode proxy (le petit nuage orange dans le dashboard DNS). Si tu vois l'IP réelle de IONOS (généralement dans 217.160.x.x ou 82.165.x.x), Cloudflare est en mode DNS only (nuage gris) et le problème vient d'ailleurs.

Étape 2 : tester en bypassant Cloudflare

curl -I -H "Host: exemple.fr" http://217.160.123.45

Remplace l'IP par celle de ton serveur d'origine (tu la trouves dans ton panel IONOS, section Hébergement > Détails). Cette commande va frapper directement ton serveur sans passer par Cloudflare, en envoyant le bon header Host pour que vhost réponde correctement.

Si tu reçois un HTTP/1.1 301 Moved Permanently avec Location: https://exemple.fr/, tu as trouvé la coupable : c'est ta règle de redirection HTTP vers HTTPS qui ne sait pas qu'elle est derrière un proxy.

Étape 3 : vérifier les en-têtes Cloudflare

curl -I https://exemple.fr | grep -i "cf-\|server\|x-forwarded"

Tu devrais voir des en-têtes comme cf-ray, cf-cache-status, et server: cloudflare. Si oui, ta requête transite bien par Cloudflare.

Solution 1 : passer Cloudflare en Full (Strict)

C'est la solution propre, celle que je recommande à 100% des clients. Le mode Flexible était une commodité de l'époque où installer un certificat SSL côté origine coûtait cher ou prenait du temps. Aujourd'hui avec Let's Encrypt et les certificats gratuits IONOS, ça n'a plus aucun sens.

Procédure dans le dashboard Cloudflare

  1. Connecte-toi sur dash.cloudflare.com
  2. Sélectionne le domaine concerné
  3. Dans le menu de gauche : SSL/TLS > Overview
  4. Passe le mode de Flexible à Full (Strict)
  5. Attends 30 secondes pour la propagation
  6. Vide le cache Cloudflare : Caching > Configuration > Purge Everything

Le mode Full (Strict) force Cloudflare à valider que ton certificat d'origine est valide et signé par une autorité reconnue. Si ton serveur IONOS utilise déjà un certificat Let's Encrypt ou le certificat IONOS gratuit, ça marche directement.

Pré-requis côté origine

Pour que Full (Strict) fonctionne, ton serveur d'origine doit :

Vérifie avec :

curl -vI https://exemple.fr 2>&1 | grep -i "subject\|issuer\|expire"

Si tu vois SSL certificate problem: self signed certificate, il faut générer un Let's Encrypt ou activer le SSL gratuit dans ton panel IONOS avant de basculer en Full Strict.

Solution 2 : adapter le .htaccess pour Apache

Si pour une raison X tu dois rester en mode Flexible (rare mais ça arrive), il faut que ton .htaccess détecte qu'il est derrière Cloudflare et arrête de rediriger.

Cloudflare envoie deux en-têtes utiles : CF-Visitor (qui contient {"scheme":"https"}) et X-Forwarded-Proto (qui vaut https ou http). Les deux fonctionnent, je préfère X-Forwarded-Proto parce qu'il est plus standard et marche aussi derrière d'autres reverse proxies.

RewriteEngine On

# Si la requête vient en HTTPS depuis Cloudflare, on ne redirige pas
RewriteCond %{HTTP:X-Forwarded-Proto} =https [OR]
RewriteCond %{HTTPS} =on
RewriteRule ^ - [L]

# Sinon, on force la redirection HTTPS
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP:X-Forwarded-Proto} !=https
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]

La première règle court-circuite tout si Cloudflare nous dit que le visiteur est en HTTPS. La seconde redirige uniquement si on est vraiment en HTTP non-Cloudflare (typiquement un robot ou un test direct sur l'IP).

Variante avec CF-Visitor

Si tu veux du Cloudflare-specific :

RewriteEngine On
RewriteCond %{HTTP:CF-Visitor} '"scheme":"http"'
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]

Cette règle redirige uniquement si Cloudflare nous indique que le visiteur n'est pas en HTTPS. Sinon on laisse passer.

Solution 3 : config Nginx propre

Sur un VPS IONOS avec Nginx, voici la config qui marche tout le temps :

server {
    listen 80;
    server_name exemple.fr www.exemple.fr;

    # Si la requête vient via Cloudflare en HTTPS, on sert directement
    if ($http_x_forwarded_proto = "https") {
        set $skip_redirect 1;
    }

    # Sinon on redirige vers HTTPS
    if ($skip_redirect != 1) {
        return 301 https://$host$request_uri;
    }

    root /var/www/exemple.fr/public;
    index index.php index.html;
}

server {
    listen 443 ssl http2;
    server_name exemple.fr www.exemple.fr;

    ssl_certificate /etc/letsencrypt/live/exemple.fr/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/exemple.fr/privkey.pem;

    # Restreindre aux IPs Cloudflare uniquement (optionnel mais recommandé)
    set_real_ip_from 173.245.48.0/20;
    set_real_ip_from 103.21.244.0/22;
    set_real_ip_from 103.22.200.0/22;
    real_ip_header CF-Connecting-IP;

    root /var/www/exemple.fr/public;
    index index.php index.html;
}

Le set_real_ip_from est important : sans ça, tous tes logs vont contenir l'IP de Cloudflare au lieu de celle du visiteur. Pour la liste complète des plages IP Cloudflare, va sur cloudflare.com/ips/.

Cas particulier WordPress

WordPress 6.x a son propre piège : même si Apache et Cloudflare sont alignés, WordPress peut continuer à rediriger en boucle parce qu'il pense être en HTTP côté serveur (puisque c'est ce que Cloudflare lui envoie en mode Flexible).

Dans wp-config.php, avant la ligne require_once ABSPATH . 'wp-settings.php'; :

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
    $_SERVER['HTTPS'] = 'on';
}

Ce bout de code dit à WordPress : si Cloudflare nous indique que le visiteur est en HTTPS, fais comme si la connexion était en HTTPS. Toutes les fonctions internes WordPress (is_ssl(), génération d'URLs, redirections admin) vont alors fonctionner correctement.

Vérifie aussi que siteurl et home dans la table wp_options sont bien en https:// :

wp option get siteurl
wp option get home
wp option update siteurl https://exemple.fr
wp option update home https://exemple.fr

Erreurs courantes et leur fix

J'ai vu ces erreurs des dizaines de fois au support, voici les plus fréquentes.

Erreur 1 : le cache navigateur fait croire que ça marche pas

Client corrige tout, retest, toujours ERR_TOO_MANY_REDIRECTS. En réalité c'est parfait côté serveur, mais le navigateur a mis en cache le 301 précédent. Solution : navigation privée, ou Ctrl+Shift+Suppr puis vider les données du dernier jour. Tu peux aussi taper chrome://net-internals/#dns et cliquer sur Clear host cache.

Erreur 2 : Cloudflare cache aussi les 301

Cloudflare met agressivement en cache les redirections 301. Après avoir corrigé, si tu purges pas le cache CF, tu vas continuer à servir l'ancienne réponse aux visiteurs. Va dans Caching > Configuration > Purge Everything ou utilise l'API :

curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache" \
  -H "Authorization: Bearer TON_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"purge_everything":true}'

Erreur 3 : Page Rules qui force le HTTPS

Certains clients ont mis en place une Page Rule Cloudflare qui force Always Use HTTPS. Combinée avec un mode SSL Flexible et une redirection htaccess, ça crée une triple boucle. Désactive la Page Rule ou passe-la en mode Off le temps de déboguer.

Erreur 4 : HSTS activé pendant le débogage

Si tu as activé HSTS dans Cloudflare et que tu testes sur un sous-domaine où le SSL est cassé, le navigateur va refuser de tomber en HTTP même pour tester. Désactive HSTS pendant le débogage, ou utilise un autre navigateur.

Erreur 5 : redirection www vers non-www en double

Classique : .htaccess redirige www.exemple.fr vers exemple.fr, et Cloudflare a une Page Rule qui fait l'inverse. Ping-pong garanti. Choisis un seul endroit pour gérer la redirection www, jamais les deux.

Vérifier que tout est revenu à la normale

Une fois corrigé, je teste systématiquement avec :

curl -I https://exemple.fr
curl -I https://www.exemple.fr
curl -I http://exemple.fr

Sur les deux premiers j'attends un 200 OK direct (pas de redirection). Sur le troisième j'attends un 301 ou 308 vers la version HTTPS, une seule fois. Si je vois plusieurs 301 en cascade ou une 200 sur le HTTP, il y a encore un souci.

Un outil pratique aussi : redirectchecker.com ou l'extension Chrome Redirect Path qui te montre toute la chaîne de redirections d'une URL.

Pour aller plus loin

Les redirections SSL avec Cloudflare ne sont qu'une partie de la sécurisation et de l'optimisation d'un site. Voici les sujets connexes que je traite régulièrement au support :

La leçon que je tire de chaque ticket Cloudflare

Les boucles de redirection SSL c'est jamais un bug, c'est toujours un mismatch de configuration entre deux couches qui ne se parlent pas. Le truc c'est de comprendre que Cloudflare en proxy ajoute une couche supplémentaire dans la chaîne de protocole, et que tout ce qui prend des décisions basées sur HTTP/HTTPS (htaccess, WordPress, applications PHP) doit être conscient de cette couche.

Ma recommandation depuis trois ans : passe systématiquement en Full (Strict) dès que tu actives Cloudflare. Tu installes Let's Encrypt sur ton origine en deux commandes (certbot --nginx -d exemple.fr et c'est fini), et tu n'auras plus jamais ce genre de problème. C'est aussi mieux pour la sécurité parce que le trafic entre Cloudflare et ton serveur reste chiffré, ce qui n'est pas le cas en Flexible.

Et si tu dois quand même rester en Flexible pour une raison technique, n'oublie jamais le check sur X-Forwarded-Proto partout : htaccess, Nginx, et wp-config.php. Les trois doivent être alignés. Sinon la boucle revient.

# Articles similaires

Sur les memes sujets et plus loin