556 votes

Dans Nginx, comment puis-je réécrire toutes les requêtes http en https tout en conservant le sous-domaine ?

Je veux réécrire toutes les requêtes http sur mon serveur web pour en faire des requêtes https, j'ai commencé avec ce qui suit :

server {
    listen      80;

    location / {
      rewrite     ^(.\*)   https://mysite.com$1 permanent;
    }
...

Un problème est que cela supprime toute information sur les sous-domaines (par exemple, node1.mysite.com/dossier), comment puis-je réécrire ce qui précède pour tout rediriger vers https et maintenir le sous-domaine ?

2 votes

Veuillez envisager de déplacer la "réponse acceptée" vers serverfault.com/a/171238/90758 . C'est le bon.

0 votes

Il suffit d'utiliser $server_name au lieu du code dur mysite.com.

13voto

Mahmoud Al-Qudsi Points 489

J'ai posté un commentaire sur la bonne réponse il y a très, très longtemps avec une correction très importante, mais je pense qu'il est nécessaire de souligner cette correction dans sa propre réponse. Aucune des réponses précédentes ne peut être utilisée en toute sécurité si, à un moment ou à un autre, vous avez configuré un protocole HTTP non sécurisé et que vous attendez du contenu utilisateur, que vous avez des formulaires, que vous hébergez une API ou que vous avez configuré un site Web, un outil, une application ou un utilitaire pour qu'il parle à votre site.

Le problème survient lorsqu'un POST une demande est faite à votre serveur. Si le serveur répond par un simple 30x rediriger le contenu du POST sera perdu. Ce qui se passe, c'est que le navigateur/client met à jour la demande en SSL mais déclassement le site POST à un GET demande. Le site POST les paramètres seront perdus et une demande incorrecte sera faite à votre serveur.

La solution est simple. Vous devez utiliser un HTTP 1.1 307 redirection. Ceci est détaillé dans la RFC 7231 S6.4.7 :

  Note: This status code is similar to 302 (Found), except that it
  does not allow changing the request method from POST to GET.  This
  specification defines no equivalent counterpart for 301 (Moved
  Permanently) ([RFC7238], however, defines the status code 308
  (Permanent Redirect) for this purpose).

La solution, adaptée de la solution acceptée, est d'utiliser 307 dans votre code de redirection :

server {
       listen         80;
       server_name    my.domain.com;
       return         307 https://$server_name$request_uri;
}

server {
       listen         443 ssl;
       server_name    my.domain.com;
       # add Strict-Transport-Security to prevent man in the middle attacks
       add_header Strict-Transport-Security "max-age=31536000"; 

       [....]
}

6voto

MANCHUCK Points 141

J'exécute ngnix derrière un ELB AWS. L'ELB communique avec ngnix par http. Comme l'ELB n'a aucun moyen d'envoyer des redirections aux clients, je vérifie l'en-tête X-Forwarded-Proto et la redirection :

if ($http_x_forwarded_proto != 'https') {
    return 301 "https://www.exampl.com";
}

5voto

stamster Points 180

J'ai réussi à le faire comme ça :

server {
listen 80;
listen 443 ssl;

server_name domain.tld www.domain.tld;

# global HTTP handler
if ($scheme = http) {
        return 301 https://www.domain.tld$request_uri;
}

# global non-WWW HTTPS handler
if ($http_host = domain.tld){
        return 303 https://www.domain.tld$request_uri;
}
}

https://stackoverflow.com/a/36777526/6076984

0 votes

Version actualisée, sans IF : paste.debian.net/plain/899679

5voto

Paul A Jungwirth Points 153

Si vous return 301 https://$host$request_uri; comme réponse par défaut sur le port 80, votre serveur peut tôt ou tard se retrouver sur une liste de proxies ouverts[1] et commencer à être utilisé de manière abusive pour envoyer du trafic ailleurs sur Internet. Si vos journaux sont remplis de messages comme celui-ci, vous savez que cela vous est arrivé :

42.232.104.114 - - [25/Mar/2018:04:50:49 +0000] "GET http://www.ioffer.com/i/new-fashion-fine-gold-bracelet-versaec-bracelet-641175733 HTTP/1.1" 301 185 "http://www.ioffer.com/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.1.8.0; RogueCleaner; Alexa Toolbar)"

Le problème est que $host renverra ce que le navigateur envoie dans le champ Host ou même le nom d'hôte de la ligne d'ouverture de HTTP, comme celle-ci :

GET http://www.ioffer.com/i/new-fashion-fine-gold-bracelet-versaec-bracelet-641175733 HTTP/1.1

En raison de ce problème, d'autres réponses ici recommandent d'utiliser $server_name au lieu de $host . $server_name évalue toujours à ce que vous mettre dans le server_name déclaration. Mais si vous avez plusieurs sous-domaines ou si vous utilisez un caractère générique, cela ne fonctionnera pas, car $server_name utilise uniquement le primero après l'entrée server_name et, plus important encore, ne fera que renvoyer un caractère générique (sans le développer).

Alors comment prendre en charge plusieurs domaines tout en maintenant la sécurité ? Sur mes propres systèmes, j'ai résolu ce dilemme de la manière suivante primero liste des default_server qui n'utilise pas $host puis de lister un bloc joker qui le fait :

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

(Vous pourriez également énumérer plus d'un domaine dans le deuxième bloc).

Avec cette combinaison, les domaines qui ne correspondent pas seront redirigés vers un endroit codé en dur (toujours example.com ), et les domaines qui correspondent aux vôtres iront au bon endroit. Votre serveur ne sera pas utile en tant que proxy ouvert, vous ne vous attirerez donc pas d'ennuis.

Si vous êtes de mauvaise humeur, je suppose que vous pourriez également faire le default_server correspondance des blocs aucun de vos domaines légitimes et servir quelque chose d'offensant. . . . .

[1] Techniquement, "proxy" n'est pas le bon mot, car votre serveur ne va pas répondre aux requêtes des clients, il envoie juste une redirection, mais je ne suis pas sûr du mot juste. Je ne suis pas non plus sûr du but recherché, mais cela remplit vos journaux de bruit et consomme votre CPU et votre bande passante, alors autant y mettre un terme.

0 votes

Avez-vous un précédent de ce type de "proxy ouvert" en raison du code return 301 https://$host$request_uri; ? J'aime l'idée de créer un bloc universel pour rediriger n'importe quel site HTTP vers le même site mais en HTTPS.

4voto

Julius Points 143

On dirait que personne n'a vraiment eu raison à 100%. Pour que les requêtes du port 80 aillent vers leurs équivalents 443 pour un serveur web entier, vous devez utiliser le écouter et non la directive server_name pour spécifier la directive fourre-tout nom. Voir aussi https://nginx.org/en/docs/http/request_processing.html

server {
    listen 80 default;
    listen \[::\]:80 default;
      return 307 https://$host$request\_uri;
}
  • $host attrape les noms de sous-domaines.
  • 307 et 308 incluent les URI de demande POST et GET.
  • 307 est temporaire, passez à la version permanente 308 après des tests approfondis :

Et assurez-vous de vérifier ce qui se trouve déjà dans /etc/nginx/conf.d/ car le plus souvent, j'ai eu des problèmes où le fichier default.conf renvoyait un serveur virtuel existant. Ma façon de travailler avec les problèmes de nginx est toujours de commencer par déplacer le fichier par défaut, le remettre en place en le commentant ligne par ligne pour voir où ça ne va pas.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X