Frage Wie kann ich in Nginx alle http-Anfragen in https umschreiben, während ich die Unterdomäne beibehalte?


Ich möchte alle HTTP-Anfragen auf meinem Webserver als https-Anfragen umschreiben. Ich habe mit folgendem begonnen:

Server {
    höre 80 zu;

    Standort / {
      umschreiben ^ (. *) https: //mysite.com$1 permanent;
    }
...


Ein Problem besteht darin, dass damit alle Subdomaininformationen entfernt werden (z. B. node1.mysite.com/folder). Wie kann ich das oben beschriebene umschreiben, um alles auf https umzuleiten und die Subdomäne zu erhalten?


495
2017-09-21 14:04


Ursprung


Bitte überlegen Sie, die 'akzeptierte Antwort' zu verschieben serverfault.com/a/171238/90758. Das ist der Richtige. - olafure
Verwenden Sie einfach $ server_name anstelle von hardcoded mysite.com - Fedir RYKHTIK


Antworten:


Korrekter Weg in neuen Versionen von nginx

Meine erste Antwort auf diese Frage war zu einer bestimmten Zeit korrekt, aber sie wurde zu einer weiteren Falle - um auf dem Laufenden zu bleiben, bitte nachsehen Steuern Rewrite Stolperfallen

Ich wurde von vielen SE-Benutzern korrigiert, daher gilt das Verdienst ihnen, aber wichtiger ist, hier ist der richtige 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; 

       [....]
}

737
2017-12-05 20:43



Sie müssten dies jedoch Domain für Domain tun - nein? Was, wenn Sie es auf jede Domain auf Ihrem Server anwenden möchten? - JM4
@ JM4: Wenn Sie $ host $ anstelle von servername im rewrite verwenden und default_server zur listen-Anweisung hinzufügen, funktioniert es für jede Domain auf Ihrem Server. - Klaas van Schelven
Es ist wichtig zu erwähnen, dass der 301 in Ihrem lokalen Cache ohne Ablaufdatum gespeichert ist. Nicht sehr nützlich, wenn sich die Konfiguration ändert - Trefex
@everyone Verwenden Sie eine 307-Umleitung, um den POST-Inhalt beizubehalten. - Mahmoud Al-Qudsi
Beachten Sie, dass Sie verwenden müssen $host anstatt $server_name wenn Sie Sub-Domains verwenden. - Catfish


HINWEIS: Der beste Weg, dies zu tun, wurde von https://serverfault.com/a/401632/3641 - Aber wird hier wiederholt:

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

Im einfachsten Fall wird Ihr Host als Ihr Service festgelegt, an den Sie ihn senden möchten - dies wird eine 301-Weiterleitung an den Browser vornehmen und die Browser-URL wird entsprechend aktualisiert.

Unten ist die vorherige Antwort, die wegen Regex ineffizient ist, eine einfache 301 ist großartig, wie @kmindi zeigt

Ich habe nginx 0.8.39 und höher verwendet und folgendes verwendet:

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

Sendet eine permanente Weiterleitung an den Client.


269
2017-08-17 03:07



Ich denke, es sollte 80 sein - da dies auf http wartet und dann dem Kunden sagt, dass er als https zurückkommen soll (443). - Michael Neale
Dies sollte die beste Antwort sein! - Nathan
Dies ist die beste Antwort. - Case
Dies ist die einfachste, aber die am wenigsten sichere Methode. Auf diese Weise können Sie Ihren Server auf eine beliebige Seite umleiten, ohne zu überprüfen, ob er überhaupt auf Ihrem Server verwendet werden darf. Wenn Ihr Server mydomain.co verwendet, können böswillige Benutzer Ihren Server weiterhin verwenden, um Benutzer zu anderen Domänen wie mydomain.co umzuleiten, z. B. google.com. - friedkiwi
@ cab0lt gibt es hier kein Sicherheitsproblem. Das Versenden einer Weiterleitung stellt kein Sicherheitsrisiko dar. Wenn es Zugriffssteuerungsanforderungen gibt, sollten diese an dem Punkt überprüft werden, an dem der Browser die neue URL anfordert. Der Browser wird nicht einfach auf der Basis der Weiterleitung zugreifen, noch benötigt er die Weiterleitung, um die neue URL anzufordern. - mc0e


