Reverse Proxy Kommunikation im lokalen Netzwerk

Physically

Lt. Commander
Registriert
Nov. 2010
Beiträge
1.708
Nabend,

ich habe einen Ubuntu-Server laufen mit Nginx installiert, der als Reverse Proxy dient. Alle Anfragen an https://example.de werden von Nginx weitergeleitet nach http://localhost:3000. HTTP-Anfragen werden immer weitergeleitet auf die HTTPS URI.

Unter Port 3000 läuft eine Server-Side-Rendered App (Nuxt). Das funktioniert soweit. Die App kommuniziert über eine API (Node) mit dem Backend. Das Backend läuft unter Port 8080 und ist erreichbar unter http://localhost:8080.

So wie ich das verstehe, bilden Frontend und Backend hinter dem Reverse Proxy für sich ein lokales Netzwerk sodass sie problemlos untereinander kommunizieren können. Das Problem ist, dass jede API-Anfrage an das Backend geblockt wird.

In den Chrome Dev Tools heißt es:
net::ERR_CONNECTION_REFUSED

In den Mozilla Dev Tools:
Quellübergreifende (Cross-Origin) Anfrage blockiert: Die Gleiche-Quelle-Regel verbietet das Lesen der externen Ressource auf http://127.0.0.1:8080/api/videos/all. (Grund: CORS-Anschlag schlug fehl).

Laut den MDN web docs scheint das ein Problem mit der Anfrage von HTTPS auf HTTP zu sein. Der Node-Server hat eine Wildcard gesetzt in Bezug auf CORS.
Ich habe jetzt den gesamten Tag mit Recherche verbracht aber die meisten Leute haben einfach nur eine Instanz hinter den Reverse Proxy und das wars. Mein Szenario ist mir bis jetzt nicht vor die Augen gekommen.

netstat -plnt gibt folgendes

Code:
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.1:8080          0.0.0.0:*               LISTEN      2058/node /home/ben
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      1106/node
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      -
tcp6       0      0 :::80                   :::*                    LISTEN      -
tcp6       0      0 :::22                   :::*                    LISTEN      -
tcp6       0      0 :::443                  :::*                    LISTEN      -

Scheint als würden alle Beteiligten laufen und "listen".

Hier die Nginx-config (/etc/nginx/sites-available/default):

Code:
upstream backend {
        server localhost:8080;
}

upstream frontend {
        server localhost:3000;
}


server {
        server_name example.de www.example.de;

        location / {
                proxy_pass http://frontend;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection 'upgrade';
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto https;
        }


        listen [::]:443 ssl ipv6only=on; # managed by Certbot
        listen 443 ssl; # managed by Certbot

        ssl_certificate /etc/letsencrypt/live/example.de/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/example.de/privkey.pem; # managed by Certbot
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}



server {
        server_name example.de www.example.de;

        listen 80;
        listen [::]:80;

        if ($host = www.example.de) {
        return 301 https://$host$request_uri;
        } # managed by Certbot


        if ($host = example.de) {
        return 301 https://$host$request_uri;
        } # managed by Certbot
}

Und zu guter letzt noch eine Skizze:

[IMG]https://pics.computerbase.de/forum/attachments/774/774343-2fcbd25168a4fc0ab43526e4ed99d767.jpg[/IMG]

Danke für jegliche Hilfe!
 

Anhänge

  • problem.png
    problem.png
    14,4 KB · Aufrufe: 425
Ich nehme an example.de hast du rein gecshrieben um hier deine eigene domain nicht oeffentlich zu zeigen?
 
tut es wenn du ssl aus hast?
Zusatz.. Mach mal die v6 elemente in der config raus. Dein dienst ist ja eh auf v4. Nur um das als Quelle auszuschliessen
 
Zuletzt bearbeitet:
Die Devtools hast du im Browser offen? Dann will der Browser eine Anfrage an 127.0.0.1 stellen, blockiert das allerdings, weil du ja eigentlich mit example.de redest.
Ergänzung ()

Nur damit ich das wirklich richtig verstehe:
  • Du öffnest im Browser die Adresse example.de
  • Die Anfrage geht an das Frontend
  • Das Frontend redet dabei mit dem Backend
  • Die Webseite im Browser redet NICHT mit dem Backend

Ergänzung ()

