Mengapa nginx merespons nama domain apa pun?

142

Saya telah menjalankan nginx dan menjalankan aplikasi Ruby / Sinatra dan semuanya baik-baik saja. Namun, sekarang saya mencoba menjalankan aplikasi kedua dari server yang sama dan saya melihat sesuatu yang aneh. Pertama, inilah nginx.conf saya:

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

Perhatikan bagaimana server_namediatur agar FAKE.COMserver merespons semua host yang mengunjungi server itu melalui nama domain lain. Bagaimana saya bisa membuat server tertentu hanya menanggapi permintaan FAKE.COM?

Martin
sumber
yang listen fake.com | something.com:80 perintah filter, tidak server_name.
Alexei Martchenko

Jawaban:

206

Blok server pertama dalam konfigurasi nginx adalah default untuk semua permintaan yang masuk ke server yang tidak memiliki blok server spesifik.

Jadi di konfigurasi Anda, dengan asumsi domain asli Anda adalah REAL.COM, ketika pengguna mengetik itu, itu akan menyelesaikan ke server Anda, dan karena tidak ada blok server untuk pengaturan ini, blok server untuk FAKE.COM, menjadi yang pertama blok server (hanya blok server dalam kasus Anda), akan memproses permintaan itu.

Inilah sebabnya mengapa konfigurasi Nginx yang tepat memiliki blok server khusus untuk default sebelum mengikuti dengan yang lain untuk domain tertentu.

# Default server
server {
    return 404;
}

server {
    server_name domain_1;
    [...]
}

server {
    server_name domain_2;
    [...]
}

dll

** EDIT **

Tampaknya beberapa pengguna agak bingung dengan contoh ini dan menganggapnya terbatas pada satu file conf, dll.

Harap dicatat bahwa di atas adalah contoh sederhana untuk mengembangkan OP sesuai kebutuhan.

Saya pribadi menggunakan file conf vhost terpisah dengan ini (CentOS / RHEL):

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

/etc/nginx/conf.d/ akan berisi domain_1.conf, domain_2.conf ... domain_n.conf yang akan dimasukkan setelah blok server di file nginx.conf utama yang akan selalu menjadi yang pertama dan akan selalu menjadi default kecuali jika diganti dengan default_server direktif di tempat lain.

Urutan abjad dari nama file dari file conf untuk server lain menjadi tidak relevan dalam kasus ini.

Selain itu, pengaturan ini memberikan banyak fleksibilitas karena dimungkinkan untuk menentukan beberapa default.

Dalam kasus khusus saya, saya meminta Apache mendengarkan pada Port 8080 hanya pada antarmuka internal dan saya mem-proxy PHP dan skrip Perl ke Apache.

Namun, saya menjalankan dua aplikasi terpisah yang keduanya mengembalikan tautan dengan ": 8080" di output html yang terpasang saat mereka mendeteksi bahwa Apache tidak berjalan pada Port standar 80 dan mencoba untuk "membantu" saya.

Ini menyebabkan masalah di mana tautan menjadi tidak valid karena Apache tidak dapat dijangkau dari antarmuka eksternal dan tautan harus mengarah ke Port 80.

Saya menyelesaikan ini dengan membuat server default untuk Port 8080 untuk mengalihkan permintaan tersebut.

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

Karena tidak ada blok server biasa yang mendengarkan di Port 8080, blok server default redirect secara transparan menangani permintaan tersebut berdasarkan posisinya di nginx.conf.

Saya sebenarnya memiliki empat blok server seperti itu dan ini adalah kasus penggunaan yang disederhanakan.

