L’aide AdSense de Google range deux problèmes de HTTPS parmi les raisons qui rendent un site inapte à afficher des annonces : un certificat qui n’est pas valide, et l’absence de redirection de HTTP vers HTTPS. On les croit réglés une fois pour toutes, et on les règle souvent à moitié, parce que HTTPS regroupe quatre éléments qui tombent en panne séparément. Le certificat doit continuer à se renouveler, la redirection doit aboutir à une seule adresse, un en-tête doit demander aux navigateurs de s’en souvenir, et aucune page ne doit charger quoi que ce soit en HTTP simple. Le cadenas de votre page d’accueil prouve que le certificat est valide aujourd’hui. Il ne dit rien des trois autres.
Vérifier le certificat par ses dates
Un cadenas indique que le certificat fonctionne maintenant. Ce qu’il vous faut savoir, c’est quand il cessera de fonctionner et si quelque chose le remplacera. Une seule commande affiche les dates directement depuis le serveur, sans passer par un navigateur :
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates
L’option -servername compte. Un serveur qui héberge plusieurs sites choisit le certificat d’après ce nom, et sans elle vous risquez de voir celui d’un autre site. Le echo | referme la connexion dès que la négociation est terminée. Lancez la même commande pour www.example.com : un visiteur qui tape www arrive d’abord sur cet hôte, et un nom qui ne correspond pas y déclenche un avertissement plein écran, affiché avant qu’une redirection ait pu avoir lieu. Pour lister les noms couverts par un certificat, remplacez -dates par -ext subjectAltName (OpenSSL 1.1.1 ou plus récent).
Pour transformer ce contrôle en alarme, -checkend fait échouer la commande si le certificat expire dans le nombre de secondes indiqué. Ici, 1209600 secondes, soit 14 jours :
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
| openssl x509 -noout -checkend 1209600
Lancez-la depuis cron ou votre outil de supervision, et envoyez l’échec à un endroit que vous lirez vraiment. Avec une autorité gratuite comme Let’s Encrypt, c’est le renouvellement automatique qui maintient le site en ligne, et il casse pour des raisons banales : une racine web déplacée, une règle de pare-feu sur le port 80, un timer supprimé. Si vous utilisez certbot, certbot renew --dry-run répète un renouvellement sans rien émettre. Relancez-le après chaque modification du serveur.
Une seule redirection vers une seule adresse finale
Le HTTP simple ne devrait jamais servir de page. Il doit répondre par une redirection permanente vers l’adresse HTTPS finale, en une seule étape, car chaque saut supplémentaire coûte un aller-retour au visiteur. Google lit un 301 comme un signal fort sur l’adresse préférée et un 302 comme un signal faible : utilisez donc un 301. Il suit jusqu’à 10 sauts, ce qui rend une chaîne plus longue coûteuse, sans être fatale. Voici la version nginx, avec les deux mêmes petits blocs que dans notre guide sur la balise canonical, plus le chemin de validation du certificat :
# Port 80 : aucun contenu, seulement une redirection vers l'adresse finale
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
# La validation du certificat répond ici au lieu d'être redirigée
location ^~ /.well-known/acme-challenge/ { root /var/www/example.com; }
location / { return 301 https://example.com$request_uri; }
}
# Port 443, www : un seul saut vers le domaine sans www
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
return 301 https://example.com$request_uri;
}
Sous Apache, mod_ssl doit être activé (a2enmod ssl sur Debian et Ubuntu). La directive Redirect de mod_alias conserve le chemin et la chaîne de requête :
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
Redirect permanent / https://example.com/
</VirtualHost>
<VirtualHost *:443>
ServerName www.example.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
Redirect permanent / https://example.com/
</VirtualHost>
Si vous n’avez pas accès au virtual host, la règle .htaccess du guide sur la balise canonical remplit le même rôle. Validez la configuration avant de la recharger (nginx -t, apachectl configtest), puis interrogez chaque variante une fois. Sans l’option -L, curl -sI n’affiche qu’un seul saut : vous lisez ainsi vers quelle adresse chaque variante envoie les visiteurs.
for u in http://example.com/ http://www.example.com/ https://www.example.com/ https://example.com/; do
echo "== $u"
curl -sI "$u" | grep -iE '^(HTTP|location)'
done
Les 3 premières variantes doivent chacune afficher un seul 301 dont le Location est https://example.com/, et la dernière doit afficher un 200 sans aucun Location. Un Location qui n’est pas l’adresse finale trahit une chaîne. Une fois la chaîne propre, alignez le reste dessus : balises canonical, entrées du sitemap et liens internes doivent tous désigner l’adresse HTTPS. Google lit aussi le fichier robots.txt par hôte et par protocole : il doit donc répondre sur l’hôte HTTPS, comme l’explique le guide des erreurs de robots.txt.
Ajouter HSTS par paliers
Une redirection laisse encore la première requête de chaque visite circuler en HTTP simple. HSTS comble cette brèche. Dès qu’un navigateur a reçu l’en-tête dans une réponse HTTPS, il se connecte de lui-même à votre site en HTTPS pendant le nombre de secondes indiqué, même si un lien pointe vers http://. Le prix à payer est la même fonction vue de l’autre côté. Si vous cassez ensuite HTTPS sur un hôte couvert, les visiteurs qui ont reçu l’en-tête obtiennent une erreur bloquante plutôt qu’un avertissement qu’on peut passer, et rien sur votre serveur ne peut aller la défaire dans leur navigateur. Chaque réponse qui porte l’en-tête relance le compte à rebours : sur un site fréquenté, un max-age long est presque définitif.
Pour cette raison, nous recommandons d’augmenter la valeur en 4 paliers, en ne passant au suivant que lorsque le précédent n’a rien révélé d’anormal. Envoyer max-age=0 en HTTPS retire la règle des navigateurs qui reviennent : les premiers paliers sont donc faciles à annuler, le dernier ne l’est pas.
| Palier | Valeur de l’en-tête | Durée | Passer au suivant quand |
|---|---|---|---|
| 1 | max-age=300; includeSubDomains | 5 minutes | chaque type de page et chaque sous-domaine s’est chargé en HTTPS sans avertissement |
| 2 | max-age=86400; includeSubDomains | 1 jour | une journée de trafic normal s’est écoulée sans plainte de certificat ni de contenu mixte |
| 3 | max-age=15552000; includeSubDomains | 180 jours | vous êtes certain qu’aucun hôte couvert n’aura plus besoin de HTTP simple |
| 4 | max-age=63072000; includeSubDomains | 2 ans | valeur finale |
Nous mettons includeSubDomains dès le palier 1, volontairement. Si vous comptez l’utiliser à terme, un sous-domaine oublié sans HTTPS ne coûte alors que 5 minutes d’accès perdu aux visiteurs qui ont chargé votre site, et vous le découvrez quand l’erreur est encore bon marché. N’ajoutez cette option qu’après avoir listé tous vos enregistrements DNS, y compris l’hôte de préproduction et l’ancien hôte de messagerie. Sous nginx, l’en-tête se place dans le bloc server HTTPS du domaine sans www :
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com;
# ssl_certificate et ssl_certificate_key comme dans le bloc www
add_header Strict-Transport-Security "max-age=300; includeSubDomains" always;
}
Sous Apache, il faut mod_headers (a2enmod headers), et la ligne va dans le virtual host HTTPS du domaine sans www :
Header always set Strict-Transport-Security "max-age=300; includeSubDomains"
Le mot-clé always fait apparaître l’en-tête aussi sur les pages d’erreur. Vérifiez-le avec curl -sI https://example.com/ | grep -i '^strict-transport', qui doit afficher exactement 1 ligne. Un add_header placé plus loin, dans un bloc location, peut supprimer l’en-tête sans bruit pour cet emplacement : nous décrivons ce piège dans le guide des en-têtes de sécurité.
Le preload vient en dernier, si jamais
La liste de préchargement (preload) est une copie de la règle HSTS livrée avec les navigateurs : même une première visite passe alors directement en HTTPS. Le site de soumission, hstspreload.org, exige un certificat valide, une redirection de HTTP vers HTTPS sur le même hôte, HTTPS sur tous les sous-domaines, et un en-tête sur le domaine sans www avec un max-age d’au moins 31536000 (1 an), includeSubDomains et preload. Il prévient aussi qu’un retrait est difficile et prend des mois.
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Deux conséquences comptent avant d’ajouter ce dernier mot. D’abord, chaque sous-domaine, actuel et futur, doit fonctionner en HTTPS, y compris ceux dont plus personne ne se souvient. Ensuite, la règle du même hôte change le conseil de redirection donné plus haut. http://www.example.com doit d’abord aller vers https://www.example.com, et seul cet hôte renvoie ensuite le visiteur vers le domaine sans www. La variante www fait donc 2 sauts au lieu d’1. C’est sans gravité pour Google, qui en suit jusqu’à 10, mais ce n’est plus l’étape unique que nous avons dessinée. Le bloc du port 80 de notre propre serveur fonctionne ainsi : il redirige d’abord vers le même hôte.
Nous n’envoyons pas preload. Cette option protège la seule visite que HSTS ne couvre pas, la toute première, avant que le navigateur ait vu votre en-tête. Pour un site de contenu qui redirige déjà et envoie un en-tête de 2 ans, nous jugeons ce gain trop faible au regard d’une sortie qui prend des mois. C’est notre jugement, pas une règle : un site qui gère des connexions ou des paiements peut le peser autrement.
Traquer le contenu mixte qui annule le cadenas
On parle de contenu mixte quand une page HTTPS charge un script, une feuille de style, une image, une police, un cadre ou un fichier média depuis une adresse http://. Les navigateurs bloquent ou signalent ces requêtes. Les symptômes : une feuille de style qui ne se charge pas, une intégration qui reste vide ou un cadenas qui se change en avertissement, en général sur quelques anciennes pages qui écrivent en dur l’ancienne adresse. Les sources habituelles sont les articles importés avant le passage en HTTPS, dont les URL d’images absolues en http:// sont enregistrées dans la base de données, les gabarits dont le protocole est écrit en dur, un url(http://...) dans une feuille de style, et les intégrations tierces collées il y a des années.
La console des outils de développement du navigateur liste chaque requête signalée, une page à la fois. Pour un site statique, analysez plutôt le résultat de la compilation (ici le dossier dist/) :
grep -rhEo '(src|href)="http://[^"]+"' dist/ | sort | uniq -c | sort -rn | head -20
Toutes les correspondances ne posent pas problème. Un <a href> vers un site extérieur qui ne propose que HTTP est un simple lien, alors qu’un src ou un <link rel="stylesheet"> est une vraie fuite. Sous WordPress, WP-CLI peut réécrire les adresses enregistrées. Faites une sauvegarde, lancez la commande une première fois avec --dry-run et lisez les compteurs avant le passage réel :
wp search-replace 'http://example.com' 'https://example.com' --dry-run
Une Content-Security-Policy contenant upgrade-insecure-requests demande aux navigateurs de charger en HTTPS les sous-ressources en http://. Nous l’emploierions comme filet de sécurité et non comme correctif : elle échoue pour toute ressource dont l’hôte n’a pas de version HTTPS, et elle masque l’origine du problème. Les politiques en mode Report-Only et les autres directives sont dans le guide des en-têtes de sécurité.
Ce que nous faisons tourner, mesuré le 7 octobre 2026
Notre serveur envoie Strict-Transport-Security: max-age=63072000; includeSubDomains, redirige www vers le domaine sans www par un 301 et utilise un certificat Let’s Encrypt qui se renouvelle automatiquement. Le 7 octobre 2026, nous avons lancé les commandes de ce guide sur notre propre domaine :
$ curl -sI https://greenlightmysite.com/ | grep -i '^strict-transport'
Strict-Transport-Security: max-age=63072000; includeSubDomains
$ curl -sI https://www.greenlightmysite.com/ | grep -iE '^(HTTP|location)'
HTTP/1.1 301 Moved Permanently
Location: https://greenlightmysite.com/
$ echo | openssl s_client -connect greenlightmysite.com:443 -servername greenlightmysite.com 2>/dev/null | openssl x509 -noout -dates
notBefore=Sep 5 07:41:00 2026 GMT
notAfter=Dec 4 07:40:59 2026 GMT
Le certificat court du 5 septembre au 4 décembre 2026 : 90 jours, ce qui explique pourquoi le renouvellement automatique n’est pas facultatif chez nous. Le seul résultat imparfait est http://www.greenlightmysite.com/ : cette adresse passe d’abord, sur le même hôte, en HTTPS, puis va vers le domaine sans www, soit 2 sauts là où l’étape unique décrite plus haut suffirait. Nous ne l’avons pas modifié, et c’est la forme à conserver si nous soumettions un jour le domaine à la liste de préchargement. Notre vérificateur SEO teste HSTS dans sa catégorie des en-têtes de sécurité, et notre vérificateur AdSense indique l’état de HTTPS et la longueur de la chaîne de redirection de la page d’accueil.
Réponses rapides
Faut-il un certificat payant pour AdSense ?
L'aide AdSense sur laquelle nous nous appuyons demande un certificat valide, sans nommer d'émetteur ni de prix. Notre propre site tourne avec un certificat Let's Encrypt gratuit, et le contrôle HTTPS de notre vérificateur AdSense était au vert quand nous avons audité le site le 7 octobre 2026.
Pourquoi curl n'affiche-t-il aucun en-tête Strict-Transport-Security sur mon adresse http:// ?
C'est normal. Les navigateurs ignorent l'en-tête quand il arrive en HTTP simple, puisque n'importe qui sur le trajet réseau aurait pu l'y glisser : il ne se place donc que sur les réponses HTTPS. Testez avec curl -sI sur l'adresse en https://.
Mon site est derrière un CDN ou un proxy qui gère le HTTPS. Où placer ces réglages ?
Placez la redirection et l'en-tête à l'étage qui termine la connexion HTTPS, puisque c'est lui que les visiteurs interrogent, et testez avec curl depuis l'extérieur de votre réseau. Si le proxy et votre serveur d'origine ajoutent tous deux Strict-Transport-Security, comptez les lignes renvoyées par curl -sI : il doit y en avoir exactement 1.