Wie kann ich in Nginx alle http-Anforderungen unter Beibehaltung der Unterdomäne auf https umschreiben?

509

Ich möchte alle http-Anfragen auf meinem Webserver in https-Anfragen umschreiben. Ich habe mit Folgendem begonnen:

Server {
    höre 80;

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


Ein Problem ist, dass hierdurch alle Subdomain-Informationen entfernt werden (z. B. node1.mysite.com/folder). Wie kann ich die obigen Informationen neu schreiben, um alles zu https umzuleiten und die Subdomain zu verwalten?

MikeN
quelle
2
Bitte ziehen Sie in Betracht, die akzeptierte Antwort auf serverfault.com/a/171238/90758 zu verschieben . Das ist der Richtige.
Olafure
Verwenden Sie einfach $ server_name anstelle von mysite.com
Fedir RYKHTIK 28.10.14

Antworten:

749

Richtiger Weg in neuen Versionen von Nginx

Entpuppen meine erste Antwort auf diese Frage zu bestimmten Zeit korrekt war, aber es stellte sich in eine andere Gefahr - zu bleiben auf dem neuesten Stand überprüfen Sie bitte Taxing Tücken umschreiben

Ich wurde von vielen SE-Benutzern korrigiert, daher geht das Guthaben an sie, aber was noch 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; 

       [....]
}
Saif Bechan
quelle
3
Sie müssten dies jedoch Domain für Domain tun - nein? Was wäre, wenn Sie es auf jede Domain auf Ihrem Server anwenden möchten?
JM4
30
@ JM4: Wenn Sie $ host $ anstelle von server_name für das Neuschreiben verwenden und default_server zur listen-Direktive hinzufügen, funktioniert dies für jede Domain auf Ihrem Server.
Klaas van Schelven
5
Es ist wichtig zu erwähnen, dass der 301 ohne Ablaufdatum in Ihrem lokalen Cache gespeichert ist. Nicht sehr nützlich, wenn sich die Konfiguration ändert
Trefex 10.04.15
9
@jeder Verwenden Sie eine 307-Umleitung, um den POST-Inhalt beizubehalten.
Mahmoud Al-Qudsi
10
Beachten Sie, dass Sie $hostanstelle von $server_nameSubdomains verwenden müssen.
Catfish
276

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

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

Im einfachsten Fall wird Ihr Host als Ihr Dienst festgelegt, an den Sie ihn senden möchten. Dies führt eine 301-Weiterleitung zum Browser durch und die Browser-URL wird entsprechend aktualisiert.

Unten ist die vorherige Antwort, die aufgrund von 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.

Michael Neale
quelle
15
Ich denke, es sollte 80 sein - da dies auf http wartet und dann dem Client sagt, dass er als https (443) zurückkehren soll.
Michael Neale
3
Dies sollte die beste Antwort sein!
Nathan
3
Dies ist die anstrengendste Antwort.
Rechtssache
1
Dies ist die einfachste, aber die am wenigsten sichere - auf diese Weise können Sie Ihrem Server erlauben, einen Benutzer auf eine Seite umzuleiten, ohne zu prüfen, ob er überhaupt auf Ihrem Server verwendet werden darf. Wenn Ihr Server mydomain.co bereitstellt, können böswillige Benutzer Ihren Server weiterhin verwenden, um Benutzer zu anderen Domains wie mydomain.co wie google.com umzuleiten.
Friedkiwi
10
@ cab0lt hier gibt es keine sicherheitsprobleme. Die Weiterleitung stellt kein Sicherheitsrisiko dar. Wenn Zugriffskontrollanforderungen bestehen, sollten diese an der Stelle überprüft werden, an der der Browser die neue URL anfordert. Der Browser erhält nicht nur aufgrund der Weiterleitung Zugriff, und er benötigt auch keine Weiterleitung, um die neue URL anzufordern.
mc0e
125

Ich denke, der beste und einzige Weg sollte sein, eine dauerhafte Umleitung mit HTTP 301 Moved wie folgt zu verwenden:

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

Die permanente Umleitung von HTTP 301 Moved ist auch die effizienteste, da laut bereits erwähnten Pitfails kein regulärer Ausdruck ausgewertet werden muss .


Das neue HTTP 308 Moved behält die Request-Methode dauerhaft bei und wird von den gängigen Browsern unterstützt . Zum Beispiel mit 308Browser aus von Ändern der Anforderungsmethode verhindert , POSTum GETdie Umleitungsanforderung.


