it-swarm.com.de

Richtiges Einrichten eines "Standard" -Nginx-Servers für https

Ich habe mehrere Server auf demselben Computer, einige nur mit http, einige mit http und https. In separaten Dateien sind mehrere Serverblöcke definiert, die in der Hauptkonfigurationsdatei enthalten sind.

Ich habe einen "Standard" -Server für http eingerichtet, der eine allgemeine "Wartungsseite" für Anforderungen bereitstellt, die keinem der anderen Servernamen in den anderen Konfigurationsdateien entsprechen. Der http-Standardserver funktioniert wie erwartet, verwendet den Servernamen "_" und wird zuerst in der Liste der Includes angezeigt (da ich festgestellt habe, dass bei doppelten Servernamen zwischen Servern der zuerst verwendete verwendet wird). Das funktioniert super.

Ich würde den gleichen exakten Serverblock erwarten (nur das Umschalten von "listen 80 default_server" auf "listen 443 default_server" und auch anstelle der Serving-Seite "return 444"), jedoch nicht. Stattdessen scheint der neue Standard-https-Server tatsächlich alle eingehenden https-Verbindungen abzurufen und zum Fehlschlagen zu führen, obwohl die anderen Serverblöcke geeignetere Servernamen für die eingehenden Anforderungen haben. Wenn Sie den neuen Standard-https-Server entfernen, wird das halbkorrekte Verhalten fortgesetzt: Die Websites mit https werden alle korrekt geladen. Die Websites ohne https werden jedoch alle an den ersten https-Server in den Include-Dateien weitergeleitet (wenn laut Dokumentation kein "default_server" angezeigt wird, ist der erste Serverblock, der angezeigt wird, "default").

Meine Frage ist also, wie man einen "Standardserver" in nginx für SSL-Verbindungen richtig definiert. Warum wird es, wenn ich explizit einen "Standard-Server" setze, gierig und greift nach allen Verbindungen, während es, wenn ich nginx implizit den "Standardserver" entscheiden lasse, wie erwartet funktioniert (mit dem falschen Server als Standard und den anderen realen Servern) richtig verhalten)?

Hier sind meine "Standardserver". HTTP funktioniert ohne andere Server zu beschädigen. Https bricht andere Server und verbraucht alles.

server {
    listen 443 ssl default_server;
    server_name _;

    access_log /var/log/nginx/maintenance.access.log;
    error_log /var/log/nginx/maintenance.error.log error;

    return 444;
}

server {
    listen *:80 default_server;
    server_name _;
    charset utf-8;

    access_log /var/log/nginx/maintenance.access.log;
    error_log /var/log/nginx/maintenance.error.log error;

    root /home/path/to/templates;

    location / {
        return 503;
    }

    error_page 503 @maintenance;

    location @maintenance {
        rewrite ^(.*)$ /maintenance.html break;
    }
}

Hat jemand von euch gesehen, was hier falsch sein könnte?

84
Roar

In Ihrem "Standard" -Htpsps-Block ist kein ssl_certificate oder ssl_certificate_key definiert. Obwohl Sie für dieses Standardszenario keinen echten Schlüssel haben oder möchten, müssen Sie dennoch einen konfigurieren, da sonst nginx das von Ihnen beschriebene unerwünschte Verhalten aufweist.

Erstellen Sie ein selbstsigniertes Zertifikat mit dem allgemeinen Namen * und schließen Sie es an Ihre Konfiguration an. Es funktioniert dann wie gewünscht.

Das "Standard" -Verhalten unter dieser Einrichtung besteht darin, dass ein Browser eine Warnung erhält, dass das Zertifikat nicht vertrauenswürdig ist. Wenn der Benutzer das Zertifikat ausnahmsweise hinzufügt, wird die Verbindung von nginx getrennt und die Standardeinstellung seines Browsers wird angezeigt Fehlermeldung "Verbindung konnte nicht hergestellt werden".

29

Ich habe es geschafft, ein gemeinsames dediziertes Hosting auf einer einzelnen IP mit nginx zu konfigurieren. Standardmäßig werden HTTP und HTTPS für eingehende unbekannte Domänen mit 404 bedient.

1 - Standardzone erstellen