Ist die nginx Config vollständig geposted? Da wird nämlich ein Upstream zum Backend definiert, aber nie benutzt.
 
@madmax2010 : Also nur über HTTP gibt es keine Probleme mit der API-Kommunikation. Habe einen cleanen Ubuntu-Server aufgesetzt und getestet.

@KillerCow

KillerCow schrieb:
Die Devtools hast du im Browser offen?

Ja

KillerCow schrieb:
  • Du öffnest im Browser die Adresse example.de
  • Die Anfrage geht an das Frontend
  • Das Frontend redet dabei mit dem Backend
  • Die Webseite im Browser redet NICHT mit dem Backend

Ja, alles richtig.

KillerCow schrieb:
Ist die nginx Config vollständig geposted? Da wird nämlich ein Upstream zum Backend definiert, aber nie benutzt.

Ja ist vollständig. Der Upstream zum Backend ist überflüssig. Der kann weg. Aber auch wenn dieser weg ist funktioniert es nicht.
 
So wie ich dich verstehe, läuft das Backend unabhängig vom Frontend und sollte von außen gar nicht erreichbar sein. Backend und Frontend kommunizieren serverintern über eine API.
Firefox blockiert nun eine Anfrage an "localhost", eine Anfrage, die eigentlich das Frontend intern an sich selber stellen sollte. Irgendwie rutscht diese nun doch nach draußen.
Wenn ich dein Problem richtig verstanden habe, scheint mir das Problem nicht bei Nginx zu liegen, sondern bei deinem FrontEnd. Vermutlich hast du irgendeinen JavaScript Code, den nicht der Server ausführt, sondern an den Browser weitergeleitet wird. Den Code würde ich an deiner Stelle prüfen.
 
  • Gefällt mir
Reaktionen: KillerCow
Aber warum funktioniert dann die Kommunikation unverschlüsselt über HTTP?

Mit der identischen Codebase.
Ergänzung ()

Habe jetzt ein SSL-Zertifikat auf den cleanen Ubuntu-Server installiert. Zwar kann ich die Domain über HTTPS aufrufen, aber gleicher Error. API-Kommunikation nicht mehr vorhanden.

So schaut die cleane nginx-config aus:

Code:
server {

        root /var/www/html;

        index index.html index.htm index.nginx-debian.html;

        server_name example.de www.example.de;

        location / {
                proxy_pass http://localhost:3000;
                 proxy_http_version 1.1;
                 proxy_set_header Upgrade $http_upgrade;
                 proxy_set_header Connection 'upgrade';
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;
        }


    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.de/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.de/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot


}
server {
    if ($host = www.example.de) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    if ($host = example.de) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


        listen 80 default_server;
        listen [::]:80 default_server;

        server_name example.de www.example.de;
    return 404; # managed by Certbot
}
 
Zuletzt bearbeitet:
Wie genau erfolgt der Aufruf?
Kann gut sein das der 301 Ärger macht.

Teste das ggf mal mit curl -I durch
 
curl -I gibt folgende Ergebnisse:

1) http://example.de
Code:
HTTP/1.1 301 Moved Permanently
Server: nginx/1.14.0 (Ubuntu)
Date: Wed, 11 Mar 2020 19:45:40 GMT
Content-Type: text/html
Content-Length: 194
Connection: keep-alive
Location: https://example.de/

2) https://example.de
Code:
HTTP/1.1 200 OK
Server: nginx/1.14.0 (Ubuntu)
Date: Wed, 11 Mar 2020 19:46:46 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 294059
Connection: keep-alive
Set-Cookie: auth.strategy=local; Max-Age=21600; Path=/; Secure
ETag: "47cab-IE8v561ropNjEXpFHM/PLJMv4pY"
Accept-Ranges: none
Vary: Accept-Encoding

Der 301 kommt ja vom Eintrag in der nginx-config wenn ich die Domain via HTTP aufrufe.

Ach so, Firewall (UFW) ist die ganze Zeit deaktivert falls jemand fragt.
 
Läuft denn aktuell alles auf demselben Host? Also auch der Browser?
Ich bleibe dabei, wie auch @Lukas' geschrieben hat, wenn du in den devtools im Browser einen Aufruf an 127.0.0.1 siehst, dann stimmt was nicht mit deiner Kommunikation Browser <-> Frontend <-> Backend. Der Aufruf impliziert eine direkte Abhängigkeit von Browser <-> Backend.
Die Blockierung durch den Browser kommt dann ggf. tatsächlich durch die Mischung aus https und http, wobei das dann eher ein "mixed-content" Fehler sein sollte.
Ergänzung ()