Dayo
sumber
1
Nginx membutuhkan sensitivitas huruf besar- "Server" harus menjadi server dan "Kembali" harus dikembalikan. Semoga ini menghemat beberapa masalah saat menyalin kode ini.
Capaj
2
statis, lihat jawaban Oleg Neumyvkin - jika Anda memiliki banyak file konfigurasi di situs-tersedia, maka server pertama di file pertama berdasarkan urutan abjad adalah default Anda. Saya curiga ini mungkin menjadi masalah. Selain itu, banyak distribusi yang menjalankan 'nginx -t' untuk menguji konfigurasi sebelum memulai ulang - Anda mungkin mengalami kesalahan yang mencegah memulai ulang.
jwhitlock
2
Ini tidak lengkap dan seharusnya bukan jawaban yang diterima. Agar ini bekerja, Anda juga harus menghapus default_server dari arahan mendengarkan apa pun.
Ben
@ben Pertama, OP tidak memiliki "default_server" dalam contoh soal dan jawabannya disesuaikan dengan spesifikasi pertanyaan itu. Kedua, mengapa ada orang yang mendefinisikan default_server di lokasi server terpisah saat mengikuti instruksi untuk membuat server yang ditentukan pertama sebagai default berada di luar jangkauan saya. Bagaimanapun, jika default_server telah ditentukan secara spesifik, maka Q / A set ini bukanlah yang harus dilihat untuk menyelesaikan masalah apa pun yang mungkin mereka hadapi.
Dayo
1
@Dayo Anda benar bahwa Anda menangani konfigurasi khusus yang diposting oleh OP. Tetapi untuk jawaban lengkap atas pertanyaan yang diajukan, saya rasa perlu untuk menyebutkan default_server. Sangat mungkin untuk membaca jawaban Anda dan tidak menyadari bagaimana default_server akan mengganggunya. Ini bahkan lebih mungkin karena beberapa distro yang dikirimkan dengan default_server yang ditentukan dalam file yang mungkin tidak jelas bagi pengguna.
Ben
64

Anda harus memiliki server default untuk menangkap semua , Anda dapat kembali 404atau lebih baik untuk tidak merespons sama sekali (akan menghemat beberapa bandwidth) dengan mengembalikan 444yang merupakan respons HTTP khusus nginx yang hanya menutup koneksi dan tidak mengembalikan apa-apa

server {
    listen       80  default_server;
    server_name  _; # some invalid name that won't match anything
    return       444;
}
iTech
sumber
Bekerja untuk saya untuk nginx 1.8.0. The server_name _;saya tidak ada di versi sebelumnya untuk nginx, tapi itu bekerja. Sekarang untuk versi nginx yang lebih baru sepertinya Anda membutuhkan file server_name _;. Terima kasih
daniel
Terpecahkan. Saya lupa titik koma; _;
pengguna1201917
2
@iTech: Untuk beberapa alasan, ini mengembalikan 444 untuk semua permintaan. Ada petunjuk?
Divick
Tip bagus tentang 444, dan saya akan menemukan solusi yang jauh lebih bersih daripada mengembalikan kode kesalahan.
qqilihq
1
Penting untuk menentukan sertifikat / kunci, jika tidak semua koneksi SSL akan cocok dan gagal, seperti yang ditunjukkan oleh @AndreyT dalam jawabannya di bawah ini.
Mark Fletcher
35

Saya tidak dapat menyelesaikan masalah saya dengan salah satu jawaban lainnya. Saya menyelesaikan masalah dengan memeriksa untuk melihat apakah tuan rumah cocok dan mengembalikan 403 jika tidak. (Saya memiliki beberapa situs web acak yang menunjuk ke konten server web saya. Saya menduga untuk membajak peringkat pencarian)

server {
    listen 443;
    server_name example.com;

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

    ...
}
Matt Carrier
sumber
1
Jika praktiknya buruk: nginx.com/resources/wiki/start/topics/depth/ifisevil
Esolitos
1
Ada kasus di mana Anda tidak dapat menghindari penggunaan if, misalnya, jika Anda perlu menguji variabel yang tidak memiliki direktif yang setara.
Edward
4
@Esolitos Secara harfiah baris ketiga dari artikel itu mengatakan bahwa kasus penggunaan ini baik-baik saja. Saya memahami perlunya berhati-hati, tetapi jangan mengibas-ngibaskan jari pada kasus penggunaan yang wajar.
diberdayakan
Menurut pendapat saya, solusi termudah dan paling ringkas, karena hanya membutuhkan 3 baris kode, Anda dapat dengan senang hati menempelkannya ke file vhost apa pun, hanya dengan mengubah $ host yang dibandingkan, sesudahnya.
Akito
31