Ich denke, der beste und einzige Weg sollte eine sein HTTP 301 wurde dauerhaft verschoben Umleitung so:

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

Das HTTP 301 wurde dauerhaft verschoben Redirect ist auch der effizienteste, weil es keine Regex gibt, die bereits erwähnt wurde Pitfails.


Das neue HTTP 308 wurde dauerhaft verschoben Erhält die Request-Methode und ist unterstützt von den wichtigsten Browsern. Zum Beispiel mit 308 Verhindert, dass Browser die Anfrage-Methode ändern POST zu GET für die Weiterleitungsanfrage.


Wenn du möchtest Bewahren Sie den Hostnamen und die Subdomain auf das ist der Weg.

Diese funktioniert immer noch, wenn Sie kein DNS haben, wie ich es auch lokal verwende. Ich fordere zum Beispiel mit http://192.168.0.100/index.php und wird genau weitergeleitet werden https://192.168.0.100/index.php.

ich benutze listen [::]:80 auf meinem Gastgeber, weil ich habe bindv6only einstellen false, also bindet es auch an den ipv4-socket. ändere es zu listen 80 wenn Sie kein IPv6 wollen oder woanders binden wollen.

Die Lösung von Saif Bechan nutzt die server_name Das ist in meinem Fall localhost, aber das ist nicht über ein Netzwerk erreichbar.

Die Lösung von Michael Neale ist gut, aber laut Pitfails gibt es eine bessere Lösung mit Redirect 301;)


121
2018-06-23 17:19



Schön, dass Sie versuchen, es zu zitieren, aber 301 funktioniert nicht auf HTTPS. - Case
was funktioniert nicht? Der angegebene Server-Abschnitt ist für unverschlüsselten http (ohne s) Verkehr permanent auf den verschlüsselten Server umgeleitet (der Abschnitt, der auf 443 (https) hört, ist nicht aufgeführt) - kmindi
Ich habe überprüft, das funktioniert gut mit https und alles - @kmindi Ich aktualisierte meine Antwort mit Bezug auf Ihre - wie ich denke, es ist der richtige Weg, und dies taucht immer wieder auf! Gute Arbeit. - Michael Neale
Wenn ich eine Domain (non-ip) Anfrage verwende, funktioniert das nicht, wenn ich '[::]: 80' nicht zu '80' ändere. - Joseph Lust
das könnte das erwartete Verhalten sein: trac.nginx.org/nginx/ticket/345. Ich habe die Antwort aktualisiert, um die Höroption zu beschreiben. - kmindi


Das oben Gesagte hat nicht funktioniert, da immer neue Subdomains erstellt wurden. z.B. AAA.example.com BBB.example.com für ungefähr 30 Subdomains.

Endlich habe ich eine Konfiguration bekommen, die mit folgendem funktioniert:

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



Danke dir! Nginx würde entweder zurückkehren 301 https://*/ oder stornieren Sie die Anfrage vorzeitig in den anderen Antworten hier. server_name _; mit $host war die Antwort, die den Trick gemacht hat. +1 - zamnuts
Dieser ist optimal! Ich empfehle jedoch für einige zu ersetzen _ mit der tatsächlichen Domäne, z.B. .domain.com Ich hatte zwei Server, und nginx wies versehentlich einen meiner Server auf den Standardserver. - zzz
Dies ist die einzige Antwort, die für mich funktioniert hat, danke! - Snowman
Vielen Dank Kumpel .. Ich habe viele der Lösungen ausprobiert, aber nicht funktioniert. Diese Lösung ist großartig und hat für mich funktioniert. Servername _; Wofür ist das gedacht? Ich habe es nicht verstanden. Bitte erläutern Sie mir das. - Pavan Kumar


Innerhalb des Serverblocks können Sie auch Folgendes tun:

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

16
2017-07-31 19:50



Diese Konfiguration hat dazu geführt, dass mein Server eine Umleitungsschleife erzeugt hat - Corkscreewe
Vielleicht, weil eine andere Weiterleitung vorhanden ist oder https in Ihrer Website / App nicht aktiviert ist - Oriol
Keiner der anderen schien außer diesem einen zu arbeiten. Verwenden der nginx-Version: nginx / 1.10.0 (Ubuntu) - ThatGuy343
upvoted für https: // $ host $ uri - AMB
Dies ist der Weg zu gehen, wenn Sie hinter einem Loadbalancer sind! - Antwan


