Redirection HTTP vers HTTPS dans Nginx : bonnes pratiques

Configurez une redirection fiable de HTTP vers HTTPS dans Nginx à l'aide d'un bloc dédié sur le port 80, évitez les boucles de redirection, choisissez le bon code de redirection et ajoutez HSTS lorsque vous êtes prêt.

Redirection HTTP vers HTTPS dans Nginx : bonnes pratiques

Rediriger HTTP vers HTTPS dans Nginx garantit que les visiteurs utilisent la version chiffrée de votre site, même s'ils tapent l'ancienne URL http:// ou suivent un lien obsolète. Une configuration de redirection propre améliore la sécurité, évite les doublons d'URL et offre aux utilisateurs un point d'entrée cohérent.

La meilleure approche est généralement simple : garder le port 80 ouvert juste assez longtemps pour rediriger le trafic, et servir le site réel sur le port 443 avec un certificat TLS valide.

Les détails comptent car les redirections sont faciles à faire presque correctement. Une redirection qui supprime le chemin casse les signets. Une redirection qui préserve le mauvais nom d'hôte peut créer des URL canoniques en double. Une redirection derrière un équilibreur de charge peut boucler indéfiniment si Nginx ne comprend pas où TLS se termine.

Considérez la redirection comme faisant partie de votre API publique. Les gens collent des liens dans les discussions, les moteurs de recherche les explorent, les systèmes de surveillance les atteignent, et les anciens e-mails les maintiennent en vie pendant des années. Si la redirection est stable, personne ne le remarque. Si elle est bâclée, les utilisateurs voient des avertissements de certificat, des chemins cassés ou des erreurs de trop nombreuses redirections avant même que votre application ne reçoive une requête.

Pourquoi les redirections HTTPS sont importantes

HTTPS protège le trafic entre le navigateur et votre serveur en utilisant le chiffrement TLS. Sans cela, les données peuvent être inspectées ou modifiées par les réseaux entre l'utilisateur et votre site. Cela est important pour les connexions, les formulaires, les cookies, les zones d'administration, les API, et même la navigation ordinaire.

Les redirections aident également à la cohérence. Les moteurs de recherche et les utilisateurs ne devraient pas voir http://example.com/page et https://example.com/page comme deux destinations distinctes. Une redirection permanente indique aux clients que HTTPS est la version préférée.

Le modèle standard Nginx est un bloc serveur dédié sur le port 80 :

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

    return 301 https://$host$request_uri;
}

Ensuite, votre bloc serveur HTTPS gère le site réel :

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

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

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

La directive return 301 est efficace et claire. Elle indique à Nginx d'envoyer une redirection permanente sans effectuer de traitement supplémentaire de localisation. $request_uri préserve le chemin et la chaîne de requête, donc /docs?page=2 devient https://example.com/docs?page=2.

Pour une configuration TLS complète, voir sécuriser Nginx avec HTTPS.

Pour la plupart des sites, évitez de mettre la logique applicative dans le bloc du port 80. Il ne devrait pas servir de fichiers statiques, faire proxy vers l'application, ou contenir un grand ensemble d'emplacements. Gardez-le simple :

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://example.com$request_uri;
}

Ce petit bloc est plus facile à auditer et moins susceptible de dériver de la configuration HTTPS.

Choisir entre les redirections 301 et 302

Utilisez 301 pour une redirection permanente HTTP vers HTTPS sur un site de production. Les navigateurs et les moteurs de recherche comprennent que l'URL HTTPS doit remplacer l'URL HTTP.

Utilisez 302 ou 307 uniquement lorsque la redirection est temporaire. Par exemple, vous pourriez utiliser une redirection temporaire pendant les tests avant que les certificats et les noms d'hôte ne soient finalisés. Une fois le site HTTPS prêt, passez à une redirection permanente.

Soyez prudent lors de la configuration initiale. Les navigateurs peuvent mettre en cache les redirections 301 de manière agressive. Si vous redirigez accidentellement vers le mauvais nom d'hôte, le navigateur peut continuer à utiliser la mauvaise redirection même après avoir corrigé Nginx. Testez avec curl, des fenêtres de navigation privée et des noms d'hôte non productifs lorsque c'est possible.

Un flux de déploiement pratique ressemble à ceci :

  1. Confirmez que le bloc serveur HTTPS fonctionne directement.
  2. Confirmez que le certificat correspond à chaque nom d'hôte.
  3. Ajoutez le bloc serveur de redirection HTTP.
  4. Testez plusieurs chemins et chaînes de requête.
  5. Changez les redirections temporaires en permanentes uniquement lorsque le comportement est correct.

Vous devez également décider du nom d'hôte canonique. Si example.com et www.example.com fonctionnent tous les deux, choisissez-en un comme nom d'hôte public préféré. Sinon, les utilisateurs peuvent rebondir entre les noms d'hôte ou les moteurs de recherche peuvent indexer les deux.

