Nginx neden herhangi bir alan adına cevap veriyor?


139

Ben nginx kadar var ve bir Ruby / Sinatra uygulaması ile çalışan ve her şey yolunda. Ancak, şimdi aynı sunucudan çalışan ikinci bir uygulama var çalışıyorum ve garip bir şey fark ettim. İlk olarak, benim 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

Sunucu nasıl server_nameayarlandığına dikkat edin FAKE.COM, sunucu o etki alanına isabet eden tüm ana bilgisayarlara diğer etki alanı adları aracılığıyla yanıt verir. Söz konusu sunucunun yalnızca isteklerine yanıt vermesini nasıl sağlayabilirim FAKE.COM?


listen fake.com | something.com:80 Komut, değil filtreler server_name.
Alexei Martchenko

Yanıtlar:


202

Nginx yapılandırmasındaki ilk sunucu bloğu, belirli bir sunucu bloğu olmayan sunucuya çarpan tüm istekler için varsayılan değerdir.

Bu nedenle, yapılandırmanızda, gerçek etki alanınızın REAL.COM olduğu varsayılarak, bir kullanıcı bunu yazdığında sunucunuza çözülecektir ve bu kurulum için sunucu bloğu olmadığından, ilk olarak FAKE.COM için sunucu bloğu sunucu bloğu (yalnızca sizin durumunuzdaki sunucu bloğu), bu isteği işler.

Bu nedenle, uygun Nginx yapılandırmalarının belirli etki alanları için diğerleriyle izlemeden önce varsayılanlar için belirli bir sunucu bloğu vardır.

# Default server
server {
    return 404;
}

server {
    server_name domain_1;
    [...]
}

server {
    server_name domain_2;
    [...]
}

vb

** DÜZENLE **

Bazı kullanıcılar bu örnekle biraz karışık görünüyor ve tek bir conf dosyasıyla sınırlı olduğunu düşünüyorlar.

Yukarıdakilerin OP'nin gerektiği gibi gelişmesi için basit bir örnek olduğunu lütfen unutmayın.

Şahsen bu şekilde ayrı vhost conf dosyaları kullanmak (CentOS / RHEL):

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

/etc/nginx/conf.d/ domain_1.conf, domain_2.conf ... domain_n.conf dosyasını içerecek ve ana nginx.conf dosyasındaki sunucu bloğundan sonra her zaman ilk olacak ve default_server ile geçersiz kılınmadıkça her zaman varsayılan olacak direktif başka yerde.

Diğer sunucular için conf dosyalarının dosya adlarının alfabetik sırası bu durumda önemsiz hale gelir.

Ek olarak, bu düzenleme birden fazla varsayılan tanımlamanın mümkün olması nedeniyle çok fazla esneklik sağlar.

Özel durumumda, yalnızca dahili arabirimde 8080 numaralı bağlantı noktasında Apache dinliyorum ve Apache'ye PHP ve Perl betiklerini proxy veriyorum.

Ancak, Apache'nin standart Port 80'de çalışmadığını tespit ettikleri ve bana "yardım etmeye" çalıştıkları için her ikisi de bağlı çıkış html'sinde ": 8080" ile bağlantı döndüren iki ayrı uygulama çalıştırıyorum.

Bu, dış arabirimden Apache'ye erişilemediğinden ve bağlantıların 80 numaralı bağlantı noktasını işaret etmesinden dolayı bağlantıların geçersiz hale gelmesine neden olur.

Ben bu tür istekleri yeniden yönlendirmek için 8080 bağlantı noktası için varsayılan bir sunucu oluşturarak bunu gidermek.

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;
}

Normal sunucu bloklarındaki hiçbir şey 8080 numaralı bağlantı noktasını dinlemediğinden, yönlendirme varsayılan sunucu bloğu, nginx.conf'daki konumu nedeniyle bu tür istekleri şeffaf bir şekilde işler.

Aslında bu tür sunucu blokları dört var ve bu basitleştirilmiş bir kullanım durumudur.


