web-dev-qa-db-fra.com

Comment rediriger les requêtes https: // vers http: // dans NGINX?

Existe-t-il un moyen de rediriger les requêtes https: // vers http: // en ajoutant une règle dans le fichier vhost du domaine? J'utilise NGINX.

34
deb

Pourquoi est-ce que quelque chose comme ça est utile? À première vue, je n'étais pas sûr que cela puisse être fait. Mais cela posait une question intéressante.

Vous pouvez essayer de mettre une instruction de redirection dans votre fichier de configuration et de redémarrer votre serveur. Deux possibilités pourraient se présenter:

  1. Le serveur émettra la redirection - ce que vous semblez vouloir.
  2. Le serveur fera d’abord l’échange https, puis ALORS l’émission de la redirection; dans quel cas, quel est le but?

Ajoutera plus si je trouve quelque chose de plus concret.

UPDATE: (quelques heures plus tard) Vous pouvez essayer ceci. Vous devez mettre ceci dans votre nginx.conf fichier - 

server {
       listen 443;
       server_name _ *;
       rewrite ^(.*) http://$Host$1 permanent;
 }

Envoie une redirection permanente au client. Je suppose que vous utilisez le port 443 (par défaut) pour https.

server {
    listen      80;
    server_name _ *;
    ...
}

Ajoutez ceci afin que vos requêtes HTTP normales sur le port 80 ne soient pas perturbées.

UPDATE: 18th Dec 2016 - server_name _ doit être utilisé à la place de server_name _ * dans les versions nginx> 0.6.25 (merci à @Luca Steeb)

32
Srikar Appalaraju

rewrite et if doivent être évités avec Nginx. La fameuse phrase est "Nginx n’est pas Apache": en d’autres termes, Nginx dispose de meilleurs moyens de gérer les URL que de les réécrire. return fait toujours partie techniquement du module de réécriture, mais il ne supporte pas les frais généraux de rewrite et n'est pas aussi difficile à éviter que if.

Nginx a une page entière sur pourquoi if est "diabolique" . Il fournit également une page constructive expliquant pourquoi rewrite et if sont mauvais } et comment vous pouvez le contourner. Voici ce que la page dit à propos de rewrite et if:

C'est une façon fausse, lourde et inefficace.

Vous pouvez résoudre ce problème correctement en utilisant return:

server {
    listen 443 ssl;

    # You will need a wildcard certificate if you want to specify multiple
    # hostnames here.
    server_name domain.example www.domain.example;

    # If you have a certificate that is shared among several servers, you
    # can move these outside the `server` block.
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/cert.key;

    # 301          indicates a permanent redirect.  If your redirect is
    #              temporary, you can change it to 302 or omit the number
    #              altogether.
    # $http_Host   is the hostname and, if applicable, port--unlike $Host,
    #              which will break on non-standard ports
    # $request_uri is the raw URI requested by the client, including any
    #              querystring
    return 301 http://$http_Host$request_uri;
}

Si vous attendez beaucoup de robots qui n'envoient pas d'en-tête Host, vous pouvez utiliser $Host au lieu de $http_Host tant que vous vous en tenez aux ports 80 et 443. Sinon, vous devrez renseigner de manière dynamique un substitut $http_Host. Ce code est efficace et sûr tant qu'il apparaît dans la racine de server (plutôt que dans un bloc location), malgré l'utilisation de if. Cependant, vous devez utiliser un serveur par défaut pour que cela soit applicable, ce qui devrait être évité avec https.

set $request_Host $server_name:$server_port;
if ($http_Host) {
    set $request_Host $http_Host;
}

Si vous souhaitez appliquer SSL/TLS pour des chemins spécifiques, mais interdisez-le autrement:

server {
    listen 443 ssl;
    server_name domain.example;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/cert.key;

    location / {
        return 301 http://$Host$request_uri;
    }

    location /secure/ {
        try_files $uri =404;
    }
}

server {
    listen 80;
    server_name domain.example;

    location / {
        try_files $uri =404;
    }

    location /secure/ {
        return 301 https://$http_Host$request_uri;
    }
}

Si votre serveur n'est pas en communication directe avec le client - par exemple, si vous utilisez CloudFlare - les choses se compliquent un peu. Vous devez vous assurer que tout serveur en communication directe avec le client ajoute un en-tête X-Forwarded-Proto approprié à la demande.

Utiliser ceci est une proposition en désordre; pour une explication complète, voir IfIsEvil . Pour que cela soit utile, le bloc if ne peut pas être à l'intérieur d'un bloc location, pour diverses raisons complexes. Cela force l'utilisation de rewrite pour les tests d'URI. En bref, si vous devez utiliser ceci sur un serveur de production ... ne le faites pas. Pensez-y de cette façon: si vous avez dépassé Apache, vous avez dépassé cette solution.

/ secure,/secure/et tout ce qui se trouve dans/secure/appliquera https, tandis que tous les autres URI appliqueront http. La construction (?! ) PCRE est une assertion d'anticipation négative . (?: ) est un groupe non-capturant .

server {
    # If you're using https between servers, you'll need to modify the listen
    # block and ensure that proper ssl_* statements are either present or
    # inherited.
    listen 80;
    server_name domain.example;

    if ($http_x_forwarded_proto = https) {
        rewrite ^(?!/secure)/ http://$http_Host$request_uri? permanent;
    }
    if ($http_x_forwarded_proto != https) {
        rewrite ^/secure(?:/|$) https://$http_Host$request_uri? permanent;
    }
}
29
Zenexer
location / {
    if ($scheme = https) {
        rewrite ^(.*)? http://$http_Host$1 permanent;
    }
}
6
ansiart

cette question aurait été mieux adaptée au site serverfault.com.

Une meilleure façon de faire la redirection vers http:

server {
   listen 443;
   return 301 http://$Host$request_uri;
}

Cela évite à la fois la clause 'if' et l'expression régulière dans la réécriture qui sont des fonctionnalités des autres solutions à ce jour. Les deux ont des implications en termes de performances, bien qu'en pratique, il faudrait beaucoup de trafic avant que cela ne soit important.

En fonction de votre configuration, vous voudrez probablement également spécifier une adresse IP dans la clause d'écoute, et peut-être une clause nom_serveur dans la section ci-dessus. Tel quel, cela s'appliquera à toutes les demandes du port 443 pour tous les noms de domaine. Vous voulez généralement une adresse IP par domaine avec https. Par conséquent, lier le plus haut à un IP vaut plus que l’attribuer à un nom de domaine, mais il existe des variantes, par exemple lorsque tous les domaines sont des sous-domaines d’un domaine.

EDIT: TLS est proche de l’universel à présent, et avec lui l’identification du nom de serveur (SNI), qui permet de créer des sites HTTPS sur plusieurs domaines partageant une même adresse IP. Il y a un bon article ici

4
mc0e

Cela m'a aidé:

server {
    listen 443;
    server_name server.org www.server.org;
    rewrite ^ http://$server_name$request_uri? permanent;
}
0
devcline

La seule règle simple est déjà expliquée sur le post ci-dessus:

server {
    listen ip:443;
    server_name www.example.com;
    rewrite ^(.*) http://$Host$1 permanent;
}
0
Maarten