Par exemple, pour rediriger tout le trafic HTTP vers le nom d'hôte HTTPS non-www :

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

    return 301 https://example.com$request_uri;
}

Cela est différent de https://$host$request_uri, qui préserve le nom d'hôte demandé par l'utilisateur.

Vous pouvez également séparer les redirections de nom d'hôte des redirections de schéma si vous voulez que le comportement soit explicite :

server {
    listen 80;
    server_name www.example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen 80;
    server_name example.com;
    return 301 https://example.com$request_uri;
}

C'est plus verbeux, mais cela rend la destination finale évidente. Sur un petit site, les deux styles conviennent. Sur un site plus grand avec de nombreux alias, des blocs serveur explicites peuvent réduire la confusion lors des modifications ultérieures.

Éviter les boucles de redirection et les problèmes de certificat

Les boucles de redirection se produisent lorsque Nginx, un équilibreur de charge ou une application continue d'envoyer une requête vers une URL qui déclenche une autre redirection. Cela est courant lorsque TLS se termine avant Nginx, par exemple au niveau d'un équilibreur de charge cloud ou d'un CDN.

Dans une configuration simple à serveur unique, Nginx reçoit HTTPS directement, donc la redirection est simple. Dans une chaîne de proxy, Nginx peut recevoir HTTP simple de l'équilibreur de charge même si l'utilisateur s'est connecté avec HTTPS. Si votre application essaie ensuite de forcer HTTPS en fonction du schéma de connexion local, cela peut provoquer une boucle.

La solution dépend de votre architecture. Généralement, l'équilibreur de charge doit passer des en-têtes tels que X-Forwarded-Proto, et l'application ou la configuration Nginx doit les approuver uniquement à partir d'adresses proxy connues.

Par exemple, si Nginx se trouve derrière un équilibreur de charge de confiance et ne reçoit que du HTTP interne, vous ne voudrez peut-être pas que Nginx redirige chaque requête HTTP locale. Au lieu de cela, l'équilibreur de charge peut gérer la redirection HTTP vers HTTPS publique, tandis que Nginx sert le trafic depuis le réseau privé. Si Nginx doit prendre la décision, il a besoin d'informations fiables sur le protocole transféré provenant du proxy devant lui. Ne faites pas confiance à X-Forwarded-Proto provenant de clients Internet arbitraires.

Assurez-vous également que les certificats couvrent chaque nom d'hôte redirigé. Si un utilisateur visite http://www.example.com et que vous redirigez vers https://www.example.com, le certificat doit être valide pour www.example.com. Si vous redirigez tout vers https://example.com, le certificat du site final doit couvrir example.com.

Testez avec :

curl -I http://example.com/some/path?x=1

Recherchez :

HTTP/1.1 301 Moved Permanently
Location: https://example.com/some/path?x=1

Ensuite, testez l'URL HTTPS :

curl -I https://example.com/some/path?x=1

La réponse HTTPS doit renvoyer le statut réel de la page, pas une autre redirection vers HTTP.

Testez également les deux noms d'hôte s'ils existent tous les deux :

curl -I http://www.example.com/
curl -I https://www.example.com/
curl -I http://example.com/
curl -I https://example.com/

Vous recherchez une chaîne courte et prévisible. Une seule redirection de HTTP vers l'URL HTTPS canonique est bonne. Plusieurs sauts, comme HTTP non-www vers HTTPS non-www vers HTTPS www et inversement, sont un signe que Nginx, l'application, les règles CDN ou le transfert au niveau DNS se battent entre eux.

Vous pouvez inspecter toute la chaîne avec :

curl -IL http://www.example.com/some/path

Le drapeau -L suit les redirections. Dans une configuration propre, la sortie doit montrer la réponse HTTP initiale puis la réponse HTTPS finale. Si vous voyez trois ou quatre en-têtes Location, simplifiez les règles jusqu'à ce qu'il y ait une route claire vers l'URL canonique.

HSTS et autres bonnes pratiques

Une fois votre configuration HTTPS stable, vous pouvez envisager HTTP Strict Transport Security, généralement appelé HSTS. HSTS indique aux navigateurs d'utiliser HTTPS automatiquement pour les visites futures.

Un en-tête courant ressemble à ceci :

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

Ne l'ajoutez pas à la légère. Si vous incluez les sous-domaines, chaque sous-domaine doit prendre en charge HTTPS. Si vous cassez HTTPS plus tard, les navigateurs qui ont vu l'en-tête HSTS peuvent refuser d'accéder à la version HTTP. Commencez avec un max-age plus court pendant les tests, puis augmentez-le une fois que vous êtes confiant.

Autres bonnes pratiques :

  • Gardez le bloc du port 80 simple.
  • Préservez les chemins et les chaînes de requête sauf si vous avez une raison de ne pas le faire.
  • Choisissez un nom d'hôte canonique.
  • Testez les redirections avec curl, pas seulement un navigateur.
  • Renouvelez les certificats automatiquement et surveillez les échecs de renouvellement.
  • Gardez la logique de redirection dans Nginx lorsque c'est possible au lieu de la dupliquer dans l'application.