1
Nginx büyük / küçük harfe duyarlılık gerektirir- "Sunucu" sunucu ve "Dönüş" döndürülmelidir. Umarım bu kodu kopyalarken birkaç sorundan tasarruf eder.
Çapaj

2
statik, bkz. Oleg Neumyvkin'in cevabı - eğer kullanılabilir sitelerde birden fazla yapılandırma dosyası varsa, ilk dosyadaki alfabetik sırayla ilk sunucu varsayılan değerdir. Bunun bir sorun olabileceğinden şüpheleniyorum. Ayrıca, birçok dağıtım, yeniden başlatmadan önce yapılandırmayı sınamak için bir 'nginx -t' çalıştırır - yeniden başlatmayı engelleyen bir hata olabilir.
jwhitlock

2
Bu eksiktir ve kabul edilen cevap olmamalıdır. Bunun çalışması için, default_server öğesini herhangi bir dinleme yönergesinden de kaldırmanız gerekir.
Ben

@ben İlk olarak OP'nin problem örneğinde "default_server" yoktu ve cevap bu sorunun özelliklerine göre uyarlandı. İkincisi, ilk tanımlı sunucuyu varsayılan yapmak benim üstümde olmak için yönergeleri uygularken neden herkes default_server'ı ayrı bir sunucu konumunda tanımlasın? Her durumda, bir default_server özel olarak tanımlanmışsa, bu Q / A kümesi, karşılaştıkları sorunları çözmek için bakılması gereken şey değildir.
Dayo

1
@Dayo OP tarafından gönderilen belirli yapılandırmaya hitap ettiğinizden emin olabilirsiniz. Ancak sorulan soruların tam bir cevabı için, default_server'dan bahsetmenin gerekli olduğunu düşünüyorum. Cevabınızı okumak ve default_server'ın buna nasıl müdahale edeceğini anlamak mümkün değildir. Bunun nedeni, dosyada default_server ile tanımlanmış bazı dağıtımların, kullanıcı tarafından açıkça görülmeyebilecek olması nedeniyle daha da olasıdır.
Ben

62

Tümünü yakalama için varsayılan bir sunucunuz olmalıdır , yalnızca bağlantıyı kapatan ve hiçbir şey döndürmeyen nginx'e özgü HTTP yanıtı 404döndürerek hiç yanıt vermemek için geri dönebilir veya daha iyi olabilirsiniz (bazı bant genişliğini kaydeder)444

server {
    listen       80  default_server;
    server_name  _; # some invalid name that won't match anything
    return       444;
}

Benim için nginx 1.8.0 için çalıştı. server_name _;Ben nginx için önceki sürümlerinde yoktu, ama işe yaradı. Şimdi yeni nginx sürümleri için ihtiyacınız var gibi görünüyor server_name _;. Teşekkürler
daniel

Çözüldü. Noktalı virgül unuttum; _;
user1201917

2
@iTech: Nedense tüm talepler için 444 döndürüyor. Herhangi bir ipucu var mı?
Divick

Büyük ipucu hakkında ve 444bir hata kodu döndürmekten çok daha temiz bir çözüm imho.
qqilihq

1
Bir sertifika / anahtar belirtmek önemlidir, aksi takdirde aşağıdaki cevabında @AndreyT tarafından belirtildiği gibi tüm SSL bağlantıları eşleşir ve başarısız olur.
Mark Fletcher

35

Diğer yanıtlardan herhangi biriyle sorunumu çözemedim. Ana bilgisayar eşleşip eşleşmediğini kontrol edip kontrol etmediyse sorunu çözemedim. (Web sunucularımın içeriğine işaret eden rastgele bir web sitem vardı. Arama sıralamasını kaçırmayı düşünüyorum)

server {
    listen 443;
    server_name example.com;

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

    ...
}


1
Örneğin, eşdeğer bir yönergesi olmayan bir değişkeni test etmeniz gerekiyorsa, bir if kullanmaktan kaçınamayacağınız durumlar vardır.
Edward

