Erreur 503 et Cloudflare

Distinguer les erreurs Cloudflare des erreurs serveur

CDN, protection DDoS, Workers : maîtrisez votre couche de protection.

Cloudflare et les erreurs 503

Cloudflare agit comme un intermédiaire entre vos visiteurs et votre serveur. Quand une erreur 503 apparaît, elle peut venir de deux sources :

  1. Votre serveur origine renvoie une 503 (maintenance, surcharge)
  2. Cloudflare lui-même génère une 503 (origine injoignable, protection activée)

Savoir distinguer les deux est crucial pour résoudre le problème. Ce guide couvre les deux scénarios et vous montre comment utiliser Cloudflare pour gérer proprement vos maintenances.

Besoin d’aide pour votre infrastructure ? Foxop propose des audits et de l’infogérance avec configuration Cloudflare optimisée.

Identifier l’origine de l’erreur

Les pages d’erreur Cloudflare

Cloudflare a un style visuel distinctif pour ses pages d’erreur :

CodeTitre CloudflareSignification
520Web server is returning an unknown errorRéponse vide ou invalide de l’origine
521Web server is downConnexion refusée par l’origine
522Connection timed outTimeout de connexion à l’origine
523Origin is unreachableDNS ou réseau vers l’origine KO
524A timeout occurredL’origine a mis trop de temps à répondre
525SSL handshake failedProblème de certificat SSL origine
526Invalid SSL certificateCertificat origine invalide
503Service Temporarily UnavailableOrigine renvoie 503 OU Cloudflare en mode maintenance

Astuce visuelle : Les pages d’erreur Cloudflare affichent toujours le logo Cloudflare, un « Ray ID » unique, et votre IP de visiteur. Si vous voyez votre propre page d’erreur personnalisée, c’est votre serveur qui répond.

Vérifier avec les headers HTTP

$ curl -I https://monsite.com

# Erreur venant de Cloudflare
HTTP/2 503
date: Thu, 26 Dec 2024 14:30:00 GMT
content-type: text/html; charset=UTF-8
cf-ray: 8a1b2c3d4e5f6g7h-CDG    # ← Ray ID Cloudflare
cf-cache-status: DYNAMIC
server: cloudflare               # ← Cloudflare

# Erreur venant de votre serveur (passée par Cloudflare)
HTTP/2 503
date: Thu, 26 Dec 2024 14:30:00 GMT
content-type: text/html
retry-after: 3600                # ← Votre header
cf-ray: 8a1b2c3d4e5f6g7h-CDG
server: cloudflare
# Mais le contenu est votre page de maintenance

Utiliser le Ray ID pour diagnostiquer

Le Ray ID est un identifiant unique pour chaque requête. Utilisez-le pour :

  1. Chercher dans les logs Cloudflare (Dashboard > Analytics > Logs)
  2. Contacter le support Cloudflare (plans payants)
  3. Corréler avec vos logs serveur (si la requête est arrivée jusqu’à l’origine)

Erreurs Cloudflare courantes (5xx)

Erreur 521 : Web server is down

Signification : Cloudflare n’arrive pas à se connecter à votre serveur.

flowchart LR
    A[Visiteur] --> B[Cloudflare]
    B -->|Connection refused| C[Votre serveur]
    B --> D[521 Error]

Causes :

  • Serveur web arrêté (Nginx, Apache down)
  • Pare-feu bloquant les IPs Cloudflare
  • Port 80/443 non ouvert
  • Serveur éteint ou inaccessible

Solutions :

# 1. Vérifier que le serveur web tourne
$ systemctl status nginx
$ systemctl status apache2

# 2. Vérifier que les ports sont ouverts
$ ss -tlnp | grep -E ':(80|443)'

# 3. Vérifier le pare-feu
$ ufw status
$ iptables -L -n | grep -E '(80|443)'

