Bagaimana cara menilai-batas dalam nginx, tetapi termasuk / tidak termasuk alamat IP tertentu?
27
Saya dapat menggunakan limit_requntuk menilai-membatasi semua permintaan ke server saya.
Namun saya ingin menghapus batasan laju untuk alamat IP tertentu (mis. Daftar putih) dan menggunakan batasan tarif lain untuk yang lain (mis. IP tertentu saya ingin serendah 1r / s).
Saya mencoba menggunakan conditional (misalnya if ( $remote_addr = "1.2.3.4" ) {}) tetapi tampaknya hanya berfungsi dengan aturan penulisan ulang, bukan untuk aturan batas-tingkat.
Sebaiknya hindari penggunaan arahan "jika". Ketika kunci di limit_req_zone (dan limit_conn_zone) kosong, batas tidak diterapkan. Anda dapat menggunakan ini bersama dengan modul peta dan geo untuk membuat daftar putih IPs di mana batas throttle tidak diterapkan.
Contoh ini menunjukkan cara mengonfigurasi batas untuk permintaan bersamaan dan tingkat permintaan dari satu IP.
http {
geo $whitelist {
default 0;
# CIDR in the list below are not limited
1.2.3.0/24 1;
9.10.11.12/32 1;
127.0.0.1/32 1;
}
map $whitelist $limit {
0 $binary_remote_addr;
1 "";
}
# The directives below limit concurrent connections from a
# non-whitelisted IP address to five
limit_conn_zone $limit zone=connlimit:10m;
limit_conn connlimit 5;
limit_conn_log_level warn; # logging level when threshold exceeded
limit_conn_status 503; # the error code to return
# The code below limits the number requests from a non-whitelisted IP
# to one every two seconds with up to 3 requests per IP delayed
# until the average time between responses reaches the threshold.
# Further requests over and above this limit will result
# in an immediate 503 error.
limit_req_zone $limit zone=one:10m rate=30r/m;
limit_req zone=one burst=3;
limit_req_log_level warn;
limit_req_status 503;
Arahan zona harus ditempatkan di tingkat http, namun arahan lain dapat ditempatkan lebih jauh ke bawah, misalnya di server atau tingkat lokasi untuk membatasi ruang lingkup mereka atau lebih lanjut menyesuaikan batas.
Sesuai komentar, yang pertama membatasi koneksi konkuren, yang kedua membatasi laju koneksi
pengguna linux shonky
Bisakah Anda menjelaskan mengapa Anda melakukan pemetaan dalam dua tahap, dengan geodiikuti oleh map, daripada hanya digunakan geountuk mengatur $limitsecara langsung?
Marcus Downing
2
Tampaknya geotidak dapat memetakan ke variabel jadi jika Anda menetapkan $binary_remote_addrsebagai nilai pemetaan, ini akan diterjemahkan ke string literal "$binary_remote_addr", bukan nilai variabel.
ColinM
1
Saya ingin menambahkan bahwa jika IP yang dimaksud sudah ada di zona, Anda harus me - restart nginx; memuat ulang tidak cukup.
Halfgaar
5
Anda dapat menggunakan lokasi yang ditentukan dengan aman, seperti "@lokasi" di blok if ().
Saya tidak yakin saya mengerti bagian 410? Apakah klien benar-benar melihat kode status http 410?
svrist
1
Wow, ini benar-benar berfungsi! error_pageTrik yang sangat bagus , +1! @svrist, lihat serverfault.com/a/870170/110020 untuk penjelasan lengkap tentang bagaimana sesuatu seperti ini akan bekerja, dan mengapa.
geo
diikuti olehmap
, daripada hanya digunakangeo
untuk mengatur$limit
secara langsung?geo
tidak dapat memetakan ke variabel jadi jika Anda menetapkan$binary_remote_addr
sebagai nilai pemetaan, ini akan diterjemahkan ke string literal"$binary_remote_addr"
, bukan nilai variabel.Anda dapat menggunakan lokasi yang ditentukan dengan aman, seperti "@lokasi" di blok if ().
Lihat: http://wiki.nginx.org/IfIsEvil
Sesuatu seperti ini seharusnya bekerja:
Isi "location @slowdown {}" dengan informasi yang sama dengan "location / {}, seperti proxy_pass jika Anda menggunakan nginx sebagai proxy terbalik.
sumber
error_page
Trik yang sangat bagus , +1! @svrist, lihat serverfault.com/a/870170/110020 untuk penjelasan lengkap tentang bagaimana sesuatu seperti ini akan bekerja, dan mengapa.