Da nginx vhosts in aufsteigender Reihenfolge lädt, sollten Sie eine 00-default - Datei/einen symbolischen Link in Ihre /etc/nginx/sites-enabled Erstellen.

2 - Füllen Sie die Standardzone

Füllen Sie Ihren 00-default Mit Standard-vhosts. Hier ist die Zone, die ich benutze:

server {
    server_name _;
    listen       80  default_server;
    return       404;
}


server {
    listen 443 ssl;
    server_name _;
    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;
    return       404;
}

- Selbstsigniertes Zertifikat erstellen, testen und neu laden

Sie müssen ein selbstsigniertes Zertifikat in /etc/nginx/ssl/nginx.crt Erstellen.

Erstellen Sie ein selbstsigniertes Standardzertifikat:

Sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt

Nur eine Erinnerung:

  • Testen Sie die Nginx-Konfiguration vor dem Neuladen/Neustarten: nginx -t
  • Laden Sie einen Genuss neu: Sudo service nginx reload

Ich hoffe es hilft.

25
Ifnot

Grundsätzlich möchten wir unbedingt vermeiden, dass die erste Serverdefinition in unserer Konfigurationsdatei als Catch-All-Server für SSL-Verbindungen dient. Wir alle wissen, dass dies der Fall ist (im Gegensatz zu http und der Verwendung der default_server-Konfiguration, die gut funktioniert).

Dies kann (noch) nicht deklarativ für SSL erreicht werden, daher müssen wir es mit einem IF codieren ...

Die Variable $Host ist der Hostname aus der Anforderungszeile oder dem http-Header. Die Variable $server_name ist der Name des Serverblocks, in dem wir uns gerade befinden.

Wenn diese beiden also nicht gleich sind, haben Sie diesen SSL-Serverblock für einen anderen Host bereitgestellt, sodass dieser blockiert werden sollte.

Der Code enthält keine spezifischen Verweise auf Ihre Server-IP-Adressen, sodass er ohne Änderungen problemlos für andere Serverkonfigurationen wiederverwendet werden kann.

Beispiel:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    ###
    ### Section: SSL

    #
    ## Check if this certificate is really served for this server_name
    ##   http://serverfault.com/questions/578648/properly-setting-up-a-default-nginx-server-for-https
    if ($Host != $server_name) {
        #return 404 "this is an invalid request";
        return       444;
    }

    ...
17
Rolf

Um mehr über die Antwort von Radmilla Mustafa zu erfahren:

Nginx verwendet den 'Host'-Header für die Übereinstimmung von Servernamen. Es wird kein TLS-SNI verwendet. Dies bedeutet, dass nginx für einen SSL-Server eine SSL-Verbindung akzeptieren muss, was darauf hinausläuft, über ein Zertifikat/einen Schlüssel zu verfügen. Das Zertifikat/der Schlüssel kann ein beliebiges sein, z. selbstsigniert.

Siehe Dokumentation

Daher lautet die Lösung:

server {
    server_name _;
    listen 80 default_server;
    listen 443 ssl default_server;

    ## To also support IPv6, uncomment this block
    # listen [::]:80 default_server;
    # listen [::]:443 ssl default_server;

    ssl_certificate <path to cert>;
    ssl_certificate_key <path to key>;
    return 404; # or whatever
}
8
andreycpp

An alle, die so viel Haare verloren haben wie ich (heute fast den ganzen Tag damit verbracht). Ich habe fast alles versucht, und das, was es endlich richtig funktionieren ließ, war diese dumme Zeile:

ssl_session_tickets off;

Aufbauend auf der Antwort von Ifnot lautet mein Arbeitsbeispiel:

server {
    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;
    server_name _;

    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;
    ssl_session_tickets off;

    return 404;
}

Ich habe keine Ahnung, warum dies notwendig war. Das einzige Prinzip, das ich daraus abgeleitet habe, war, dass sich Nginx sehr seltsam verhält, wenn wir ihm nicht geben, was er will.

4
Marek Lisý

Wenn Sie absolut sicher sein möchten, verwenden Sie separate IP-Adressen für Hosts, die nicht auf HTTPS antworten sollen, und Hosts, die dies tun sollten. Dies behebt auch das Browser-Warnproblem "Ungültiges Zertifikat".

1
Michael Hampton