Ich habe vor langer, langer Zeit einen Kommentar über die richtige Antwort gepostet, mit einer sehr wichtigen Korrektur, aber ich finde es notwendig, diese Korrektur in ihrer eigenen Antwort hervorzuheben. Keine der vorherigen Antworten ist sicher zu verwenden, wenn Sie zu irgendeinem Zeitpunkt unsicheres HTTP-Setup hatten und Benutzerinhalte erwarten, Formulare haben, eine API hosten oder eine Website, ein Tool, eine Anwendung oder ein Dienstprogramm konfiguriert haben, um mit Ihrer Site zu kommunizieren.

Das Problem tritt auf, wenn a POST Anfrage wird an Ihren Server gestellt. Wenn der Server mit einer Ebene antwortet 30x umleiten Der POST-Inhalt geht verloren. Was passiert, ist, dass der Browser / Client die Anfrage auf SSL aktualisiert Downgrade das POST zu einem GET anfordern. Das POST Parameter gehen verloren und es wird eine falsche Anfrage an Ihren Server gestellt.

Die Lösung ist einfach. Sie müssen ein verwenden HTTP 1.1 307 umleiten. Dies ist detailliert in 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).

Die Lösung, angepasst von der akzeptierten Lösung, soll verwendet werden 307 in deinem Weiterleitungscode:

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



sehr, sehr sehr handliches Kommando. Vielen Dank! - Denis Matafonov


Ich schaffte es so:

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



Aktualisierte Version, ohne IF: paste.debian.net/plain/899679 - stamster


Ich betreibe ngnix hinter einem AWS ELB. Der ELB spricht mit ngnix über http. Da der ELB keine Weiterleitungen an Clients senden kann, suche ich nach dem X-Forwarded-Proto-Header und Redirect:

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

3
2018-01-04 17:09





Wenn du return 301 https://$host$request_uri; Als Standardantwort auf Port 80 kann Ihr Server früher oder später in eine Liste offener Proxies [1] gelangen und missbraucht werden, um Datenverkehr an anderer Stelle im Internet zu senden. Wenn deine Logs voll sind mit Nachrichten wie dieser, dann weißt du, dass es dir passiert ist:

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)"

Das Problem ist, dass $host wird zurücksenden, was auch immer der Browser in der sendet Host Header oder sogar der Hostname aus der HTTP-Anfangszeile, wie dieser:

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

Wegen dieses Problems empfehlen einige andere Antworten hier zu verwenden $server_name anstatt $host. $server_name wertet immer was aus Sie setzen Sie das ein server_name Erklärung. Aber wenn Sie dort mehrere Subdomains haben oder einen Platzhalter verwenden, wird das nicht funktionieren, weil $server_name benutzt nur die zuerst Eintrag nach dem server_name Deklaration, und noch wichtiger, wird nur einen Platzhalter zurückgeben (nicht expandieren).

Wie können Sie mehrere Domains unterstützen und gleichzeitig die Sicherheit erhalten? Auf meinen eigenen Systemen habe ich mich mit diesem Dilemma beschäftigt zuerst Auflistung a default_server Block, der nicht verwendet wird $hostund dann einen Platzhalterblock auflisten, der

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

(Sie könnten auch mehr als eine Domäne im zweiten Block auflisten.)

Mit dieser Kombination werden unübertroffene Domains irgendwo hardcoded umgeleitet (immer example.com), und Domains, die zu Ihren eigenen passen, werden an den richtigen Ort gehen. Ihr Server wird als offener Proxy nicht nützlich sein, so dass Sie keine Probleme bekommen.

Wenn Sie sich ornery fühlen, können Sie vermutlich auch die default_server Übereinstimmung blockieren keiner von deinen legitimen Domains und diene etwas Offensives. . . .

[1] Technisch ist "Proxy" das falsche Wort, weil dein Server nicht ausgeht und Anfragen für die Clients erfüllt, sondern nur eine Weiterleitung sendet, aber ich bin mir nicht sicher, was das richtige Wort wäre. Ich bin mir auch nicht sicher, was das Ziel ist, aber es füllt Ihre Logs mit Rauschen und verbraucht Ihre CPU und Bandbreite, also können Sie es auch stoppen.


0
2018-03-25 05:58





rewrite ^!https https://$host$request_uri permanent;

-1
2018-06-29 04:33