Wenn Sie den Hostnamen und die Unterdomäne beibehalten möchten, ist dies der richtige Weg.

Dies funktioniert immer noch, wenn Sie kein DNS haben , da ich es auch lokal verwende. Ich fordere zum Beispiel mit an http://192.168.0.100/index.phpund werde auf genau umgeleitet https://192.168.0.100/index.php.

Ich verwende listen [::]:80auf meinem Host, weil ich auf bindv6onlyfestgelegt habe false, so bindet es auch an IPv4-Socket. Ändern Sie listen 80die Einstellung in, wenn Sie IPv6 nicht oder nicht an eine andere Stelle binden möchten.

Die Lösung von Saif Bechan verwendet das, server_namewas in meinem Fall localhost ist, aber nicht über ein Netzwerk erreichbar ist.

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

kmindi
quelle
Schön, dass Sie versuchen, es zu zitieren, aber 301 funktioniert nicht auf HTTPS.
Fall
5
was funktioniert nicht? Der angegebene Serverabschnitt ist für unverschlüsselten http-Verkehr (ohne s) vorgesehen, der permanent auf den verschlüsselten Server umgeleitet wird (der Abschnitt, der auf 443 (https) lauscht, ist nicht aufgeführt)
kmindi
Ich habe überprüft, ob dies mit https und allem funktioniert - @kmindi Ich habe meine Antwort mit Bezug auf Ihre aktualisiert - da ich denke, dass es der richtige Weg ist und dies immer wieder auftaucht! Gute Arbeit.
Michael Neale
Funktioniert bei Verwendung einer Domänenanforderung (keine IP-Adresse) nur, wenn ich "[::]: 80" in "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
20

Innerhalb des Server-Blocks können Sie auch Folgendes tun:

# Force HTTPS connection. This rules is domain agnostic
if ($scheme != "https") {
    rewrite ^ https://$host$uri permanent;
}
Oriol
quelle
2
Diese Konfiguration hat dazu geführt, dass mein Server eine Umleitungsschleife erstellt hat
Corkscreewe
Möglicherweise, weil eine andere Weiterleitung vorhanden ist oder https in Ihrer Site / App nicht aktiviert ist
Oriol
1
Keiner der anderen schien zu funktionieren, außer diesem. Verwenden von Nginx-Version: Nginx / 1.10.0 (Ubuntu)
ThatGuy343
upvoted für https: // $ host $ uri
AMB
4
Dies ist der richtige Weg, wenn Sie sich hinter einem Loadbalancer befinden!
Antwan
17

Das oben Genannte hat nicht funktioniert, da ständig neue Subdomains erstellt wurden. zB AAA.example.com BBB.example.com für ca. 30 Subdomains.

Endlich habe ich eine Konfiguration, 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
# ...
}
Aleck Landgraf
quelle
Dankeschön! nginx würde 301 https://*/die Anfrage in den anderen Antworten hier entweder zurückgeben oder vorzeitig stornieren. server_name _;mit $hostwar die Antwort, die den Trick tat. +1
zamnuts
1
Dieser ist optimal! Ich empfehle jedoch, einige durch _die eigentliche Domain zu ersetzen , z. B. .domain.comich hatte zwei Server, und nginx leitete versehentlich einen meiner Server an den Standardserver.
zzz
1
Dies ist die einzige Antwort, die für mich funktioniert hat, danke!
Schneemann
Vielen Dank Kumpel .. Ich habe viele der Lösungen ausprobiert, aber nicht geklappt. Diese Lösung ist fantastisch und hat bei mir funktioniert. Servername _; Wofür ist das gedacht? Ich habe es nicht verstanden. Bitte erkläre mir das.
Pavan Kumar
6

Ich habe vor langer, langer Zeit einen Kommentar zur richtigen Antwort mit einer sehr wichtigen Korrektur gepostet, aber ich halte es für notwendig, diese Korrektur in seiner eigenen Antwort hervorzuheben. Keine der vorherigen Antworten kann sicher verwendet werden, wenn Sie zu irgendeinem Zeitpunkt unsicheres HTTP eingerichtet haben 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 sprechen.

Das Problem tritt auf, wenn eine POSTAnfrage an Ihren Server gestellt wird. Wenn der Server mit einer einfachen 30xWeiterleitung antwortet, geht der POST-Inhalt verloren. Was passiert , ist , dass der Browser / Client die Anforderung an SSL - Upgrade aber Herabstufung der POSTauf eine GETAnfrage. Die POSTParameter gehen verloren und es wird eine falsche Anfrage an Ihren Server gesendet.

