Hoe stuur ik HTTPS om naar HTTP op NGINX?

Is er een manier om HTTPS-verzoeken om te leiden naar HTTP door een regel toe te voegen aan het vhost-bestand van het domein?


Antwoord 1, autoriteit 100%

Waarom is zoiets nuttig? Op het eerste gezicht was ik niet zeker of het kon worden gedaan. Maar het leverde een interessante vraag op.

U kunt proberen een omleidingsstatement in uw configuratiebestand te plaatsen en uw server opnieuw op te starten. Er kunnen zich twee mogelijkheden voordoen:

  1. De server zal de omleiding geven – wat je lijkt te willen.
  2. De server zal eerst de https-uitwisseling uitvoeren en DAARNA de omleiding geven, in welk geval, wat heeft het voor zin?

Zal meer toevoegen als ik met iets meer concreets op de proppen kom.

UPDATE:(paar uur later)
Je zou dit kunnen proberen. U moet dit in uw nginx.conf-bestand plaatsen –

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

Stuurt een permanente omleiding naar de client. Ik neem aan dat je poort 443 (standaard) gebruikt voor https.

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

Voeg dit toe zodat uw normale http-verzoeken op poort 80 ongestoord zijn.

UPDATE:18 december 2016
server_name _moet worden gebruikt in plaats van server_name _ *in nginx-versies > 0.6.25 (met dank aan @Luca Steeb)


Antwoord 2, autoriteit 84%

rewriteen ifmoeten worden vermeden met Nginx. De beroemde regel is: “Nginx is not Apache”: met andere woorden, Nginx heeft betere manieren om met URL’s om te gaan dan te herschrijven. returnis technisch gezien nog steeds onderdeel van de herschrijfmodule, maar het draagt ​​niet de overhead van rewrite, en is niet zo ondermijnd als if.

Nginx heeft een hele pagina over waarom if“slecht” is. Het biedt ook een constructieve pagina waarin wordt uitgelegd waarom rewriteen ifzijn slecht, en hoe u er omheen kunt werken. Dit is wat de pagina te zeggen heeft over rewriteen if:

Dit is een verkeerde, omslachtige en ineffectieve manier.

Je kunt dit probleem goed oplossen met 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;
}

Als u veel bots verwacht die geen Host-header verzenden, kunt u $hostgebruiken in plaats van $http_hostals zolang je je aan poorten 80 en 443 houdt. Anders moet je dynamisch een $http_host-substituut invullen. Deze code is efficiënt en veilig zolang deze verschijnt in de root van server(in plaats van in een location-blok), ondanks het gebruik van if. U moet echter een standaardserver gebruiken om dit van toepassing te laten zijn, wat met https moet worden vermeden.

set $request_host $server_name:$server_port;
if ($http_host) {
    set $request_host $http_host;
}

Als u SSL/TLS voor specifieke paden wilt afdwingen, maar het anders wilt verbieden:

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

Als uw server niet in directe communicatie met de client staat, bijvoorbeeld als u CloudFlare gebruikt, wordt het een beetje ingewikkelder. U moet ervoor zorgen dat elke server die rechtstreeks met de client communiceert, een geschikte X-Forwarded-Proto-header aan het verzoek toevoegt.

Het gebruik hiervan is een rommelig voorstel; voor een volledige uitleg, zie IfIsEvil. Om dit nuttig te laten zijn, mag het if-blok om verschillende complexe redenen niet in een location-blok staan. Dit dwingt het gebruik van rewritevoor URI-tests. Kortom, als je dit op een productieserver moet gebruiken… niet doen. Zie het zo: als je Apache bent ontgroeid, ben je deze oplossing ontgroeid.

/secure, /secure/ en alles in /secure/ dwingt https af, terwijl alle andere URI’s http afdwingen. De (?! )PCRE-constructie is een negatieve vooruitblik-bewering. (?: )is een niet-vastleggende groep.

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

Antwoord 3, autoriteit 14%

location / {
    if ($scheme = https) {
        rewrite ^(.*)? http://$http_host$1 permanent;
    }
}

Antwoord 4, autoriteit 10%

deze vraag zou beter passen bij de serverfault.com-site.

Een betere manier om de omleiding naar http uit te voeren:

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

Dit vermijdt zowel de ‘if’-clausule als de regex in de herschrijving die kenmerken zijn van de andere oplossingen tot nu toe. Beide hebben implicaties voor de prestaties, hoewel je in de praktijk behoorlijk veel verkeer zou moeten hebben voordat het ertoe zou doen.

Afhankelijk van je setup, wil je waarschijnlijk ook een ip specificeren in de listen-clausule, en misschien een servername-clausule in het bovenstaande. Zoals het is, zal het van toepassing zijn op alle poort 443-verzoeken voor alle domeinnamen. Over het algemeen wil je een IP per domein met https, dus meestal is het bovenstaande aan een IP meer to the point dan het aan een domeinnaam te koppelen, maar daar zijn variaties op, bijvoorbeeld waar alle domeinen subdomeinen zijn van één domein.

EDIT: TLS is nu bijna universeel, en daarmee Server Name Identification (SNI) waarmee HTTPS-sites op meerdere domeinen een enkel IP-adres kunnen delen. Er is een goede beschrijving hier


Antwoord 5

Dit heeft me geholpen:

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

Antwoord 6

Geen goede oplossing, maar ik heb mijn use case kunnen oplossen door Cloudflare te gebruiken, dat de SSL transparant voor mij afhandelde.


Antwoord 7

De enige simpele regel is al uitgelegd in de post boven mij:

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

Antwoord 8

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

Na het invoeren van deze code wordt al het verkeer voor de standaard HTTP-server omgeleid naar HTTPS.

Other episodes