SSL handshake failed: error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure. Cette ligne, remontée par les journaux du CDN à raison d’environ une requête sur six pendant plusieurs heures, ne correspondait à aucune alerte côté navigateur : les visiteurs continuaient de voir le site s’afficher normalement, cadenas compris. Le problème ne se situait pas entre le visiteur et le CDN, mais entre le CDN et le serveur d’origine.
Ce cas concerne un site WordPress dont le CDN était déjà en place et fonctionnel depuis plusieurs mois ; la mise en place initiale de ce CDN n’est pas le sujet ici. L’incident a démarré juste après le renouvellement automatique du certificat TLS sur l’un des trois serveurs d’origine d’une ferme derrière un répartiteur de charge.
Symptôme : des échecs intermittents et invisibles pour l’utilisateur
Le comportement le plus déroutant de cet incident tenait à son intermittence. Sur trois serveurs d’origine identiques en apparence, un seul renvoyait des échecs de négociation TLS au CDN, sans qu’aucune erreur ne soit visible côté public : le CDN, configuré pour retenter automatiquement sur un autre serveur d’origine en cas d’échec, masquait le problème aux visiteurs tout en dégradant silencieusement les temps de réponse moyens.
Diagnostic : isoler le serveur fautif

Première étape du diagnostic : interroger directement chaque serveur d’origine, en contournant le répartiteur de charge et le CDN, avec openssl s_client pointé successivement sur chacune des trois adresses IP internes.
openssl s_client -connect 10.0.4.12:443 -servername exemple.fr -tls1_2
CONNECTED(00000003)
depth=0 CN = exemple.fr
verify error:num=21:unable to verify the first certificate
---
Certificate chain
0 s:CN = exemple.fr
i:C = US, O = Let's Encrypt, CN = R3
---
SSL handshake has read 1834 bytes and written 391 bytes
New, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256
La commande a mis en évidence un détail facile à manquer : sur le serveur fautif, le certificat feuille était bien présent et valide, mais la chaîne intermédiaire renvoyée était incomplète. Le renouvellement automatique venait de basculer d’une autorité intermédiaire à une autre chez Let’s Encrypt, et le fichier de chaîne complète (fullchain.pem) n’avait pas été régénéré correctement sur ce serveur précis lors du dernier passage du script de renouvellement.
Pourquoi le CDN, spécifiquement, était sensible
Un navigateur classique tolère souvent une chaîne intermédiaire incomplète, car il peut aller chercher lui-même le certificat manquant via l’extension AIA (Authority Information Access) du certificat, ou dispose déjà de l’intermédiaire en cache local. Le CDN, lui, effectuait une validation stricte de la chaîne complète sans ce filet de rattrapage, rejetant purement et simplement la connexion vers cette origine dès que la chaîne était incomplète.
Correctif : régénérer et vérifier la chaîne complète
Le correctif a consisté à forcer une régénération du certificat sur le serveur concerné, en vérifiant explicitement le contenu du fichier de chaîne avant de redémarrer le service web.
- Régénération forcée du certificat via
certbot renew --force-renewalsur le serveur identifié. - Vérification du fichier
fullchain.pemavecopenssl crl2pkcs7 -nocrl -certfile fullchain.pem | openssl pkcs7 -print_certs -noout, qui doit afficher deux entrées : le certificat du site et l’intermédiaire. - Rechargement du service
nginx(et non un simple redémarrage) pour prendre en compte le nouveau certificat sans coupure de connexion. - Nouveau test
openssl s_clientconfirmant une chaîne complète et une négociation TLS 1.2 réussie sans avertissement.
Prévention : surveiller chaque origine, pas seulement le domaine public
La leçon la plus utile de cet incident concerne la supervision. Un test de certificat classique, effectué depuis l’extérieur sur le nom de domaine public, ne passe que par le CDN et ne révèle jamais l’état réel de chaque serveur d’origine derrière lui. Une supervision efficace doit interroger directement chaque adresse IP d’origine, en contournant volontairement le CDN, pour détecter ce genre de divergence avant qu’elle ne dégrade le service.
Un repère qu’on applique systématiquement depuis cet incident : sur une ferme de plusieurs serveurs d’origine, tester chaque nœud individuellement après chaque renouvellement de certificat, jamais uniquement le nom de domaine public.
En résumé
Un échec de négociation TLS entre un CDN et son origine peut rester totalement invisible côté utilisateur final tout en dégradant la fiabilité du service de façon insidieuse. La cause tient souvent à une chaîne de certificats intermédiaire incomplète, plus tolérée par les navigateurs que par les CDN eux-mêmes. Une vérification systématique de chaque serveur d’origine après tout renouvellement automatique de certificat reste la meilleure prévention contre ce type d’incident silencieux.