4
@Esolitos Kelimenin tam anlamıyla üçüncü satır, bu kullanım durumunun iyi olduğunu söylüyor. Dikkatli olmanın gerekliliğini anlıyorum, ama makul kullanım durumlarında parmakları sallamayalım.
mpowered

Benim düşünceme göre, en kolay ve en özlü çözüm, sadece 3 satır kod gerektirdiğinden, herhangi bir vhost dosyasına memnuniyetle yapıştırabilir, daha sonra sadece karşılaştırılan $ host'u değiştirebilirsiniz.
Akito

28

Sorunuzu cevaplamak için - nginx, eşleşme yoksa ilk sunucuyu seçer. Belgelere bakın :

Değeri herhangi bir sunucu adıyla eşleşmiyorsa veya istek bu başlık alanını hiç içermiyorsa, nginx, isteği bu bağlantı noktasının varsayılan sunucusuna yönlendirir. Yukarıdaki yapılandırmada, varsayılan sunucu ilk sunucudur ...

Şimdi, tüm isteklere 404 ile yanıt veren varsayılan bir tümünü yakalama sunucunuz olmasını istiyorsanız, bunu nasıl yapacağınız aşağıda açıklanmıştır:

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;
}

Sertifika / anahtar (kendinden imzalı olabilen) belirtmeniz gerektiğini unutmayın, aksi takdirde nginx bu varsayılan_server kullanarak bağlantıyı kabul etmeye çalışacağından ve cert / key bulamayacağından tüm SSL bağlantıları başarısız olur.


3
Bu cevabın neden bu kadar listede olduğunu bilmiyorum. Bu, yol boyunca parlak şeylerden rahatsız olmadan soruyu cevaplayan kişidir.
mmc

Bu, www olmayan bir www'den yönlendirme deniyordu bir sorun çözmek bana yardımcı oldu ben bu yönlendirme yolunda benim ssl sertifikası eklemek zorunda kaldı aksi takdirde farklı bir etki alanı için bir varsayılan ssl cert kapmak çalışıyordu.
endyourif

1
Bu, çoğu yapılandırma için en iyi yanıt gibi görünüyor ... Bu günlerde SSL olmadan nginx'i kimin kullandığından emin değilim, ancak bunun SSL'yi kapsayan tek kişi olması son derece anlatıyor.
mpowered

Öyle görünmüyor server_name _;bile.
Julien Salinas

26

Varsayılan sunucuyu belirtmenin birkaç yolu vardır.

İlk yol - Sunucu yapılandırmalarınızı yukarıda gösterilen Dayo gibi bir yapılandırma dosyasında tutarsanız, önce listede varsayılan sunucuyu belirtin.

İkinci yol (daha iyi) Daha esnek - talimat için default_serverparametre sağlayın listen, örneğin:

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

Daha fazla bilgi için buraya tıklayın: Nginx doc / Listen

Bu şekilde sunucu yapılandırmalarını ayrı dosyalarda tuttuğunuzda ve bu dosyaları alfabetik olarak adlandırmak istemediğinizde daha kullanışlı olur.


3
Bu doğru cevap olmalı. Kabul edilen cevap yanıltıcıdır. Başka bir sunucu varsayılan sunucu olarak yapılandırılmışsa, yapılandırmaya başka bir sunucu eklemek sorunu çözmez.
Ben

1
@Pavel, verilen cevabın birden fazla ayrı vhost dosyasıyla çalışmamasının bir nedeni yoktur. Ayrıca, bununla birlikte, varsayılan sunucumun her zaman ana nginx.conf dosyasında olduğunu ve birçok ayrı vhost dosyamdan hangisinin bunu içerdiğini hatırlamak zorunda olmadığını biliyorum.
Dayo

SSL için 443'ü de dinlemeyi unutmayın (aşağıdaki @ AndreyT'nin cevabına bakınız).
Constantinos

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.