# 4. Autoriser les IPs Cloudflare
$ curl -s https://www.cloudflare.com/ips-v4 >> /tmp/cf-ips.txt
$ for ip in $(cat /tmp/cf-ips.txt); do
    ufw allow from $ip to any port 80,443 proto tcp
done

Important : Cloudflare se connecte depuis ses propres IPs, pas depuis l’IP du visiteur. Votre pare-feu doit autoriser les ranges IP Cloudflare.

Erreur 522 : Connection timed out

Signification : Cloudflare a pu initier une connexion mais n’a pas reçu de réponse TCP dans les temps.

Causes :

  • Serveur surchargé (ne répond pas assez vite)
  • Problème réseau entre Cloudflare et l’origine
  • Pare-feu qui « drop » au lieu de « reject »

Solutions :

# Vérifier la charge serveur
$ uptime
$ top -bn1 | head -10

# Tester la connectivité depuis le serveur lui-même
$ curl -I http://localhost
$ curl -I https://localhost

# Vérifier les timeouts côté serveur
# Nginx
$ grep -E "timeout|keepalive" /etc/nginx/nginx.conf

# Apache
$ grep -E "Timeout|KeepAlive" /etc/apache2/apache2.conf

Configuration Cloudflare :

  • Augmentez le timeout dans Network > HTTP/2 Edge Prioritization
  • En Enterprise, vous pouvez augmenter les timeouts proxy

Erreur 524 : A timeout occurred

Signification : La connexion TCP a réussi mais la réponse HTTP n’est pas arrivée dans les 100 secondes (limite Cloudflare Free/Pro).

Causes :

  • Script PHP qui prend trop de temps
  • Requête API externe lente
  • Import/export volumineux

Solutions :

  1. Optimiser le script pour qu’il réponde en moins de 100s
  2. Utiliser des tâches asynchrones (queue, cron) pour les opérations longues
  3. Exclure les URLs longues du proxy Cloudflare (DNS-only)
  4. Plan Enterprise : Timeouts configurables jusqu’à 600s

Exclure une URL du proxy (via Page Rules)

URL: *monsite.com/api/long-operation*
Setting: Cache Level → Bypass
Setting: Proxy → Off (DNS only pour ce path)

Mode « Under Attack » et ses effets

Qu’est-ce que le mode Under Attack ?

Quand vous activez « I’m Under Attack Mode », Cloudflare ajoute un challenge JavaScript de 5 secondes avant chaque visite. Cela bloque les bots simples et les attaques DDoS layer 7.

flowchart LR
    A[Visiteur] --> B[Cloudflare]
    B --> C{Under Attack
Mode ?} C -->|Oui| D[Challenge JS
5 secondes] D -->|Réussi| E[Accès au site] D -->|Échoué| F[Bloqué] C -->|Non| E

Quand l’activer

  • ✅ Attaque DDoS en cours
  • ✅ Trafic anormal détecté
  • ✅ Serveur qui ne tient plus la charge

Quand NE PAS l’activer

  • ❌ En permanence (mauvaise UX, bloque les bots légitimes)
  • ❌ Pour une maintenance planifiée (utilisez une page maintenance à la place)
  • ❌ Si vous avez des webhooks/APIs (ils seront bloqués)

Activation / Désactivation

Via le Dashboard :

Overview > Quick Actions > Under Attack Mode → ON/OFF

Via l’API :

# Activer
$ curl -X PATCH "https://api.cloudflare.com/client/v4/zones/ZONE_ID/settings/security_level" \\
    -H "Authorization: Bearer API_TOKEN" \\
    -H "Content-Type: application/json" \\
    --data '{"value":"under_attack"}'

# Désactiver (revenir à Medium)
$ curl -X PATCH "https://api.cloudflare.com/client/v4/zones/ZONE_ID/settings/security_level" \\
    -H "Authorization: Bearer API_TOKEN" \\
    -H "Content-Type: application/json" \\
    --data '{"value":"medium"}'