Des règles de redirection simples sont plus faciles à raisonner et moins susceptibles de se casser lors des modifications ultérieures du site.

Erreurs courantes

L'erreur la plus courante est d'utiliser rewrite pour une simple redirection :

rewrite ^ https://example.com$request_uri permanent;

Cela peut fonctionner, mais return 301 ... est plus clair et évite un traitement de réécriture supplémentaire. Utilisez rewrite lorsque vous avez vraiment besoin de correspondance de motifs, pas pour une redirection de schéma de base.

Une autre erreur est de rediriger vers $server_name sans comprendre ce qu'il contient. $host provient de l'en-tête d'hôte de la requête, tandis que $server_name est basé sur le nom de serveur Nginx correspondant. Pour les redirections canoniques, un nom d'hôte littéral est souvent l'option la moins surprenante :

return 301 https://example.com$request_uri;

Vous devriez également éviter de rediriger les chemins de défi ACME HTTP si votre outil de certificat en a besoin sur le port 80. De nombreuses configurations Let's Encrypt gèrent cela automatiquement, mais les configurations personnalisées peuvent nécessiter une exception :

location /.well-known/acme-challenge/ {
    root /var/www/letsencrypt;
}

location / {
    return 301 https://example.com$request_uri;
}

N'ajoutez cette exception que si votre client de certificat l'utilise. Si vos certificats se renouvellent via une validation DNS ou un serveur temporaire géré par un outil, gardez le bloc de redirection simple.

Un modèle de déploiement sûr

Pour un site de production, effectuez le changement par étapes :

  1. Confirmez que le bloc serveur HTTPS sert correctement le site.
  2. Confirmez que le renouvellement du certificat fonctionne ou est surveillé.
  3. Ajoutez une redirection temporaire sur le port 80 si vous testez encore les noms d'hôte.
  4. Testez les URL courantes avec curl -I et curl -IL.
  5. Passez à 301 une fois la cible de redirection finale.
  6. Attendez avant d'activer HSTS à longue durée de vie.

Cette période d'attente est utile. Elle vous donne le temps de détecter les sous-domaines oubliés, les anciennes URL de webhook, les liens http:// codés en dur, ou une règle CDN qui n'était pas visible depuis votre première machine de test.

Gardez également la surveillance à l'esprit. Si votre vérification de disponibilité pointe toujours vers http://example.com, décidez si elle doit s'attendre à un 301 ou suivre les redirections et vérifier la page HTTPS finale. Les deux peuvent être valides, mais le moniteur doit correspondre au comportement que vous souhaitez réellement.

Exemple : site statique et proxy inverse

Pour un site statique, le bloc HTTPS peut être uniquement une racine de documents :

server {
    listen 443 ssl http2;
    server_name example.com;

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

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

Pour une application derrière Nginx, le bloc de redirection reste le même, mais le bloc HTTPS fait proxy du trafic :

server {
    listen 443 ssl http2;
    server_name example.com;

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

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Le point important est la séparation. Le port 80 décide où le navigateur doit aller. Le port 443 sert le site. Mélanger ces tâches rend le comportement de redirection plus difficile à raisonner, surtout lorsqu'un autre proxy ou CDN est ajouté plus tard.

Après modification, exécutez toujours :

sudo nginx -t
sudo systemctl reload nginx

Si le test échoue, ne rechargez pas. Corrigez d'abord l'erreur de syntaxe, puis testez à nouveau.

Une dernière vérification vaut la peine d'être effectuée depuis l'extérieur du serveur, pas seulement via SSH sur l'hôte. Un pare-feu, un CDN ou un équilibreur de charge peut modifier ce que voient les utilisateurs réels. Exécutez les mêmes vérifications curl -I depuis votre ordinateur portable, un emplacement de surveillance ou une instance cloud temporaire. Si le résultat externe diffère de localhost, le problème de redirection se situe probablement dans la couche réseau devant Nginx, pas dans le bloc serveur lui-même. Vérifiez cela avant de réécrire une configuration fonctionnelle.

Quand demander de l'aide

Demandez l'aide d'un ingénieur DevOps si votre site se trouve derrière un CDN, un équilibreur de charge cloud, une entrée Kubernetes ou plusieurs proxys inverses. Les redirections HTTPS dans une infrastructure en couches dépendent de l'endroit où TLS se termine et des en-têtes approuvés.

Vous devriez également demander de l'aide avant d'activer HSTS à long terme sur de nombreux sous-domaines. Un mauvais réglage peut verrouiller les utilisateurs hors des services qui ne sont pas prêts pour HTTPS.

Rediriger HTTP vers HTTPS dans Nginx est un petit changement de configuration avec un grand impact sur la sécurité. Utilisez un bloc de redirection dédié sur le port 80, préservez l'URI de la requête, vérifiez les certificats et testez les boucles avant de considérer la tâche comme terminée.