Untuk menjawab pertanyaan Anda - nginx memilih server pertama jika tidak ada yang cocok. Lihat dokumentasi :

Jika nilainya tidak cocok dengan nama server mana pun, atau permintaan tidak berisi bidang header ini sama sekali, maka nginx akan mengarahkan permintaan ke server default untuk port ini. Pada konfigurasi di atas, server default adalah yang pertama ...

Sekarang, jika Anda ingin memiliki server penampung semua default yang, katakanlah, merespons dengan 404 ke semua permintaan, berikut cara melakukannya:

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

Perhatikan bahwa Anda perlu menentukan sertifikat / kunci (yang dapat ditandatangani sendiri), jika tidak, semua koneksi SSL akan gagal karena nginx akan mencoba menerima koneksi menggunakan default_server ini dan tidak akan menemukan sertifikat / kunci.

andreycpp
sumber
3
Saya tidak tahu mengapa jawaban ini sangat jauh dari daftar. Ini adalah pertanyaan yang menjawab pertanyaan tanpa terganggu oleh hal-hal yang mengilap di sepanjang jalan.
mmc
Ini membantu saya memecahkan masalah di mana saya mencoba pengalihan dari non-www ke www sehingga saya harus menyertakan sertifikat ssl saya dalam rute pengalihan ini jika tidak, saya mencoba mengambil sertifikat ssl default saya yang merupakan untuk domain yang berbeda.
endyourif
1
Ini sepertinya jawaban terbaik untuk sebagian besar konfigurasi ... tidak yakin siapa yang menggunakan nginx tanpa SSL akhir-akhir ini, tetapi fakta bahwa ini adalah satu-satunya yang mencakup SSL sangat jelas.
diberdayakan
Tampaknya itu server_name _;bahkan tidak diperlukan.
Julien Salinas
26

Ada beberapa cara untuk menentukan server default.

Cara pertama - Tentukan server default terlebih dahulu dalam daftar, jika Anda menyimpan konfigurasi server Anda dalam satu file konfigurasi, seperti yang ditunjukkan Dayo di atas.

Cara kedua (lebih baik) Lebih fleksibel - berikan default_serverparameter untuk listeninstruksi, misalnya:

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

Informasi lebih lanjut di sini: Nginx doc / Listen

Cara ini lebih berguna saat Anda menyimpan konfigurasi server dalam file terpisah dan tidak ingin menamai file tersebut menurut abjad.

Pavel
sumber
3
Ini harus menjadi jawaban yang benar. Jawaban yang diterima menyesatkan. Cukup menambahkan server lain ke konfigurasi tidak akan menyelesaikan masalah jika server lain dikonfigurasi menjadi server default.
Ben
1
@Pavel Tidak ada alasan mengapa jawaban yang diberikan tidak dapat berfungsi dengan beberapa file vhost terpisah. Juga, dengan ini, saya tahu bahwa server default saya selalu ada di file nginx.conf utama dan tidak perlu mengingat yang mana dari banyak file vhost terpisah saya yang berisi ini.
Dayo
Jangan lupa untuk mendengarkan 443 juga untuk ssl (lihat respon @ AndreyT di bawah).
Constantinos
8

Sedikit komentar untuk menjawab:

jika Anda memiliki beberapa host virtual pada beberapa IP dalam beberapa file konfigurasi di sites-available /, maka domain "default" untuk IP akan diambil dari file pertama berdasarkan urutan abjad.

Dan seperti yang dikatakan Pavel, ada argumen "default_server" untuk perintah "dengarkan" http://nginx.org/en/docs/http/ngx_http_core_module.html#listen

Oleg Neumyvakin
sumber