Dlaczego Nginx odpowiada na dowolną nazwę domeny?

139

Mam uruchomiony Nginx z aplikacją Ruby / Sinatra i wszystko jest w porządku. Jednak próbuję teraz uruchomić drugą aplikację z tego samego serwera i zauważyłem coś dziwnego. Po pierwsze, oto mój nginx.conf:

pid /tmp/nginx.pid;
error_log /tmp/nginx.error.log;

events {
  worker_connections 1024;
  accept_mutex off;
}

http {
  default_type application/octet-stream;
  access_log /tmp/nginx.access.log combined;

  sendfile on;
  tcp_nopush on;
  tcp_nodelay off;

  gzip on;
  gzip_http_version 1.0;
  gzip_proxied any;
  gzip_min_length 500;
  gzip_disable "MSIE [1-6]\.";
  gzip_types text/plain text/xml text/css
             text/comma-separated-values
             text/javascript application/x-javascript
             application/atom+xml;

  upstream app {
    server unix:/var/www/app/tmp/sockets/unicorn.sock fail_timeout=0;
  }

  server {
    listen 80;
    client_max_body_size 4G;
    server_name FAKE.COM;

    keepalive_timeout 5;

    root /var/www/app/public;

    location / {
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_redirect off;

      if (!-f $request_filename) {
        proxy_pass http://app;
        break;
      }
    }

    error_page 500 502 503 504 /500.html;
    location = /500.html {
      root /var/www/app/public;
    }
  }
}
                                                          68,0-1        B

Zwróć uwagę, jak server_nameustawione jest, FAKE.COMże serwer odpowiada wszystkim hostom, które trafiają na ten serwer za pośrednictwem innych nazw domen. Jak sprawić, by ten konkretny serwer odpowiadał tylko na żądania FAKE.COM?

Jaskółka oknówka
źródło
listen fake.com | something.com:80 polecenia filtruje, nie server_name.
Alexei Martchenko

Odpowiedzi:

202

Pierwszy blok serwera w konfiguracji nginx jest domyślny dla wszystkich żądań trafiających do serwera, dla którego nie ma określonego bloku serwera.

Więc w twojej konfiguracji, zakładając, że twoja prawdziwa domena to REAL.COM, kiedy użytkownik wpisze to, zostanie to rozwiązane na twój serwer, a ponieważ nie ma bloku serwera dla tej konfiguracji, blok serwera dla FAKE.COM, jako pierwszy blok serwera (w twoim przypadku tylko blok serwera), przetworzy to żądanie.

Dlatego właściwe konfiguracje Nginx mają określony blok serwera dla ustawień domyślnych przed podążaniem za innymi dla określonych domen.

# Default server
server {
    return 404;
}

server {
    server_name domain_1;
    [...]
}

server {
    server_name domain_2;
    [...]
}

itp

** EDYTOWAĆ **

Wygląda na to, że niektórzy użytkownicy są nieco zdezorientowani tym przykładem i myślą, że jest on ograniczony do jednego pliku konfiguracyjnego itp.

Należy pamiętać, że powyższe jest prostym przykładem na to, aby PO rozwijało się zgodnie z wymaganiami.

Osobiście używam oddzielnych plików conf vhost z tym (CentOS / RHEL):