Laut dem curl Aufruf wird auch kein CORS Header gesetzt oder hast du das gekürzt? Da müsste mindestens ein "Access-Control-Allow-Origin" Header in der Antwort stehen... oder kommt der nur bei ner OPTIONS-Anfrage, bin ich mir gerade nicht sicher. Siehst du in den devtools den Header? Da müsste dann auch ein zugehöriger OPTIONS Request auftauchen.
Ok, eben nochmal gelesen. Same-origin greift auch bei einem Unterschied des Schemas, also http/https. Ändert aber nichts am Umstand, dass der Browser offenbar direkt mit dem Backend reden will und DAS ist dein eigentliches Problem.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: Lukas'
Sehe das genauso wie @KillerCow. Ich kann mir folgendes vorstellen:
Die Anfrage an "localhost" ist unnütz für den Aufbau der Webseite ist und führt ins Leere. Bei Aufruf via HTTP wird diese Anfrage ausgeführt (evtl. mal in den DevTools prüfen, welche Pakete bei Aufruf der Webseite rumgeschickt werden) und stört trotz Fehler nicht. Bei HTTPS ist der Browser aber restriktiver und fürchtet einen Angriff, der die verschlüsselte Verbindung schwächt, weshalb er die Anfrage blockiert. Deshalb der Fehler bei verschlüsseltem Aufruf.

Das ist alles nur mein Bauchgefühl, detaillierter geht es bei der Fehlerbeschreibung nicht. Deshalb noch einmal der Rat: lass Nginx erst einmal in Ruhe und beschäftige dich mit dem Code deines Frontends.
 
Der Browser läuft nicht auf dem selben Host, das ist meine Router-IP oder wie meinst du?
Frontend und Backend laufen hinter einem Ubuntu-Server mit Nginx als Webserver-Software und eben Reverse Proxy.

Also das Problem ist soweit klar. Den Tipp mit dem Frontend nehme ich gerne an.

Im Frontend ist es so eingestellt, dass HTTP-Anfragen immer mit "http://localhost:8080/api" beginnen. So habe ich es als Basis-URL für Anfragen festgelegt. Hat halt auch im Development funktioniert und ist ja auch Sinn der Sache. Fragt sich halt was da anstelle dessen hin soll. Ich stelle mir es so vor. dass die Anfrage an z.B. "http://localhost:8080/api/videos/all" so verarbeitet wird, dass im lokalen Netzwerk, also hinterm Proxy, der Port 8080 angefragt wird. Eine andere Einstellung ist im Frontend nicht vorhanden (von mir).
Ergänzung ()

Ich habe es geschafft! Ich habe im Frontend die Base-URL für API-Requests von "http://localhost:8080/api" auf "/api" geändert. So gabs erstmal folgende Meldung von Chrome:

GET https://example.de/api/videos/all 404 (Not Found)

Dann habe ich in der Nginx-config folgenden Block eingebunden:

Code:
location /api {
                proxy_pass http://localhost:8080/api;
        }

Das macht Sinn. Jetzt komm ich aber von außen auch auf die API. Da kommen wahrscheinlich die CORS policies ins Spiel.

Was meint ihr, gibts noch dazu etwas zu beachten?
Ergänzung ()

Was mich allerdings wundert ist, dass nur ein API-Request gesendet wird, wenn ich auf der Seite navigiere. Wenn ich z.B. example.de/videos direkt aufrufe, dann wird keine Verbindung aufgebaucht. Komisch.
 
Zuletzt bearbeitet:
Dann ist die Situation doch exakt die, die dir von uns oben beschrieben wurde. Der Browser redet mit dem Backend. Du hast jetzt schlicht nur den Weg dahin über den nginx geebnet.

Bist du dir sicher, dass du verstanden hast, wie deine Applikation mit ihren Komponenten kommuniziert?
 
Ich bin mir sicher. Die Frage meinerseits wurde extra einfach gestellt falls es noch wichtige Dinge zu beachten gibt. Vielleicht kommt jemand und sagt: "Unbedingt XY in den Einstellungen aktivieren aus Sicherheitsgründen".
 
Zurück
Oben