web-dev-qa-db-fra.com

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

Je veux réécrire toutes les demandes http sur mon serveur Web pour être des demandes https, j'ai commencé par ce qui suit:

 serveur {
 écouter 80; 
 
 emplacement/{
 réécrire ^ (. *) https: //mysite.com$1 permanent; 
} 
 ... 


.

517
MikeN

Bonne façon dans les nouvelles versions de nginx

Il s'est avéré que ma première réponse à cette question était correcte à un certain moment, mais elle s'est transformée en un autre piège - pour rester à jour, veuillez vérifier Taxing rewrite pitfalls

J'ai été corrigé par de nombreux utilisateurs de SE, donc le mérite leur revient, mais plus important encore, voici le bon code:

server {
       listen         80;
       server_name    my.domain.com;
       return         301 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" always; 

       [....]
}
758
Saif Bechan

REMARQUE: La meilleure façon de procéder a été fournie par https://serverfault.com/a/401632/3641 - mais est répétée ici:

server {
    listen         80;
    return 301 https://$Host$request_uri;
}

Dans le cas le plus simple, votre hôte sera fixé pour être le service auquel vous souhaitez les envoyer - cela fera une redirection 301 vers le navigateur et l'URL du navigateur sera mise à jour en conséquence.

Ci-dessous la réponse précédente, qui est inefficace en raison de l'expression rationnelle, un simple 301 est excellent comme le montre @kmindi

J'utilise nginx 0.8.39 et supérieur et j'ai utilisé ce qui suit:

 server {
       listen 80;
       rewrite ^(.*) https://$Host$1 permanent;
 }

Envoie une redirection permanente au client.

280
Michael Neale

Je pense que la meilleure et la seule façon devrait être d'utiliser une redirection HTTP 301 déplacée en permanence comme ceci:

server {
    listen         [::]:80;
    return 301 https://$Host$request_uri;
}

La redirection HTTP 301 déplacée de manière permanente est également la plus efficace car il n'y a pas d'expression régulière à évaluer, selon ce qui a déjà été mentionné pièges .


Le nouveau HTTP 308 déplacé en permanence préserve la méthode Request et est pris en charge par les principaux navigateurs . Par exemple, en utilisant 308 empêche les navigateurs de changer la méthode de demande de POST à GET pour la demande de redirection.


Si vous voulez conserver le nom d'hôte et le sous-domaine c'est la voie.

Cela fonctionne toujours si vous n'avez pas de DNS , car je l'utilise également localement. Je demande par exemple avec http://192.168.0.100/index.php et sera redirigé exactement vers https://192.168.0.100/index.php.

J'utilise listen [::]:80 sur mon hôte car j'ai bindv6only défini sur false, donc il se lie également au socket ipv4. changez-le en listen 80 si vous ne voulez pas IPv6 ou que vous souhaitez établir une liaison ailleurs.

La solution de Saif Bechan utilise le server_name qui dans mon cas est localhost mais qui n'est pas accessible sur un réseau.

La solution de Michael Neale est bonne, mais selon les pièges, il existe une meilleure solution avec la redirection 301;)

125
kmindi

Dans le bloc serveur, vous pouvez également effectuer les opérations suivantes:

# Force HTTPS connection. This rules is domain agnostic
if ($scheme != "https") {
    rewrite ^ https://$Host$uri permanent;
}
22
Oriol

Ce qui précède n'a pas fonctionné avec de nouveaux sous-domaines étant créés tout le temps. par exemple. AAA.example.com BBB.example.com pour environ 30 sous-domaines.

J'ai finalement obtenu une configuration avec les éléments suivants:

server {
  listen 80;
  server_name _;
  rewrite ^ https://$Host$request_uri? permanent;
}
server {
  listen  443;
  server_name example.com;
  ssl on;
  ssl_certificate /etc/ssl/certs/myssl.crt;
  ssl_certificate_key /etc/ssl/private/myssl.key;
  ssl_prefer_server_ciphers       on;
# ...
# rest of config here
# ...
}
17
Aleck Landgraf

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 mettre en évidence 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 donné, vous avez configuré HTTP non sécurisé et attendez du contenu utilisateur, avez des formulaires, hébergez une API ou avez configuré un site Web, un outil, une application ou un utilitaire pour parler votre site.

Le problème se produit lorsqu'une demande POST est envoyée à votre serveur. Si la réponse du serveur avec un simple 30x rediriger le contenu POST sera perdu. Ce qui se passe, c'est que le navigateur/client mettra à niveau la demande vers SSL mais rétrograder la requête POST en requête GET. Les paramètres POST seront perdus et une requête incorrecte sera envoyée à votre serveur.

La solution est simple. Vous devez utiliser un HTTP 1.1 307 rediriger. 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, consiste à 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"; 

       [....]
}
6
Mahmoud Al-Qudsi

Je lance ngnix derrière un AWS ELB. L'ELB parle à ngnix via http. Étant donné que l'ELB n'a aucun moyen d'envoyer des redirections aux clients, je vérifie l'en-tête X-Forwarded-Proto et redirige:

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

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

4
stamster

Si vous return 301 https://$Host$request_uri; comme réponse par défaut sur le port 80, alors votre serveur peut tôt ou tard obtenir une liste de proxys ouverts [1] et commencer à être abusé pour envoyer du trafic ailleurs sur Internet. Si vos journaux se remplissent 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 fera écho à tout ce que le navigateur envoie dans l'en-tête Host ou même le nom d'hôte de la ligne d'ouverture de HTTP, comme celui-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 recommandent ici d'utiliser $server_name au lieu de $Host. $server_name évalue toujours ce que vous mettez dans le server_name déclaration. Mais si vous avez plusieurs sous-domaines ou utilisez un caractère générique, cela ne fonctionnera pas, car $server_name n'utilise l'entrée premier qu'après server_name déclaration et, plus important encore, ne fera que renvoyer un caractère générique (pas de 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 en premier listant un default_server bloc qui n'utilise pas $Host, puis répertoriant un bloc générique qui:

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 pouvez également répertorier plusieurs domaines dans le deuxième bloc.)

Avec cette combinaison, les domaines inégalés seront redirigés quelque part codés 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 n'attirerez donc aucun problème.

Si vous vous sentez énervé, je suppose que vous pourriez également faire le default_server bloquer la correspondance 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 sort pas et ne répond pas aux demandes des clients, il suffit d'envoyer une redirection, mais je ne sais pas quel serait le bon mot. Je ne sais pas non plus quel est l'objectif, mais cela remplit vos journaux de bruit et consomme votre processeur et votre bande passante, vous pouvez donc aussi y mettre un terme.

1
Paul A Jungwirth

On dirait que personne n'a vraiment raison à 100%. Pour que les demandes du port 80 soient envoyées à leurs 443 équivalents pour un serveur Web entier, vous devez utiliser la directive Listen, pas la directive server_name pour spécifier le catch- tout nom. Voir aussi https://nginx.org/en/docs/http/request_processing.html

serveur {
 écouter 80 par défaut; 
 écouter [::]: 80 par défaut; 
 renvoyer 307 https: // $ Host $ request_uri; 
} 
  • $ Host intercepte les noms de sous-domaine.
  • 307 et 308 incluent les deux POST et GET demandent les URI.
  • 307 est temporaire, changez pour le permanent 308 après des tests approfondis:

Et assurez-vous de vérifier ce qui est déjà dans /etc/nginx/conf.d/ parce que le plus souvent j'ai eu des problèmes où le default.conf a renvoyé un vhost existant. Mon ordre de travail avec les problèmes nginx commence toujours par déplacer le fichier par défaut, en le remettant en commentaire ligne par ligne pour voir où il va mal.

0
Julius