http {
    [...]
    # Default server
    server {
        return 404;
    }
    # Other servers
    include /etc/nginx/conf.d/*.conf;
}

/etc/nginx/conf.d/ będzie zawierał domain_1.conf, domain_2.conf ... domain_n.conf, które zostaną uwzględnione po bloku serwera w głównym pliku nginx.conf, który zawsze będzie pierwszym i zawsze będzie domyślnym, chyba że zostanie nadpisany przez default_server dyrektywy w innym miejscu.

W tym przypadku kolejność alfabetyczna nazw plików konfiguracyjnych dla innych serwerów nie ma znaczenia.

Ponadto taki układ zapewnia dużą elastyczność, ponieważ można zdefiniować wiele domyślnych wartości.

W moim konkretnym przypadku Apache nasłuchuje na porcie 8080 tylko na wewnętrznym interfejsie i przekazuję skrypty PHP i Perl do Apache.

Jednak uruchamiam dwie oddzielne aplikacje, które zwracają linki z „: 8080” w dołączonym wyjściowym html, ponieważ wykryją, że Apache nie działa na standardowym porcie 80 i próbują mi „pomóc”.

Powoduje to problem polegający na tym, że łącza stają się nieprawidłowe, ponieważ Apache nie jest dostępny z zewnętrznego interfejsu, a łącza powinny wskazywać na port 80.

Rozwiązuję ten problem, tworząc domyślny serwer dla portu 8080 do przekierowywania takich żądań.

http {
    [...]
    # Default server block for undefined domains
    server {
        listen 80;
        return 404;
    }
    # Default server block to redirect Port 8080 for all domains
    server {
        listen my.external.ip.addr:8080;
        return 301 http://$host$request_uri;
    }
    # Other servers
    include /etc/nginx/conf.d/*.conf;
}

Ponieważ nic w zwykłych blokach serwerów nie nasłuchuje na porcie 8080, domyślny blok serwera przekierowania w przejrzysty sposób obsługuje takie żądania ze względu na swoją pozycję w nginx.conf.

Właściwie mam cztery takie bloki serwera i jest to uproszczony przypadek użycia.

Dayo
źródło
1
Nginx wymaga rozróżniania wielkości liter - „Server” powinien być serwerem, a „Return” powinien być zwracany. Mam nadzieję, że zaoszczędzi to kilku problemów podczas kopiowania tego kodu.
Capaj,
2
statyczny, zobacz odpowiedź Olega Neumyvkina - jeśli masz wiele plików konfiguracyjnych w witrynach dostępnych, to pierwszy serwer w pierwszym pliku w kolejności alfabetycznej jest Twoim domyślnym. Podejrzewam, że to może być problem. Ponadto wiele dystrybucji uruchamia polecenie „nginx -t”, aby przetestować konfigurację przed ponownym uruchomieniem - możesz mieć błąd uniemożliwiający ponowne uruchomienie.
jwhitlock
2
To jest niekompletne i nie powinno być akceptowaną odpowiedzią. Aby to zadziałało, musiałbyś również usunąć default_server z wszystkich dyrektyw nasłuchujących.
Ben
@ben Po pierwsze, OP nie miał „default_server” w swoim przykładzie problemu, a odpowiedź jest dostosowana do specyfiki tego pytania. Po drugie, dlaczego ktokolwiek miałby definiować default_server w oddzielnej lokalizacji serwera podczas wykonywania instrukcji, aby ustawić pierwszy zdefiniowany serwer jako domyślny, jest poza mną. W każdym razie, jeśli domyślny_serwer został specjalnie zdefiniowany, to ten zestaw pytań i odpowiedzi nie jest tym, na co należy zwrócić uwagę, aby rozwiązać wszelkie problemy, które mogą mieć.
Dayo
1
@Dayo Masz rację, że zająłeś się określoną konfiguracją opublikowaną przez OP. Jednak aby uzyskać pełną odpowiedź na zadane pytanie, myślę, że należy wspomnieć o domyślnym serwerze. Bardzo możliwe jest przeczytanie twojej odpowiedzi i nie zdawanie sobie sprawy, w jaki sposób default_server by ją zakłócał. Jest to jeszcze bardziej prawdopodobne, ponieważ niektóre dystrybucje wysyłane z domyślnym serwerem zdefiniowanym w pliku mogą nie być oczywiste dla użytkownika.
Ben
61

Powinieneś mieć domyślny serwer dla catch-all , możesz wrócić404 lub lepiej nie odpowiadać w ogóle (zaoszczędzi trochę przepustowości), zwracając 444odpowiedź HTTP specyficzną dla nginx, która po prostu zamyka połączenie i nic nie zwraca

server {
    listen       80  default_server;
    server_name  _; # some invalid name that won't match anything
    return       444;
}
iTech
źródło
Pracował dla mnie dla nginx 1.8.0. server_name _;Nie miałem we wcześniejszych wersjach dla nginx, ale to działało. Teraz w przypadku nowszych wersji nginx wydaje się, że potrzebujesz server_name _;. Dzięki
daniel
Rozwiązany. Zapomniałem średnika; _;
user1201917
2
@iTech: Z jakiegoś powodu zwraca 444 dla wszystkich żądań. Jakieś wskazówki?
Divick
Świetna wskazówka na temat 444i imho jest znacznie czystszym rozwiązaniem niż zwracanie kodu błędu.
qqilihq
1
Ważne jest, aby określić certyfikat / klucz, w przeciwnym razie wszystkie połączenia SSL będą pasować i kończyć się niepowodzeniem, jak wskazał @AndreyT w swojej odpowiedzi poniżej.
Mark Fletcher
35

Nie udało mi się rozwiązać problemu żadną z pozostałych odpowiedzi. Rozwiązałem problem, sprawdzając, czy host pasuje i zwracając 403, jeśli nie. (Miałem przypadkową stronę internetową wskazującą na zawartość moich serwerów internetowych. Zgaduję, że przechwycę pozycję wyszukiwania)

server {
    listen 443;
    server_name example.com;

    if ($host != "example.com") {
        return 403;
    }

    ...
}
Matt Carrier
źródło
1
Jeśli to zła praktyka: nginx.com/resources/wiki/start/topics/depth/ifisevil
Esolitos
1
Są przypadki, w których po prostu nie można uniknąć użycia warunku if, na przykład, jeśli trzeba przetestować zmienną, która nie ma równoważnej dyrektywy.
Edward
4
@Esolitos Dosłownie trzecia linijka tego artykułu mówi, że ten przypadek użycia jest w porządku. Rozumiem potrzebę zachowania ostrożności, ale nie machajmy palcami w rozsądnych przypadkach użycia.
Włączono
Moim zdaniem najłatwiejsze i najbardziej zwięzłe rozwiązanie, ponieważ wymaga tylko 3 linii kodu, które możesz z przyjemnością wkleić do dowolnego pliku vhost, zmieniając potem tylko porównywany $ host.
Akito
28

Odpowiadając na twoje pytanie - nginx wybiera pierwszy serwer, jeśli nie ma dopasowania. Zobacz dokumentację :

Jeśli jego wartość nie jest zgodna z żadną nazwą serwera lub żądanie w ogóle nie zawiera tego pola nagłówka, wtedy nginx skieruje żądanie do domyślnego serwera dla tego portu. W powyższej konfiguracji domyślnym serwerem jest pierwszy ...

Teraz, jeśli chcesz mieć domyślny serwer typu catch-all, który, powiedzmy, odpowiada 404 na wszystkie żądania, oto jak to zrobić:

server {
    listen 80 default_server;
    listen 443 ssl default_server;
    server_name _;
    ssl_certificate <path to cert>
    ssl_certificate_key <path to key>
    return 404;
}

Zauważ, że musisz określić certyfikat / klucz (który może być samopodpisany), w przeciwnym razie wszystkie połączenia SSL zakończą się niepowodzeniem, ponieważ nginx spróbuje zaakceptować połączenie przy użyciu tego domyślnego_serwera i nie znajdzie certyfikatu / klucza.

andreycpp
źródło
3
Nie mam pojęcia, dlaczego ta odpowiedź jest tak daleko na liście. To jest ten, który odpowiada na pytanie bez rozpraszania się błyszczącymi rzeczami po drodze.
mmc
Pomogło mi to rozwiązać problem polegający na tym, że próbowałem przekierować z innej niż www na www, że musiałem dołączyć mój certyfikat ssl do tej trasy przekierowania, w przeciwnym razie próbowałem pobrać mój domyślny certyfikat ssl, który był dla innej domeny.
endyourif
1
Wydaje się, że jest to najlepsza odpowiedź dla większości konfiguracji ... nie jestem pewien, kto używa obecnie nginx bez SSL, ale fakt, że jest to jedyny, który obejmuje SSL, jest niezwykle wymowny.
Włączono
Wydaje się, że server_name _;nie jest to nawet potrzebne.
Julien Salinas
26

Istnieje kilka sposobów określenia domyślnego serwera.

Pierwszy sposób - Określ domyślny serwer jako pierwszy na liście, jeśli przechowujesz konfiguracje serwera w jednym pliku konfiguracyjnym, jak pokazał Dayo powyżej.

Drugi sposób (lepszy) Bardziej elastyczny - podaj default_serverparametr listeninstrukcji, na przykład:

server {
    listen  *:80 default_server;
    root /www/project/public/;
}

Więcej informacji tutaj: Nginx doc / Listen

Jest to bardziej przydatne, gdy konfiguracje serwera są przechowywane w osobnych plikach i nie chcesz nazywać tych plików alfabetycznie.

Pavel
źródło
3
To powinna być prawidłowa odpowiedź. Przyjęta odpowiedź jest myląca. Samo dodanie kolejnego serwera do konfiguracji nie rozwiąże problemu, jeśli inny serwer jest skonfigurowany jako serwer domyślny.
Ben
1
@Pavel nie ma powodu, dla którego podana odpowiedź nie może działać z wieloma oddzielnymi plikami vhost. Dzięki temu wiem, że mój domyślny serwer zawsze znajduje się w głównym pliku nginx.conf i nie muszę pamiętać, który z wielu oddzielnych plików vhost to zawiera.
Dayo
Nie zapomnij posłuchać również protokołu 443 dla ssl (zobacz odpowiedź @ AndreyT poniżej).
Constantinos,
8

Mały komentarz do odpowiedzi:

jeśli masz kilka wirtualnych hostów na kilku adresach IP w kilku plikach konfiguracyjnych w sites-available /, to domena „domyślna” dla IP zostanie pobrana z pierwszego pliku w kolejności alfabetycznej.

Jak powiedział Pavel, istnieje argument „default_server” dla dyrektywy „Listen” http://nginx.org/en/docs/http/ngx_http_core_module.html#listen

Oleg Neumyvakin
źródło