Migration HTTP vers HTTPS : checklist SEO complète

En 2024, un e-commerce mode de 12 000 pages a perdu 34 % de son trafic organique pendant 11 semaines après une migration HTTPS mal exécutée. Pas à cause du certificat — à cause de redirections en chaîne, de canonical HTTP résiduels dans le <head>, et d'un sitemap qui pointait encore vers les anciennes URLs. Tout était techniquement "en HTTPS", mais Google continuait d'indexer les versions HTTP.

La migration HTTP vers HTTPS est considérée comme triviale par beaucoup de développeurs. Installer un certificat Let's Encrypt, activer une règle de redirect, terminé. En réalité, c'est une migration d'URLs à part entière — chaque URL HTTP est une ancienne URL qui doit être correctement redirigée, désindexée, et remplacée dans tous les signaux que Google utilise pour évaluer votre site.

Pré-requis : auditer l'état HTTP avant de toucher quoi que ce soit

Avant d'activer la moindre redirection, vous avez besoin d'un snapshot complet de votre site en HTTP. Sans cette baseline, vous n'aurez aucun moyen de mesurer l'impact de la migration ni de diagnostiquer les problèmes post-migration.

Crawl complet du site HTTP

Lancez un crawl exhaustif avec Screaming Frog (ou Sitebulb) en configurant le crawler sur le protocole http://. Exportez :

  • La liste complète des URLs crawlées (HTML, images, CSS, JS)
  • Les canonical déclarés sur chaque page
  • Les hreflang (si site multilingue — voir architecture technique multilingue)
  • Les liens internes et leur protocole
  • Les réponses HTTP (200, 301, 404, etc.)

Ce crawl est votre référence. Vous le comparerez au crawl post-migration pour identifier chaque divergence.

Snapshot des positions et du trafic

Dans Google Search Console, exportez les données de performance (clics, impressions, CTR, position moyenne) par page sur les 3 derniers mois. Faites la même chose dans votre outil analytics. Ces données serviront de baseline pour mesurer l'impact.

Si vous suivez des KPIs SEO techniques avec des dashboards automatisés, prenez un snapshot daté le jour J-1 de la migration.

Inventaire des signaux externes

Vos backlinks pointent vers des URLs HTTP. Votre sitemap est en HTTP. Vos profils Google Business, vos réseaux sociaux, vos annuaires — tout référence le protocole HTTP. Listez ces sources. Vous ne pourrez pas toutes les mettre à jour immédiatement, mais vous devez savoir d'où viennent les signaux pour prioriser.

Utilisez Ahrefs ou Majestic pour exporter la liste des backlinks avec le protocole exact (http vs https). Triez par Domain Rating : les backlinks les plus puissants méritent une demande de mise à jour auprès des webmasters.

Certificat SSL/TLS : choix et installation

Quel type de certificat

Pour la majorité des sites, un certificat DV (Domain Validation) via Let's Encrypt suffit. Google ne fait aucune distinction SEO entre un certificat DV gratuit et un certificat EV à 500 €/an — c'est confirmé dans la documentation Google sur HTTPS.

Si vous gérez un site avec des sous-domaines multiples (shop.example.fr, blog.example.fr, app.example.fr), optez pour un certificat wildcard (*.example.fr) pour simplifier la gestion.

Installation et vérification

Sur un serveur Ubuntu avec Nginx et Certbot :

# Installation de Certbot pour Nginx
sudo apt update && sudo apt install certbot python3-certbot-nginx -y

# Génération du certificat (wildcard avec DNS challenge)
sudo certbot certonly --manual --preferred-challenges=dns \
  -d example.fr -d *.example.fr

# Vérification de la date d'expiration
sudo openssl x509 -in /etc/letsencrypt/live/example.fr/fullchain.pem -noout -dates

# Test de la configuration SSL
openssl s_client -connect example.fr:443 -servername example.fr

