วิธี จำกัด อัตราใน nginx แต่รวมถึง / ไม่รวมที่อยู่ IP ที่แน่นอน


27

ฉันสามารถใช้limit_reqเพื่อ จำกัด อัตราการร้องขอทั้งหมดไปยังเซิร์ฟเวอร์ของฉัน

อย่างไรก็ตามฉันต้องการลบข้อ จำกัด อัตราสำหรับที่อยู่ IP บางรายการ (เช่นรายการที่อนุญาต) และใช้การ จำกัด อัตราที่แตกต่างกันสำหรับผู้อื่น (เช่น IP ที่แน่นอนที่ฉันต้องการต่ำถึง 1r / s)

ฉันลองใช้เงื่อนไข (เช่นif ( $remote_addr = "1.2.3.4" ) {}) แต่ดูเหมือนว่าจะใช้ได้เฉพาะกับกฎการเขียนซ้ำไม่ใช่กฎการ จำกัด อัตรา

คำตอบ:


33

เป็นการดีกว่าที่จะหลีกเลี่ยงการใช้คำสั่ง "ถ้า" เมื่อคีย์ใน limit_req_zone (และ limit_conn_zone) ว่างเปล่าจะไม่มีการใช้ขีด จำกัด คุณสามารถใช้สิ่งนี้ร่วมกับแผนที่และโมดูลทางภูมิศาสตร์เพื่อสร้างรายการที่อนุญาตของ IP ที่ไม่มีการ จำกัด การใช้เค้น

ตัวอย่างนี้แสดงวิธีกำหนดค่าขีด จำกัด สำหรับการร้องขอพร้อมกันและอัตราการร้องขอจาก 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;

คำสั่งของโซนจะต้องอยู่ที่ระดับ http อย่างไรก็ตามสามารถวางคำสั่งอื่น ๆ ลงไปได้เช่นที่เซิร์ฟเวอร์หรือระดับตำแหน่งเพื่อ จำกัด ขอบเขตหรือปรับแต่งข้อ จำกัด เพิ่มเติม

สำหรับข้อมูลละเอียดเพิ่มเติมโปรดอ้างถึงเอกสาร Nginx ngx_http_limit_req_moduleและngx_http_limit_conn_module


อะไรคือความแตกต่างระหว่าง 2 โมดูลนี้?
mente

1
ตามความเห็นข้อ จำกัด แรกการเชื่อมต่อพร้อมกันที่สอง จำกัด อัตราการเชื่อมต่อ
ผู้ใช้ shonky linux

คุณช่วยอธิบายได้ไหมว่าทำไมคุณถึงทำแผนที่ในสองขั้นตอนgeoตามด้วยmapแทนที่จะใช้geoเพื่อตั้งค่า$limitโดยตรง
Marcus Downing

2
ดูเหมือนว่าgeoไม่สามารถแมปกับตัวแปรได้ดังนั้นหากคุณระบุ$binary_remote_addrเป็นค่าการจับคู่สิ่งนี้จะแปลเป็นสตริงตัวอักษร"$binary_remote_addr"ไม่ใช่ค่าของตัวแปร
ColinM

1
ฉันต้องการเพิ่มว่าหาก IP ที่เป็นปัญหาอยู่ในโซนแล้วคุณต้องรีสตาร์ท nginx; โหลดไม่เพียงพอ
Halfgaar

5

คุณสามารถใช้สถานที่ที่ตั้งชื่อไว้อย่างปลอดภัยเช่น "@location" ในบล็อก if ()

ดู: http://wiki.nginx.org/IfIsEvil

สิ่งนี้ควรใช้งานได้:

http {

   limit_req_zone $binary_remote_addr zone=delay:10m rate=1r/m;

   server {
      ...

      error_page 410 = @slowdown;

      if( $remote_addr != "1.2.3.4" ) {
         return 410;
      }

      location @slowdown {
         limit_req zone=delay burst 5;
         ...
      }

      location / {
         ...
      }
   }

กรอก "location @slowdown {}" ด้วยข้อมูลเดียวกับ "location / {} เช่น proxy_pass หากคุณใช้ nginx เป็น reverse proxy


ฉันไม่แน่ใจว่าฉันเข้าใจส่วน 410 หรือไม่ ลูกค้าเห็นรหัสสถานะ http 410 หรือไม่
svrist

1
ว้าวนี่ใช้งานได้จริง! error_pageเคล็ดลับที่ดีมาก+1! @svrist โปรดดูserverfault.com/a/870170/110020สำหรับคำอธิบายที่สมบูรณ์เกี่ยวกับวิธีการทำงานแบบนี้และทำไม
cnst
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.