it-swarm.com.de

Nginx startet nicht mit Host, der nicht im Upstream gefunden wurde

Ich verwende Nginx, um dauerhafte Verbindungen zu weit entfernten Servern für mich zu proxyen und aufrechtzuerhalten.

Ich habe ungefähr 15 Blöcke ähnlich diesem Beispiel konfiguriert:

upstream rinu-test {
    server test.rinu.test:443;
    keepalive 20;
}
server {
    listen 80;
    server_name test.rinu.test;
    location / {
        proxy_pass https://rinu-test;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $http_Host;
    }
}

Das Problem ist, wenn der Hostname nicht in einem oder mehreren der upstream Blöcke aufgelöst werden kann, wird nginx nicht (neu) gestartet. Ich kann auch keine statischen IPs verwenden. Einige dieser Hosts haben ausdrücklich darauf verzichtet, da sich die IPs ändern. In jeder anderen Lösung, die ich für diese Fehlermeldung gesehen habe, heißt es, upstream loszuwerden und alles im location -Block zu tun. Das ist hier nicht möglich, da keepalive nur unter upstream verfügbar ist.

Ich kann es mir vorübergehend leisten, einen Server zu verlieren, aber nicht alle 15.

Bearbeiten: Es stellt sich heraus, dass Nginx für diesen Anwendungsfall nicht geeignet ist. Es sollte ein alternativer Keepalive-Proxy für das Backend (Upstream) verwendet werden. Eine benutzerdefinierte Node.js-Alternative ist in meine Antwort . Bisher habe ich keine anderen Alternativen gefunden, die tatsächlich funktionieren.

29
rinu

Frühere Versionen von nginx (vor 1.1.4), die bereits eine große Anzahl der am häufigsten besuchten Websites weltweit betrieben haben (und dies auch heute noch tun, wenn man den Server-Headern Glauben schenkt), unterstützten nicht einmal keepalive auf der upstream Seite, da dies in der Einstellung für das Rechenzentrum nur sehr wenig von Vorteil ist, es sei denn, Sie haben eine nicht triviale Latenz zwischen Ihren verschiedene Gastgeber; Eine Erklärung finden Sie unter https://serverfault.com/a/883019/11002 .

Grundsätzlich besteht die Möglichkeit, dass Ihre Architektur weniger belastbar und schlechter ist, es sei denn, Sie wissen, dass Sie speziell zwischen Upstream und Front-End eine Keepalive-Funktion benötigen.

(Beachten Sie, dass Ihre aktuelle Lösung ebenfalls falsch ist, da eine Änderung der IP-Adresse ebenfalls unerkannt bleibt, da Sie die Hostnamenauflösung nur beim erneuten Laden der Konfiguration vornehmen. Selbst wenn nginx gestartet wird, funktioniert es im Grunde genommen nicht mehr, sobald die IP-Adressen vorliegen der Upstream-Server ändern sich.)

Mögliche Lösungen, wählen Sie eine:

  • Die beste Lösung scheint nur zu sein, upstreamkeepalive als wahrscheinlich unnötig in einer Datacenter-Umgebung loszuwerden und Variablen mit proxy_pass für eine aktuelle DNS-Auflösung für jede Anforderung (nginx ist immer noch intelligent genug, um solche Auflösungen noch zwischenzuspeichern)

  • Eine andere Möglichkeit wäre, eine kostenpflichtige Version von nginx über ein kommerzielles Abonnement zu erhalten, das einen resolve -Parameter für die server -Direktive innerhalb der upstream enthält. Kontext.

  • Schließlich könnte eine weitere Möglichkeit darin bestehen, eine set -Variable und/oder eine map zu verwenden, um die Server in upstream; dies wird weder bestätigt noch geleugnet, umgesetzt worden zu sein; es kann z. B. funktionieren oder nicht.

7
cnst

Eine Alternative besteht darin, einen neuen Dienst zu schreiben, der nur das tut, was ich will. Das Folgende ersetzt nginx für das Proxy von https-Verbindungen mit Node.js

const http = require('http');
const https = require('https');

const httpsKeepAliveAgent = new https.Agent({ keepAlive: true });

http.createServer(onRequest).listen(3000);

function onRequest(client_req, client_res) {
    https.pipe(
        protocol.request({
            Host: client_req.headers.Host,
            port: 443,
            path: client_req.url,
            method: client_req.method,
            headers: client_req.headers,
            agent: httpsKeepAliveAgent
        }, (res) => {
            res.pipe(client_res);
        }).on('error', (e) => {
            client_res.end();
        })
    );
}

Anwendungsbeispiel: curl http://localhost:3000/request_uri -H "Host: test.rinu.test" was äquivalent ist zu: curl https://test.rinu.test/request_uri

2
rinu

Eine mögliche Lösung besteht darin, einen lokalen DNS-Cache einzubeziehen. Es kann sich um einen lokalen DNS-Server wie Bind oder Dnsmasq handeln (bei einigen schlauen Konfigurationen kann nginx auch angegebener DNS-Server anstelle der Systemvorgabe verwenden) oder nur den Cache in hosts Datei.

Es scheint, dass die Verwendung von hosts -Dateien mit einigen Skripten sehr einfach ist. Die Hosts-Datei sollte in die statischen und dynamischen Teile aufgeteilt werden (d. H. cat hosts.static hosts.dynamic > hosts), und der dynamische Teil sollte automatisch von einem Skript generiert (und aktualisiert) werden.

Möglicherweise ist es sinnvoll, die Hostnamen von Zeit zu Zeit zu überprüfen, um IP-Adressen zu ändern, die Hostdatei zu aktualisieren und die Konfiguration in nginx bei Änderungen neu zu laden. Falls ein Hostname nicht aufgelöst werden kann, sollte die alte IP oder eine Standard-IP (wie 127.0.1.9) verwendet werden.

Wenn Sie die Hostnamen in der Nginx-Konfigurationsdatei nicht benötigen (dh IPs sind ausreichend), kann der Abschnitt upstream mit IPs (aufgelösten Hostnamen) durch ein Skript generiert werden und eingeschlossen in Nginx Config - und keine Notwendigkeit, die Hosts-Datei in einem solchen Fall zu berühren.

2
ruvim

Ich habe den Auflösungsparameter auf den Server gesetzt und Sie müssen den Nginx Resolver in der nginx.conf wie folgt einstellen:

/etc/nginx/nginx.conf:

http {
    resolver 192.168.0.2 ipv6=off valid=40s;  # The DNS IP server
} 

Site.conf:

upstream rinu-test {
    server test.rinu.test:443;
    keepalive 20;
}
1
Bruno Paiuca