Attention aux APIs et webhooks : Le mode Under Attack bloque les requêtes sans JavaScript. Vos webhooks de paiement, APIs, et callbacks échoueront. Excluez ces URLs via des règles WAF ou Page Rules.

Exclure des URLs du challenge

Security > WAF > Custom Rules

Rule name: Bypass challenge for API
When: URI Path contains "/api/" OR URI Path contains "/webhook/"
Then: Skip → All remaining custom rules
       + Security Level → Essentially Off

Page de maintenance via Cloudflare

Cloudflare peut servir une page de maintenance même quand votre serveur est complètement down. Plusieurs méthodes :

Méthode 1 : Custom Error Pages (tous plans)

Custom Pages > 503 Service Unavailable

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Maintenance en cours - MonSite</title>
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
            background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
            color: #fff;
            min-height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
            margin: 0;
        }
        .container { text-align: center; padding: 2rem; }
        h1 { font-size: 2.5rem; margin-bottom: 1rem; }
        p { font-size: 1.2rem; opacity: 0.9; }
        .eta { 
            background: rgba(255,153,0,0.2);
            border: 1px solid #ff9900;
            padding: 1rem 2rem;
            border-radius: 8px;
            margin-top: 2rem;
            display: inline-block;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>?? Maintenance en cours</h1>
        <p>Nous améliorons votre expérience.</p>
        <div class="eta">Retour prévu dans <strong>2 heures</strong></div>
    </div>
</body>
</html>

Limitations : Cette page ne s’affiche que si Cloudflare détecte une erreur 503 de votre serveur. Si votre serveur est complètement down, Cloudflare affichera sa propre page 521/522.

Méthode 2 : Always Online™ (plans payants)

Always Online sert une version en cache de votre site quand l’origine est down.

Activation : Caching > Configuration > Always Online → ON

Limitations :

  • Ne fonctionne que pour les pages déjà en cache
  • Pas de personnalisation
  • Les formulaires et contenus dynamiques ne fonctionnent pas

Méthode 3 : Workers (recommandé)

Cloudflare Workers permet de servir une page de maintenance personnalisée, avec le bon code 503 et le header Retry-After, même si votre serveur est complètement injoignable.

maintenance-worker.js

// Cloudflare Worker - Page de maintenance

const MAINTENANCE_MODE = true; // Basculer à false pour désactiver
const RETRY_AFTER = 7200; // 2 heures en secondes

// IPs autorisées à bypass la maintenance
const ALLOWED_IPS = [
    '123.456.789.012',
    '98.76.54.321'
];

// Chemins à exclure de la maintenance
const EXCLUDED_PATHS = [
    '/api/webhook',
    '/health',
    '/.well-known/'
];

const MAINTENANCE_HTML = `
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Maintenance en cours</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
            color: #fff;
            min-height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .container { text-align: center; padding: 2rem; max-width: 600px; }
        .icon { font-size: 4rem; margin-bottom: 1.5rem; }
        h1 { font-size: 2.5rem; margin-bottom: 1rem; }
        p { font-size: 1.2rem; opacity: 0.9; line-height: 1.6; }
        .eta {
            background: rgba(255, 153, 0, 0.2);
            border: 1px solid #ff9900;
            color: #ff9900;
            padding: 1rem 2rem;
            border-radius: 8px;
            margin-top: 2rem;
            display: inline-block;
            font-weight: bold;
        }
        .contact {
            margin-top: 2rem;
            opacity: 0.7;
            font-size: 0.9rem;
        }
        .contact a { color: #ff9900; }
    </style>
</head>
<body>
    <div class="container">
        <div class="icon">??</div>
        <h1>Maintenance en cours</h1>
        <p>Nous effectuons des améliorations pour vous offrir une meilleure expérience.</p>
        <div class="eta">Retour prévu dans ~2 heures</div>
        <div class="contact">
            <p>Urgence ? <a href="mailto:[email protected]">[email protected]</a></p>
        </div>
    </div>
</body>
</html>
`;

async function handleRequest(request) {
    // Récupérer l'IP du visiteur
    const clientIP = request.headers.get('CF-Connecting-IP');
    const url = new URL(request.url);
    
    // Bypass pour IPs autorisées
    if (ALLOWED_IPS.includes(clientIP)) {
        return fetch(request);
    }
    
    // Bypass pour chemins exclus
    for (const path of EXCLUDED_PATHS) {
        if (url.pathname.startsWith(path)) {
            return fetch(request);
        }
    }
    
    // Mode maintenance actif ?
    if (MAINTENANCE_MODE) {
        return new Response(MAINTENANCE_HTML, {
            status: 503,
            headers: {
                'Content-Type': 'text/html; charset=UTF-8',
                'Retry-After': RETRY_AFTER.toString(),
                'Cache-Control': 'no-store, no-cache, must-revalidate',
                'X-Maintenance-Mode': 'true'
            }
        });
    }
    
    // Sinon, passer la requête à l'origine
    return fetch(request);
}

addEventListener('fetch', event => {
    event.respondWith(handleRequest(event.request));
});

Déploiement :

  1. Dashboard Cloudflare > Workers & Pages
  2. Create Worker
  3. Coller le code
  4. Deploy
  5. Ajouter une route : monsite.com/ → votre worker

Avantages :

  • Fonctionne même si le serveur est down
  • Code 503 correct avec Retry-After
  • Bypass par IP possible
  • Exclusion de chemins (API, webhooks)
  • Personnalisation totale

Rate Limiting contre les surcharges

Le Rate Limiting de Cloudflare peut prévenir les 503 en bloquant le trafic excessif avant qu’il n’atteigne votre serveur.

Configuration de base

Security > WAF > Rate limiting rules

Rule name: Protect against request floods
If: All requests
Rate: 100 requests per 10 seconds
From: Same IP address
Then: Block for 1 hour
With response type: Default Cloudflare rate limiting response

Rules avancées

Protection login

Rule name: Protect login
If: URI Path equals "/wp-login.php" OR URI Path contains "/admin"
Rate: 5 requests per 1 minute
From: Same IP address  
Then: Challenge (CAPTCHA)

Protection API

Rule name: API rate limit
If: URI Path starts with "/api/"
Rate: 60 requests per 1 minute
From: Same IP address
Then: Block for 10 minutes
With response type: Custom JSON
    {"error": "rate_limit_exceeded", "retry_after": 600}

Rate Limiting avec headers personnalisés

Pour les réponses 429 (Too Many Requests) au lieu de block :

Response personnalisée

Status: 429
Headers:
    Retry-After: 60
    X-RateLimit-Limit: 100
    X-RateLimit-Remaining: 0
Body: {"error": "Too many requests. Please wait 60 seconds."}

Firewall Rules et WAF

Bloquer le trafic suspect avant qu’il ne cause une 503

Security > WAF > Custom rules

# Bloquer les pays à haut risque (si non pertinents pour votre business)
Rule: Block high-risk countries
If: Country equals "CN" OR Country equals "RU" OR Country equals "KP"
Then: Block

# Challenge les User-Agents suspects
Rule: Challenge bad bots
If: User Agent contains "python-requests" 
    OR User Agent contains "curl"
    OR User Agent equals ""
Then: Managed Challenge

# Protéger les endpoints sensibles
Rule: Protect sensitive paths
If: URI Path contains "xmlrpc.php"
    OR URI Path contains "wp-config"
    OR URI Path contains ".env"
Then: Block

Bot Fight Mode

Activez Security > Bots > Bot Fight Mode pour bloquer automatiquement les bots malveillants connus.

Attention : Bot Fight Mode peut bloquer certains bots légitimes (monitoring, SEO tools). Utilisez les règles WAF pour créer des exceptions si nécessaire.

Super Bot Fight Mode (Pro+)

Permet de configurer finement le traitement des :

  • Definitely automated (bots confirmés)
  • Likely automated (probablement des bots)
  • Likely human (probablement humains)
  • Verified bots (Googlebot, etc.) → Toujours autoriser

Configuration DNS et Proxy

Modes de proxy

IcôneModeDescription
?? Nuage orangeProxiedTrafic passe par Cloudflare (protection + CDN)
⚪ Nuage grisDNS onlyCloudflare ne fait que DNS, pas de protection

Quand utiliser DNS-only

  • Serveurs mail (MX records)
  • FTP
  • SSH (si vous utilisez un sous-domaine)
  • Services qui ne supportent pas le proxy HTTP

Configuration recommandée

DNS Records

Type    Name        Content             Proxy
A       @           203.0.113.50        ?? Proxied
A       www         203.0.113.50        ?? Proxied
CNAME   api         @                   ?? Proxied
A       mail        203.0.113.50        ⚪ DNS only
MX      @           mail.monsite.com    - (MX, pas de proxy)
A       ssh         203.0.113.50        ⚪ DNS only

Restaurer l’IP réelle du visiteur

Quand Cloudflare est en proxy, votre serveur voit l’IP Cloudflare, pas celle du visiteur. Pour restaurer l’IP réelle :

Nginx :

/etc/nginx/conf.d/cloudflare.conf

# IPs Cloudflare IPv4
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;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;

# IPs Cloudflare IPv6
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;

# Header contenant l'IP réelle
real_ip_header CF-Connecting-IP;

Apache :

/etc/apache2/conf-available/cloudflare.conf

<IfModule mod_remoteip.c>
    RemoteIPHeader CF-Connecting-IP
    
    # IPs Cloudflare (IPv4)
    RemoteIPTrustedProxy 173.245.48.0/20
    RemoteIPTrustedProxy 103.21.244.0/22
    RemoteIPTrustedProxy 103.22.200.0/22
    RemoteIPTrustedProxy 103.31.4.0/22
    RemoteIPTrustedProxy 141.101.64.0/18
    RemoteIPTrustedProxy 108.162.192.0/18
    RemoteIPTrustedProxy 190.93.240.0/20
    RemoteIPTrustedProxy 188.114.96.0/20
    RemoteIPTrustedProxy 197.234.240.0/22
    RemoteIPTrustedProxy 198.41.128.0/17
    RemoteIPTrustedProxy 162.158.0.0/15
    RemoteIPTrustedProxy 104.16.0.0/13
    RemoteIPTrustedProxy 104.24.0.0/14
    RemoteIPTrustedProxy 172.64.0.0/13
    RemoteIPTrustedProxy 131.0.72.0/22
</IfModule>
$ a2enmod remoteip
$ a2enconf cloudflare
$ systemctl restart apache2

Checklist de configuration Cloudflare

Diagnostic avec les outils Cloudflare

Analytics et Logs

Dashboard > Analytics > Traffic :

  • Voir le trafic par code de réponse
  • Identifier les pics de 503
  • Analyser les requêtes bloquées

Dashboard > Analytics > Security :

  • Requêtes bloquées par le WAF
  • Challenges émis
  • Menaces détectées

Trace Route

Dashboard > votre domaine > Troubleshoot :

  • Test de connectivité Cloudflare → Origine
  • Identification des problèmes réseau

Via l’API

# Récupérer les analytics
$ curl -X GET "https://api.cloudflare.com/client/v4/zones/ZONE_ID/analytics/dashboard" \\
    -H "Authorization: Bearer API_TOKEN"

# Voir les événements de sécurité
$ curl -X GET "https://api.cloudflare.com/client/v4/zones/ZONE_ID/security/events" \\
    -H "Authorization: Bearer API_TOKEN"

Logs en temps réel (Enterprise)

Pour les plans Enterprise, Cloudflare Logs permet d’exporter tous les logs vers votre SIEM ou solution d’analyse.

Scénarios courants et solutions

Scénario 1 : Migration DNS vers Cloudflare

Checklist migration

1. [ ] Noter les DNS actuels
2. [ ] Créer le compte Cloudflare et ajouter le site
3. [ ] Importer/recréer les DNS records
4. [ ] Configurer SSL (Full Strict si possible)
5. [ ] Changer les NS chez le registrar
6. [ ] Attendre la propagation (24-48h)
7. [ ] Vérifier que le site fonctionne
8. [ ] Activer les fonctionnalités de sécurité progressivement

Scénario 2 : Le site affiche 521 après activation de Cloudflare

Problème : Votre pare-feu bloque les IPs Cloudflare.

Solution :

# Autoriser les IPs Cloudflare dans UFW
$ for ip in $(curl -s https://www.cloudflare.com/ips-v4); do
    ufw allow from $ip to any port 80,443 proto tcp
done

# Ou dans iptables
$ for ip in $(curl -s https://www.cloudflare.com/ips-v4); do
    iptables -A INPUT -s $ip -p tcp --dport 80 -j ACCEPT
    iptables -A INPUT -s $ip -p tcp --dport 443 -j ACCEPT
done

Scénario 3 : Maintenance planifiée avec zéro downtime perçu

Stratégie Worker + Cache

// 1. Pré-cacher les pages importantes
// Dashboard > Caching > Tiered Cache → Activé

// 2. Déployer le Worker de maintenance 5 min avant

// 3. Le Worker sert la page 503 avec Retry-After

// 4. Effectuer la maintenance sur l'origine

// 5. Tester l'origine directement (bypass Cloudflare via hosts)

// 6. Désactiver le Worker

// 7. Purger le cache si nécessaire

Scénario 4 : DDoS en cours

# Actions immédiates via Dashboard :
1. Overview > Under Attack Mode → ON
2. Security > WAF > Créer règle "Block all except whitelist"
3. Security > Settings > Security Level → I'm Under Attack

# Ou via API pour automatisation :
$ curl -X PATCH "https://api.cloudflare.com/client/v4/zones/ZONE_ID/settings/security_level" \\
    -H "Authorization: Bearer TOKEN" \\
    --data '{"value":"under_attack"}'

Configuration Cloudflare optimisée

Audit, mise en place, monitoring. Protection DDoS et haute disponibilité.

Questions fréquentes

Cloudflare gratuit suffit-il pour protéger mon site ?

Pour la plupart des sites, oui. Le plan gratuit inclut : CDN mondial, protection DDoS de base, SSL gratuit, et 5 Page Rules. Pour des fonctionnalités avancées (WAF managé, Rate Limiting illimité, logs détaillés), les plans Pro (20$/mois) ou Business sont recommandés. Pour les sites critiques ou à fort trafic, Enterprise offre un SLA et un support dédié.

Mon webhook de paiement ne fonctionne plus depuis Cloudflare, pourquoi ?

Probablement à cause du mode Under Attack, du Bot Fight Mode, ou d’une règle WAF. Les webhooks sont des requêtes machine-to-machine qui peuvent être bloquées. Solution : créez une règle WAF qui bypass les vérifications pour l’URL du webhook, ou passez ce sous-domaine en DNS-only.

Comment savoir si une erreur vient de Cloudflare ou de mon serveur ?

Regardez les headers HTTP avec curl -I. Si vous voyez un code 52x (520-526), c’est Cloudflare qui signale un problème avec votre origine. Si c’est un 503 avec votre contenu personnalisé, c’est votre serveur. Le header cf-ray est présent dans les deux cas mais le server: cloudflare ne dit pas qui a généré l’erreur.

Cloudflare ralentit-il mon site ?

Non, généralement il l’accélère grâce au CDN (cache en edge, plus proche des visiteurs) et à l’optimisation (compression, minification). Le seul ralentissement possible est le challenge de 5 secondes en mode Under Attack, qui ne devrait être activé qu’en cas d’attaque réelle.