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


Je souhaite réécrire toutes les requêtes http sur mon serveur Web en requêtes https. J'ai commencé avec les éléments suivants:

serveur {
    écoutez 80;

    emplacement / {
      réécrire ^ (. *) https: //monsite.com$1 permanent;
    }
...


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


495
2017-09-21 14:04


origine


Veuillez envisager de déplacer la "réponse acceptée" vers serverfault.com/a/171238/90758. C'est la bonne. - olafure
Utilisez simplement $ nom_serveur au lieu de mysite.com codé en dur - Fedir RYKHTIK


Réponses:


Manière correcte dans les nouvelles versions de nginx

Il s’est avéré que ma première réponse à cette question était correcte à une certaine heure, mais elle s’est transformée en un autre piège - pour rester à jour, veuillez vérifier Imposer les pièges de réécriture

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

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; 

       [....]
}

737
2017-12-05 20:43



Cependant, vous devrez le faire domaine par domaine - non? Et si vous vouliez l'appliquer à chaque domaine de votre serveur? - JM4
@ JM4: si vous utilisez $ host $ dans la réécriture au lieu de nom_serveur et ajoutez default_server à la directive listen, cela fonctionnera pour tous les domaines de votre serveur. - Klaas van Schelven
Il est important de mentionner que le 301 est stocké dans votre cache local sans date d'expiration. Pas très utile lorsque la configuration change - Trefex
@everyone Utilisez une redirection 307 pour conserver le contenu POST. - Mahmoud Al-Qudsi
Notez que vous devez utiliser $host au lieu de $server_name si vous utilisez des sous-domaines. - Catfish


NOTE: La meilleure façon de faire cela a été fournie par https://serverfault.com/a/401632/3641 - mais se répète ici:

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

Dans le cas le plus simple, votre hôte sera désigné comme étant le service auquel vous souhaitez envoyer les messages. Cela effectuera une redirection 301 vers le navigateur et l'URL du navigateur sera mise à jour en conséquence.

Voici la réponse précédente, qui est inefficace à cause de regex, un simple 301 est génial, comme le montre @kmindi

J'utilise nginx 0.8.39 et les versions ultérieures, et j'utilise les éléments suivants:

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

Envoie une redirection permanente au client.


269
2017-08-17 03:07



Je pense que cela devrait être 80 - car il s'agit d'écouter http puis de dire au client de revenir en tant que https (443). - Michael Neale
Cela devrait être la meilleure réponse! - Nathan
C'est la réponse la plus éprouvante. - Case
C’est la solution la plus simple, mais la moins sécurisée. Ainsi, vous autorisez votre serveur à rediriger un utilisateur vers n’importe quelle page, sans vérifier si son utilisation est autorisée. Si votre serveur dessert mydomain.co, des utilisateurs malveillants peuvent toujours utiliser votre serveur pour les rediriger vers d'autres domaines tels que mydomain.co, tels que google.com. - friedkiwi
@ cab0lt il n'y a pas de problème de sécurité ici. Servir une redirection ne présente pas de risque de sécurité. S'il existe des exigences de contrôle d'accès, celles-ci doivent être vérifiées au moment où le navigateur demande la nouvelle URL. Le navigateur n'obtiendra pas l'accès simplement sur la base de la redirection, pas plus qu'il n'aura besoin de la redirection pour demander la nouvelle URL. - mc0e


Je pense que le meilleur et le seul moyen devrait utiliser un HTTP 301 déplacé de façon permanente rediriger comme ceci:

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

le HTTP 301 déplacé de façon permanente la redirection est également la plus efficace car il n’ya pas d’expression rationnelle à évaluer, selon ce qui a déjà été mentionné. pitfails.


Le nouveau HTTP 308 déplacé de façon permanente conserve la méthode Request et est supporté par les principaux navigateurs. Par exemple, en utilisant 308 empêche les navigateurs de changer la méthode de requête de POST à GET pour la demande de redirection.


Si tu veux conserver le nom d'hôte et le sous-domaine Ceci est le chemin.

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

j'utilise listen [::]:80 sur mon hôte parce que j'ai bindv6only mis à false, donc il se lie également au socket ipv4. changez le en listen 80 si vous ne voulez pas d'IPv6 ou si vous souhaitez vous connecter ailleurs.

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

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


121
2018-06-23 17:19



Bien que vous essayiez de le citer, mais 301 ne fonctionne pas sur HTTPS. - Case
qu'est-ce qui ne marche pas? la section de serveur indiquée concerne le trafic HTTP (sans s) non chiffré à rediriger en permanence vers le serveur chiffré (cette section qui écoute sur 443 (https) n'est pas répertoriée) - kmindi
J'ai vérifié que cela fonctionnait bien avec https et tout le reste - @kmindi, j'ai mis à jour ma réponse en faisant référence à la vôtre - car je pense que c'est la bonne manière et que cela continue à apparaître! Bon travail. - Michael Neale
Lors de l'utilisation d'une demande de domaine (non-ip), ne fonctionne que si je remplace '[::]: 80' par '80'. - Joseph Lust
cela pourrait être le comportement attendu: trac.nginx.org/nginx/ticket/345. J'ai mis à jour la réponse pour décrire l'option d'écoute. - kmindi


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.

Enfin, une configuration fonctionnant 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
2018-06-25 04:29



Je vous remercie! Nginx reviendrait 301 https://*/ ou annuler la demande prématurément dans les autres réponses ici. server_name _; avec $host était la réponse qui a fait le tour. +1 - zamnuts
Celui-ci est optimal! Cependant, je recommande à certains de remplacer _ avec le domaine réel, par exemple .domain.com J'avais deux serveurs et nginx dirigeait accidentellement l'un de mes serveurs vers le serveur par défaut. - zzz
C'est la seule réponse qui a fonctionné pour moi, merci! - Snowman
Merci beaucoup mon pote .. J'ai essayé beaucoup de solutions mais je n'ai pas trouvé de solution. Cette solution est géniale et a fonctionné pour moi. nom du serveur _; Qu'est-ce que cela signifie pour .. Je n'ai pas compris. S'il vous plaît, expliquez-moi ceci. - Pavan Kumar


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;
}

16
2017-07-31 19:50



Cette configuration a provoqué une boucle de redirection sur mon serveur. - Corkscreewe
Peut-être qu'il y a une autre redirection en place ou que https n'est pas activé sur votre site / application - Oriol
Aucun des autres ne semblait fonctionner sauf celui-ci. Utiliser nginx version: nginx / 1.10.0 (Ubuntu) - ThatGuy343
voté pour https: // $ host $ uri - AMB
C'est la voie à suivre si vous êtes derrière un loadbalancer! - Antwan


J'ai posté un commentaire sur la bonne réponse il y a très longtemps avec une correction très importante, mais j'estime 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 quelconque, vous avez configuré HTTP non sécurisé et attendez-vous un contenu utilisateur, avez des formulaires, hébergez une API ou avez configuré un site Web, un outil, une application ou un utilitaire pour communiquer avec votre site.

Le problème se produit quand un POST demande est faite à votre serveur. Si la réponse du serveur avec un simple 30x réorienter le contenu POST sera perdu. Qu'est-ce qui se passe est que le navigateur / client mettra à niveau la demande à SSL mais rétrograder la POST à un GET demande. le 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 réorienter. Ceci est détaillé dans 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
2018-03-19 20:24



commande très très très pratique. Merci! - Denis Matafonov


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
2018-04-21 18:27



Version mise à jour, sans IF: paste.debian.net/plain/899679 - stamster