Die Lösung ist einfach. Sie müssen eine HTTP 1.1 307Umleitung verwenden. Dies ist in RFC 7231 S6.4.7 beschrieben:

  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 von der akzeptierten Lösung angepasste Lösung wird 307in Ihrem Weiterleitungscode verwendet:

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

       [....]
}
Mahmoud Al-Qudsi
quelle
4

Ich habe es so geschafft:

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

Stempel
quelle
Aktualisierte Version, ohne IF: paste.debian.net/plain/899679
stamster
4

Ich starte ngnix hinter einer AWS ELB. Die ELB spricht über http mit ngnix. Da die ELB keine Möglichkeit hat, Weiterleitungen an Clients zu senden, überprüfe ich den X-Forwarded-Proto-Header und leite ihn weiter:

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

Wenn Sie return 301 https://$host$request_uri;die Standardantwort auf Port 80 sind, kann es sein, dass Ihr Server früher oder später eine Liste offener Proxys [1] erhält und missbraucht wird, um Datenverkehr an eine andere Stelle im Internet zu senden. Wenn sich Ihre Protokolle mit Nachrichten wie dieser füllen, wissen Sie, dass es Ihnen 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 $hostalles, was der Browser im HostHeader oder sogar im Hostnamen aus der Eröffnungszeile von HTTP sendet , wie folgt wiedergegeben wird:

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

Aufgrund dieses Problems empfehlen einige andere Antworten hier die Verwendung von $server_nameanstelle von $host. $server_nameWertet immer so aus, wie Sie es in der server_nameErklärung angegeben haben. Wenn Sie jedoch mehrere Subdomains haben oder einen Platzhalter verwenden, funktioniert dies nicht, da $server_namenur der erste Eintrag nach der server_nameDeklaration verwendet wird und vor allem nur ein Platzhalter zurückgegeben wird (nicht erweitert).

Wie kann man also mehrere Domänen unterstützen und gleichzeitig die Sicherheit gewährleisten? Auf meinen eigenen Systemen habe ich dieses Dilemma gelöst, indem ich zuerst einen default_serverBlock aufgelistet habe, der nicht verwendet wird $host, und dann einen Platzhalterblock aufgeführt habe, der Folgendes bewirkt:

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önnen auch mehr als eine Domain im zweiten Block angeben.)

Bei dieser Kombination werden nicht zugeordnete Domains (immer example.com) an einen festen Ort umgeleitet , und Domains, die mit Ihren eigenen übereinstimmen, werden an die richtige Stelle verschoben . Ihr Server ist nicht als offener Proxy geeignet, sodass Sie keine Probleme haben.

Wenn Sie sich feurig fühlen, können Sie wahrscheinlich auch dafür sorgen, dass der default_serverBlock keiner Ihrer legitimen Domänen entspricht, und etwas Anstößiges anrichten. . . .

[1] Technisch gesehen ist "Proxy" das falsche Wort, da Ihr Server nicht ausfällt und Anforderungen für die Clients erfüllt, sondern nur eine Umleitung 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 Protokolle mit Lärm und verbraucht Ihre CPU und Bandbreite, so dass Sie es genauso gut verhindern können.

Paul A Jungwirth
quelle
0

Es sieht so aus, als hätte niemand wirklich 100% richtig verstanden. Damit Port 80-Anforderungen für einen gesamten Webserver an ihre 443-Entsprechungen gesendet werden, müssen Sie die listen- Direktive verwenden, nicht die server_name-Direktive, um den Catch-All- Namen anzugeben . Siehe auch https://nginx.org/en/docs/http/request_processing.html

Server {
    Listen 80 Standard;
    listen [::]: 80 default;
      return 307 https: // $ host $ request_uri;
}
  • $ host fängt Subdomainnamen ab.
  • 307 und 308 enthalten sowohl POST- als auch GET-Anforderungs-URIs.
  • 307 ist temporär, nach gründlicher Prüfung auf Permanent 308 ändern:

Und stellen Sie sicher, dass Sie überprüfen, was bereits in /etc/nginx/conf.d/ enthalten ist, da ich häufig Probleme hatte, bei denen die default.conf einen vorhandenen vhost zurückgab. Meine Arbeit mit Nginx-Problemen beginnt immer damit, dass ich die Standarddatei herausnehme und sie zeilenweise wieder auskommentiere, um festzustellen, wo es schief geht.

Julius
quelle
-1
rewrite ^!https https://$host$request_uri permanent;
nntb2a
quelle