Vérifiez que la chaîne de certificats est complète (certificat du serveur + intermédiaire). Une chaîne incomplète provoque des erreurs sur certains clients et peut empêcher Googlebot d'accéder au site. Testez avec SSL Labs Server Test — visez un grade A minimum.

Configuration TLS dans Nginx

La configuration TLS impacte à la fois la sécurité et la performance (et donc le crawl). Voici une configuration Nginx production-ready :

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

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

    # Protocoles et ciphers modernes
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    # OCSP Stapling (réduit la latence du handshake TLS)
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 1.1.1.1 8.8.8.8 valid=300s;

    # Session caching
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;

    # HSTS (à activer APRÈS validation complète — voir section dédiée)
    # add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

    root /var/www/example.fr;
    index index.html;
}

Point critique : ne commentez pas le HSTS par défaut. Activez-le uniquement après avoir validé que tout fonctionne en HTTPS. Un HSTS mal configuré avec includeSubDomains sur un sous-domaine qui n'a pas de certificat rend ce sous-domaine totalement inaccessible.

Redirections : le cœur de la migration

C'est ici que 80 % des migrations échouent. La redirection HTTP → HTTPS est une migration d'URL. Chaque URL HTTP doit retourner une 301 vers son équivalent HTTPS exact — même path, mêmes query parameters.

Règle de redirection globale

Dans Nginx, la redirection doit être gérée dans un bloc server dédié au port 80 :

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

    # Redirection 301 globale HTTP → HTTPS
    # $request_uri préserve le path ET les query strings
    return 301 https://$host$request_uri;
}

Sur Apache, dans le .htaccess ou la configuration du VirtualHost :

<VirtualHost *:80>
    ServerName example.fr
    ServerAlias www.example.fr

    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</VirtualHost>

Les erreurs classiques qui détruisent le trafic

Chaînes de redirections. Le scénario le plus fréquent : http://example.frhttps://example.frhttps://www.example.fr. Deux redirections en chaîne. Googlebot les suit, mais chaque hop dilue le PageRank transmis et ralentit le crawl. Si vous gérez aussi la migration www vers non-www (ou l'inverse), faites une seule redirection directe :

# MAUVAIS : chaîne de redirections
server {
    listen 80;
    server_name example.fr;
    return 301 https://example.fr$request_uri;
    # Puis un autre bloc redirige https://example.fr → https://www.example.fr
}

# BON : redirection directe vers la destination finale
server {
    listen 80;
    server_name example.fr www.example.fr;
    return 301 https://www.example.fr$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.fr;
    return 301 https://www.example.fr$request_uri;
}

Redirections en 302 au lieu de 301. Certains frameworks (Express.js, Django) redirigent en 302 par défaut. Une 302 indique à Google que la redirection est temporaire — il peut continuer d'indexer l'URL HTTP. Vérifiez explicitement le code de statut dans vos headers.

Query strings perdues. Si votre e-commerce utilise des paramètres de filtrage (/chaussures?couleur=rouge&taille=42), vérifiez que la redirection les préserve. Avec $request_uri dans Nginx, c'est le cas. Avec certaines configurations CDN (Cloudflare Page Rules mal configurées), les query strings peuvent être strippées.

Vérification post-redirection

Testez un échantillon d'URLs avec curl pour valider le comportement exact :

# Vérifier le code de redirection et la destination
curl -I http://www.example.fr/categorie/chaussures-homme?tri=prix-asc

# Résultat attendu :
# HTTP/1.1 301 Moved Permanently
# Location: https://www.example.fr/categorie/chaussures-homme?tri=prix-asc

# Vérifier qu'il n'y a pas de chaîne
curl -ILs http://example.fr/categorie/chaussures-homme 2>&1 | grep -E "HTTP/|Location:"

# Résultat attendu : un seul 301, puis un 200 sur la destination HTTPS finale

Avec Screaming Frog, recrawlez le site en mode http:// et vérifiez que toutes les URLs retournent un 301 vers leur équivalent HTTPS exact. Exportez les redirections en chaîne (Redirect Chains report) et corrigez chaque cas.

