Zapobiegaj przekierowywaniu ruchu przez nginx z https na http, gdy jest używany jako odwrotny serwer proxy

16

Oto moja skrócona konfiguracja vgin nginx:

upstream gunicorn {
    server 127.0.0.1:8080 fail_timeout=0;
}

server {
    listen 80;
    listen 443 ssl;
    server_name domain.com ~^.+\.domain\.com$;

    location / {
        try_files $uri @proxy;
    }

    location @proxy {
        proxy_pass_header Server;
        proxy_redirect off;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_connect_timeout 10;
        proxy_read_timeout 120;
        proxy_pass http://gunicorn;
    }
}

Ten sam serwer musi obsługiwać zarówno HTTP, jak i HTTPS, jednak gdy nadrzędny wyda przekierowanie (na przykład po przetworzeniu formularza), wszystkie żądania HTTPS zostaną przekierowane na HTTP. Jedyną rzeczą, którą znalazłem, która naprawi ten problem, jest zmiana proxy_redirectna następujące:

proxy_redirect http:// https://;

Działa to doskonale w przypadku żądań pochodzących z HTTPS, ale jeśli przekierowanie jest wysyłane przez HTTP, przekierowuje je również do HTTPS, co stanowi problem.

Z desperacji próbowałem:

if ($scheme = 'https') {
    proxy_redirect http:// https://;
}

Ale Nginx narzeka, że proxy_redirecttutaj nie jest dozwolone.

Jedyną inną opcją, jaką mogę wymyślić, jest zdefiniowanie dwóch serwerów osobno i ustawienie proxy_redirecttylko na SSL, ale wtedy powieliłbym resztę konf (w serverdyrektywie jest wiele rzeczy , których pominąłem dla uproszczenia). Wiem, że mógłbym również użyć includedyrektywy, aby odrzucić nadmiarowość, ale naprawdę chcę zachować tylko jeden plik conf bez żadnych zależności.

Po pierwsze, czy brakuje mi czegoś, co całkowicie zlikwiduje problem? Albo, po drugie, jeśli nie, czy jest jakiś inny sposób (oprócz dołączenia pliku zewnętrznego), aby oddzielić informacje o zbędnej konfiguracji, aby móc rozdzielić wersje HTTP i HTTPS konfiguracji serwera?

Chris Pratt
źródło

Odpowiedzi:

29

Mam trochę inspiracji i próbowałem:

proxy_redirect http:// $scheme://;

Co wydaje się załatwić sprawę. Wciąż wydaje mi się to jednak hackingowe, dlatego z zadowoleniem przyjmuję wszelkie wskazówki dotyczące wszystkiego, co robię źle lub mniej hackerskich sposobów osiągnięcia tego samego rezultatu.

Chris Pratt
źródło
Rzeczywiście wydaje się, że jest to „oficjalny” sposób na zrobienie tego ... patrz wiki.nginx.org/SSL-Offloader
Hendy Irawan
Powyższy link do wiki nginx już nie działa, nowa lokalizacja to nginx.com/resources/wiki/start/topics/examples/SSL-Offloader
Paul Tobias
To nie zadziała, jeśli Twoja lokalizacja nie ma końcowego ukośnika
hdave
bóg cholernie cholera, dlaczego nie można oczekiwać, aby oprogramowanie tylko żyć za reverse proxy (lub przynajmniej cholernym szacunkiem X-Przekazano-Scheme lub jakiegokolwiek Blet +?
Axel Latvala
5

Innym rozwiązaniem jest wskazanie nadrzędnemu, czy żądanie to HTTP czy HTTPS i wydanie odpowiedniego przekierowania. Dodanie tego w konfiguracji nginx ustawiłoby nagłówek do sprawdzenia w górę.

proxy_set_header    X-Scheme $scheme;
mgorven
źródło
Ach, teraz widzę, że masz już tę konfigurację.
mgorven
Tak. Niemniej jednak doceniam próbę pomocy.
Chris Pratt
4
To wydaje się być trikowym nagłówkiem. Myślę, że X-Forwarded-Proto jest lepszy
vladkras