Dlaczego Listen 443 default_server; Reguła nginx zastępuje już skonfigurowaną regułę (reguły HTTP działają normalnie)?

9

Mam nginx i różne subdomeny:

a.mydomain.com
b.mydomain.com
c.mydomain.com

Nginx ma 4 zasady:

1) reguła przepisywania:

server {
  listen 80
  server_name gl.udesk.org;

  root /nowhere;
  rewrite ^ https://a.mydomain.com$request_uri permanent;
}

2) Reguła https:

server {

  listen 443;
  server_name a.mydomain.com;

  root /home/a/a/public;

  ssl on;
  ssl_certificate conf.d/ssl/a.crt;
  ssl_certificate_key conf.d/ssl/a.key;
  ssl_protocols ...
  ssl_ciphers ...
  ssl_prefer_server_ciphers on;

  location ...
}

3) Domyślna reguła http:

server {
  listen 80 default_server;
  return 444;
}

4) Domyślna reguła https:

server {
  listen 443 default_server;
  return 444;
}

Więc jeśli uruchomię nginx i:

  • jeśli przejdę do przeglądarki na http://a.mydomain.com , przekieruje na https://a.mydomain.com, a następnie zwróci błąd 107 (net :: ERR_SSL_PROTOCOL_ERROR): błąd protokołu SSL.
  • jeśli przejdę do przeglądarki na https://b.mydomain.com , spodziewam się, że zwróci błąd 444. Zamiast tego zwraca ten sam błąd 107 (net :: ERR_SSL_PROTOCOL_ERROR): Błąd protokołu SSL.
  • i tak dla wszystkich zarejestrowanych przez dostawcę DNS CNAME (tj. a, b, c)
  • wszystkie wersje http (np. reguła 3 -) działają zgodnie z oczekiwaniami:

Dlaczego więc reguły https w Nginx są tak trudne do skonfigurowania i jak mam je odpowiednio skonfigurować, aby uzyskać takie samo zachowanie jak w przypadku wersji HTTP?

Aktualizacja:

Tworzenie nowego certyfikatu i dodawanie:

ssl on;
ssl_certificate conf.d/ssl/default.crt;
ssl_certificate_key conf.d/ssl/default.key;

działa teraz, ale miałbym rozwiązanie bez wymaganego certyfikatu SSL. Wystarczy zresetować wszystkie połączenia dla wszystkich subdomen https (port 443) oprócz https://a.mydomain.com bez podawania certyfikatu.

statyczny
źródło
2
Nie możesz SSL wymaga certyfikatu, zanim serwer internetowy wie, jakiej domeny chcesz . Musi mieć certyfikat do wysłania lub nie może nawiązać połączenia w celu rozmowy z klientem.
Darth Android
2
@DarthAndroid: Magia nazywa się SNI - en.wikipedia.org/wiki/Server_Name_Indication .
Shi,
@Shi Jestem świadomy SNI - To pozwala wybrać serwer WWW , który certyfikat wysłać, ale wciąż musi podnieść się certyfikat. nginxnie jest wystarczająco inteligentny, aby zdać sobie sprawę, że nie potrzebuje certyfikatu do tego, co użytkownik chce zrobić.
Darth Android

Odpowiedzi:

3

Nie mieszaj portu 443 z ssl! Nginx jest całkowicie niezależny od portu. Możesz także oferować https przez port 80. Nowoczesne wersje Nginx pozwalają

listen 1234 ssl;

i wtedy nie potrzebujesz ssl on;linii.

Ale jeśli chcesz obsługiwać protokół https, musisz określić certyfikat. Twój serwer wprowadza https, kiedy przepisuje żądanie HTTP na żądanie https.

Otrzymujesz BŁĄD PROTOKOŁU, ponieważ uzgadnianie SSL odbywa się przed czymkolwiek innym. Więc return 444nie został osiągnięty. Do uzgadniania algorytmów szyfrowania parą certyfikatu / klucza prywatnego niezbędny jest uścisk dłoni SSL i certyfikat.

ikrabbe
źródło
3

returnDyrektywa jest częścią modułu rewrite. Jeśli sprawdzisz dokumentację , możesz zauważyć, że działa ona z żądaniami. W HTTPS żądania można składać tylko po zakończeniu uzgadniania.

Pojawiło się żądanie funkcji: https://trac.nginx.org/nginx/ticket/195 i zapewniono rozwiązanie obejścia.

server {
    listen 443 ssl;
    server_name bbb.example.com;
    ssl_ciphers aNULL;
    ssl_certificate /path/to/dummy.crt;
    ssl_certificate_key /path/to/dummy.key;
    return 444;
}
VBart
źródło
Zauważ, że spowoduje to przerwanie dostępu klientów HTTPS nieobsługujących SNI (takich jak własny nginx proxy_pass, chyba że ustawiłeś proxy_ssl_server_name on;) przed dotarciem do innych server_names(tak więc zasadniczo złamie uzasadnione server_names, które chcesz przepuścić). Szczegółowe informacje można znaleźć na stronie trac.nginx.org/nginx/ticket/195#comment:11 .
nh2