Mixed content : le piège silencieux

Votre page se charge en HTTPS, mais elle inclut une image en http://, un script en http://, ou une feuille CSS en http://. C'est du mixed content. Les navigateurs modernes bloquent le mixed content actif (scripts, iframes) et affichent des avertissements pour le mixed content passif (images). Google ne considère pas une page comme "sécurisée" si elle contient du mixed content actif.

Identifier le mixed content

Dans Chrome DevTools (onglet Console ou Security), les erreurs de mixed content apparaissent clairement. Mais pour un site de 12 000 pages, vous ne pouvez pas vérifier manuellement chaque page.

Screaming Frog permet de détecter le mixed content : crawlez le site en HTTPS, puis filtrez les ressources externes chargées en HTTP (Images > Protocol = HTTP, Scripts > Protocol = HTTP, etc.).

Pour une approche plus systématique, utilisez un header CSP en mode report-only :

# Dans votre configuration Nginx HTTPS
add_header Content-Security-Policy-Report-Only
    "default-src https: 'unsafe-inline' 'unsafe-eval'; report-uri /csp-report-endpoint"
    always;

Puis implémentez un endpoint qui collecte les violations :

// Express.js — endpoint de collecte des rapports CSP
const express = require('express');
const app = express();

app.use('/csp-report-endpoint', express.json({ type: 'application/csp-report' }));

app.post('/csp-report-endpoint', (req, res) => {
  const report = req.body['csp-report'];
  if (report && report['blocked-uri'] && report['blocked-uri'].startsWith('http:')) {
    console.log(JSON.stringify({
      page: report['document-uri'],
      blockedResource: report['blocked-uri'],
      directive: report['violated-directive'],
      timestamp: new Date().toISOString()
    }));
  }
  res.sendStatus(204);
});

app.listen(3000);

Laissez tourner 48 heures en production. Vous obtiendrez la liste exhaustive de toutes les ressources HTTP chargées sur vos pages HTTPS, classées par page.

Corriger le mixed content

Les sources principales de mixed content :

  • Images hardcodées en base de données : les URLs d'images insérées dans le contenu éditorial via un CMS. Requête SQL pour corriger en masse :
-- WordPress : mise à jour des URLs dans le contenu des articles
UPDATE wp_posts
SET post_content = REPLACE(post_content, 'http://cdn.example.fr', 'https://cdn.example.fr')
WHERE post_content LIKE '%http://cdn.example.fr%';

-- Idem pour les métadonnées (images à la une, etc.)
UPDATE wp_postmeta
SET meta_value = REPLACE(meta_value, 'http://cdn.example.fr', 'https://cdn.example.fr')
WHERE meta_value LIKE '%http://cdn.example.fr%';
  • Scripts et stylesheets tiers : Google Fonts, bibliothèques jQuery hébergées en HTTP, pixels de tracking anciens. Mettez à jour les références ou passez en protocol-relative (//fonts.googleapis.com/...) — bien que l'utilisation explicite de https:// soit préférable.

  • Ressources injectées par JavaScript : certains widgets (chat, analytics, pubs) génèrent dynamiquement des URLs HTTP. Vérifiez les scripts tiers et mettez à jour les versions.

Si vous utilisez un CDN comme Cloudflare, activez "Automatic HTTPS Rewrites" pour corriger à la volée le mixed content passif. C'est un filet de sécurité, pas une solution pérenne — corrigez les sources.

Signaux de référencement : tout mettre à jour

La redirection seule ne suffit pas. Google utilise de multiples signaux pour déterminer l'URL canonique d'une page. Si ces signaux se contredisent (la redirection dit HTTPS, mais le canonical dit HTTP), Google hésite et peut conserver l'ancienne URL dans l'index pendant des semaines.

Canonical tags

Chaque page doit déclarer un canonical en HTTPS :

<!-- AVANT migration -->
<link rel="canonical" href="http://www.example.fr/categorie/chaussures-homme" />

<!-- APRÈS migration -->
<link rel="canonical" href="https://www.example.fr/categorie/chaussures-homme" />

C'est le signal le plus oublié. Dans un CMS headless, le canonical est souvent généré dynamiquement côté application. Vérifiez le code source de génération, pas seulement le rendu d'une page.

Si votre site utilise un headless CMS, le canonical est typiquement construit à partir d'une variable d'environnement (SITE_URL ou équivalent). Changez cette variable de http:// en https:// et redeployez. Puis validez le rendu côté serveur.

Sitemap XML

Générez un nouveau sitemap avec toutes les URLs en HTTPS. Soumettez-le dans Google Search Console. Si votre ancien sitemap est référencé dans le robots.txt, mettez à jour cette référence :

# robots.txt — APRÈS migration
User-agent: *
Allow: /

Sitemap: https://www.example.fr/sitemap.xml

Ne supprimez pas l'ancien sitemap HTTP immédiatement. Pendant la phase de transition (4-8 semaines), avoir les deux sitemaps permet à Google de mieux comprendre la correspondance entre anciennes et nouvelles URLs.

Hreflang (sites multilingues)

Si vous avez des annotations hreflang, chaque URL référencée doit passer en HTTPS — y compris les URLs vers les versions linguistiques alternatives hébergées sur d'autres domaines ou sous-domaines. Un hreflang qui pointe vers http:// alors que la page redirige en HTTPS crée une incohérence qui peut déstabiliser l'indexation multilingue.

Liens internes

Même si les redirections 301 fonctionnent, vos liens internes doivent pointer directement vers les URLs HTTPS. Chaque lien interne en HTTP force une redirection, ce qui :

  • Ajoute 50-200 ms de latence par requête
  • Consomme inutilement du crawl budget
  • Transmet un signal ambigu à Google sur le protocole canonique

Faites un search-and-replace dans votre base de données, vos templates, et vos fichiers de configuration. Puis recrawlez pour vérifier qu'aucun lien interne ne pointe encore vers HTTP.

Open Graph et données structurées

Les balises og:url, og:image, et les URLs dans le JSON-LD (schema.org) doivent toutes passer en HTTPS. C'est souvent oublié parce que ces balises n'impactent pas directement le ranking — mais elles impactent l'affichage dans les SERP (rich snippets) et le partage social.

Google Search Console : propriétés et validation

Google Search Console traite http:// et https:// comme deux propriétés distinctes. C'est un point que beaucoup de SEO sous-estiment.

Créer la propriété HTTPS

Si vous utilisez une propriété de type "Domaine" (vérifiée par DNS), elle couvre automatiquement HTTP et HTTPS. Vous n'avez rien à faire.

Si vous utilisez une propriété de type "Préfixe d'URL" (la majorité des cas historiques), vous devez créer une nouvelle propriété https://www.example.fr et la vérifier. Ne supprimez pas l'ancienne propriété http:// — conservez-la pour surveiller la décroissance des impressions HTTP et détecter d'éventuels problèmes.

Soumettez le nouveau sitemap HTTPS dans la nouvelle propriété. Consultez les rapports Search Console que vous ignorez peut-être pour identifier les signaux de migration réussie.

Surveiller l'indexation post-migration

Dans la nouvelle propriété HTTPS, surveillez :

  • Couverture de l'index : les pages HTTPS doivent apparaître comme "Valides" progressivement. Les pages HTTP doivent passer en "Exclues — Page avec redirection".
  • Sitemaps : vérifiez que le nouveau sitemap est traité et que les URLs sont "Découvertes".
  • Performances : comparez les clics/impressions entre les propriétés HTTP et HTTPS sur une fenêtre glissante de 4 semaines.

La transition complète de l'index prend typiquement 2 à 8 semaines pour un site de 10 000-15 000 pages. Les sites avec un crawl fréquent (médias, e-commerce avec stock en temps réel) migrent plus vite parce que Googlebot passe plus souvent.

Pour automatiser cette surveillance, l'API Search Console permet d'extraire les données de couverture et de performance par propriété, et de déclencher des alertes si les métriques HTTPS ne progressent pas comme attendu.

HSTS : verrouiller la migration

Le header HTTP Strict-Transport-Security (HSTS) indique aux navigateurs de ne jamais charger votre site en HTTP, même si l'utilisateur tape http:// dans la barre d'adresse. C'est la dernière étape de la migration — et elle est irréversible si vous activez le preload.

Déploiement progressif du HSTS

Activez HSTS par paliers pour limiter les risques :

Semaine 1-2 : max-age court, sans includeSubDomains

add_header Strict-Transport-Security "max-age=300" always;

5 minutes. Si quelque chose casse, le navigateur oubliera la directive rapidement.

Semaine 3-4 : augmenter le max-age

add_header Strict-Transport-Security "max-age=86400" always;

24 heures. Surveillez les erreurs.

Semaine 5+ : max-age long avec includeSubDomains

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;

2 ans. C'est la valeur recommandée pour la soumission à la HSTS preload list.

Attention critique : includeSubDomains signifie que TOUS vos sous-domaines (staging.example.fr, api.example.fr, legacy-app.example.fr) doivent être accessibles en HTTPS avec un certificat valide. Si un sous-domaine interne utilise encore HTTP, il deviendra inaccessible pour tous les navigateurs qui ont reçu le header HSTS. Auditez vos sous-domaines avant d'activer cette directive.

HSTS Preload

Le preload inscrit votre domaine dans une liste intégrée aux navigateurs (Chrome, Firefox, Safari, Edge). Même la première visite sera forcée en HTTPS, avant même que le navigateur reçoive le header HSTS. C'est le niveau maximum de protection.

Soumettez votre domaine sur hstspreload.org uniquement quand vous êtes absolument certain que le HTTPS fonctionne partout. Le retrait de la preload list prend plusieurs mois.

Scénario réel : migration d'un e-commerce de 15 000 pages

Un e-commerce spécialisé en équipement outdoor. 15 200 pages indexées (fiches produits, catégories, pages CMS, blog). Stack : Nginx, PHP-FPM, WordPress + WooCommerce. CDN Cloudflare. 42 000 visites organiques/mois.

Chronologie

J-14 : crawl complet HTTP avec Screaming Frog. Export de 15 200 URLs en 200, 847 canonical tags, 0 hreflang (site monolingue). Identification de 312 liens internes hardcodés en http:// dans les descriptions produit (injectées via l'éditeur WYSIWYG).

J-7 : installation du certificat Let's Encrypt wildcard. Test SSL Labs : grade A. Mise à jour de WP_HOME et WP_SITEURL en https://. Exécution des requêtes SQL pour corriger les URLs dans wp_posts et wp_postmeta. Mise à jour du CDN Cloudflare : Full (Strict) SSL mode + Automatic HTTPS Rewrites activé.

J-1 : header CSP report-only déployé pendant 24h. Détection de 23 ressources mixtes (images de fournisseurs référencées en HTTP dans des fiches produit importées par flux). Correction manuelle.

J0 : activation de la redirection 301 HTTP → HTTPS dans Nginx. Déploiement du nouveau robots.txt et sitemap.xml en HTTPS. Création de la propriété HTTPS dans Search Console. Soumission du sitemap. HSTS activé avec max-age=300.

J+1 : crawl de vérification complet en HTTPS. 15 200 pages en 200. 0 mixed content détecté. 0 chaîne de redirection. Tous les canonical en HTTPS. Liens internes : 99,7 % en HTTPS (8 liens résiduels dans des widgets de sidebar, corrigés dans la journée).

J+3 : Search Console affiche 4 200 pages HTTPS indexées. Les impressions HTTP commencent à baisser.

J+14 : 12 800 pages HTTPS indexées. Trafic organique : -8 % vs baseline (fluctuation normale pendant la transition).

J+21 : HSTS passé à max-age=86400.

J+30 : 15 100 pages HTTPS indexées (99,3 %). Trafic organique revenu au niveau baseline (-1 %, dans la marge d'erreur).

J+45 : HSTS passé à max-age=63072000; includeSubDomains. Trafic organique : +3 % vs baseline (corrélation probable avec une légère amélioration du ranking — HTTPS est un signal de classement confirmé par Google, même si son poids est modeste).

J+60 : soumission au HSTS preload. Propriété HTTP Search Console conservée en lecture seule pour archivage.

Leçons de ce cas

Le creux de -8 % à J+14 est normal et documenté. Google doit recrawler et réindexer chaque page dans sa nouvelle version HTTPS. Pendant cette période, certaines pages sont encore indexées en HTTP, d'autres en HTTPS, et les signaux sont fragmentés. La durée du creux dépend directement de la fréquence de crawl de votre site.

La correction des 312 liens internes hardcodés en base de données a été le point le plus chronophage (3 heures de vérification et de requêtes SQL). Sur un site avec un contenu éditorial plus riche (média, blog avec des milliers d'articles), cette étape peut prendre une journée complète.

Monitoring post-migration et détection de régression

La migration ne s'arrête pas à J+30. Des régressions peuvent survenir des mois plus tard :

  • Un développeur ajoute une nouvelle page avec un canonical en HTTP parce que la variable d'environnement de staging a fuité en production
  • Un import de flux produit réintroduit des URLs d'images en HTTP
  • Un plugin WordPress mis à jour écrase la configuration HTTPS du sitemap
  • Une page 404 custom renvoie un canonical HTTP

Ce type de régression silencieuse est exactement le genre de problème qu'un outil de monitoring comme Seogard détecte automatiquement — un canonical qui change de protocole, une redirection qui passe de 301 à 302, du mixed content qui réapparaît sur des pages précédemment clean.

Intégrez des checks SEO dans votre pipeline CI/CD pour détecter ces régressions avant qu'elles n'atteignent la production. Un test simple mais efficace :

// Test CI — vérifier que toutes les pages déclarent un canonical HTTPS
const { test, expect } = require('@playwright/test');

test('canonical tags use HTTPS protocol', async ({ page }) => {
  const urls = [
    'https://www.example.fr/',
    'https://www.example.fr/categorie/chaussures-homme',
    'https://www.example.fr/produit/trail-runner-pro-3',
    'https://www.example.fr/blog/entretien-chaussures-randonnee',
  ];

  for (const url of urls) {
    await page.goto(url);
    const canonical = await page.$eval(
      'link[rel="canonical"]',
      (el) => el.getAttribute('href')
    );
    expect(canonical, `Canonical HTTP détecté sur ${url}`).toMatch(/^https:\/\//);
    expect(canonical, `Canonical ne doit pas contenir de double slash dans le path`).not.toMatch(/https:\/\/.*\/\//);
  }
});

Exécutez ce test à chaque déploiement. Si un canonical HTTP apparaît, le pipeline échoue et le déploiement est bloqué. C'est un filet de sécurité qui coûte 10 minutes à mettre en place et qui peut éviter des semaines de perte de trafic.

Pour un monitoring plus profond et continu sur l'ensemble de vos pages (pas seulement un échantillon CI), les vérifications automatisées de Chrome DevTools en mode headless ou un crawler programmé permettent de scanner quotidiennement votre site à la recherche de régressions de protocole.


La migration HTTP → HTTPS est une opération chirurgicale, pas un toggle. Chaque signal — redirections, canonical, sitemap, liens internes, hreflang, données structurées, HSTS — doit pointer de manière cohérente vers HTTPS. Une seule incohérence suffit à fragmenter vos signaux d'indexation et à prolonger la période de creux. Préparez minutieusement, déployez en une seule fois, et monitorez en continu les semaines qui suivent — c'est dans le suivi que se joue la différence entre une migration à 0 % de perte et une migration à 30 % de perte.