ตั้ง Rate Limiting ด้วย Nginx บน VPS

ตั้ง Rate Limiting ด้วย Nginx บน VPS

มิถุนายน 2026 · อ่าน 7 นาที

Rate limiting คือการจำกัดจำนวน request ที่ IP หนึ่งทำได้ต่อวินาที ช่วยป้องกัน brute force login, abuse API endpoint, และลดผลกระทบของ DDoS เบาๆ Nginx มี rate limiting built-in ที่ตั้งง่ายและมีประสิทธิภาพสูงโดยไม่ต้องใช้ plugin เพิ่ม

หลักการ: limit_req_zone

# ตั้งใน nginx.conf หรือ /etc/nginx/conf.d/
# ส่วน http {} block:

# สร้าง zone: ชื่อ "one" ขนาด 10MB รับ 10 request/วินาที ต่อ IP
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;

# Zone สำหรับ login endpoint (เข้มงวดกว่า)
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;

ใช้ Rate Limit ใน Server Block

server {
    listen 443 ssl;
    server_name yourdomain.com;

    # ทั้ง site: 10 req/s, burst 20
    limit_req zone=one burst=20 nodelay;

    # Login page: เข้มงวดกว่า
    location /wp-login.php {
        limit_req zone=login burst=5 nodelay;
        # ถ้าเกิน → 429 Too Many Requests
        limit_req_status 429;
        proxy_pass http://localhost:8080;
    }

    # API: ไม่มี burst เลย (strict)
    location /api/ {
        limit_req zone=one burst=5;
        proxy_pass http://localhost:3000;
    }
}

Rate Limit Connection (limit_conn)

# http {} block:
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;

# server {} block:
# จำกัด IP เดียวเปิดได้สูงสุด 20 connections พร้อมกัน
limit_conn conn_limit 20;

Whitelist IP สำหรับ Admin

# ใช้ geo module ยกเว้น IP บางตัว
geo $limit {
    default         1;
    127.0.0.1       0;
    203.0.113.0/24  0;  # office IP range
}

map $limit $limit_key {
    0 "";
    1 $binary_remote_addr;
}

limit_req_zone $limit_key zone=protected:10m rate=10r/s;

# ใช้ใน server block:
location /admin/ {
    limit_req zone=protected burst=20;
}

Log Request ที่ถูก Reject

# ใน nginx.conf:
limit_req_log_level warn;   # log level (warn/error/crit/alert)

# ดู log:
sudo tail -f /var/log/nginx/error.log | grep limiting
Tip: ทดสอบ rate limit ด้วย ab -n 100 -c 20 https://yourdomain.com/api/ (Apache Benchmark) เพื่อดูว่า response code 429 ปรากฏขึ้นเมื่อใด ปรับ burst ให้เหมาะกับ traffic จริง

เลือกค่า rate ที่เหมาะกับงานจริง

ตั้งต่ำไปลูกค้าจริงโดน 503, ตั้งสูงไปกัน abuse ไม่อยู่ — ใช้ตารางนี้เป็นจุดเริ่ม แล้วปรับจาก log จริง:

ประเภท endpointrate แนะนำburst
หน้าเว็บทั่วไป30r/s50
API (อ่าน)10r/s20
หน้า login / สมัคร1r/s5 nodelay
ส่ง email / OTP1r/m3
Tip: ใช้ burst=N nodelay บนหน้า login เพื่ออนุญาต spike สั้นๆ (เช่นกรอกผิดแล้วลองใหม่) แต่ยังบล็อก brute-force ที่ยิงต่อเนื่อง — ต่างจาก delay ที่จะหน่วง request แทนที่จะ reject ทันที

ตรวจสอบว่า Rate Limiting ทำงานถูกต้อง

# ตรวจ config ไม่ error
sudo nginx -t

# Reload nginx
sudo systemctl reload nginx

# ทดสอบ burst ด้วย curl loop
for i in {1..20}; do curl -s -o /dev/null -w "%{http_code}\n" https://yourdomain.com/api/test; done

# ดู 429 ใน log
sudo grep "limiting requests" /var/log/nginx/error.log | tail -20
Tip: ตั้ง Custom Error Page สำหรับ 429 เพื่อ UX ที่ดีกว่า Nginx default: error_page 429 /rate-limit.html;

แก้ปัญหาที่พบบ่อย

Legitimate users โดน block (False positive)

burst ต่ำเกินไป หรือ rate ต่ำเกินไป เพิ่ม burst ก่อน หรือตรวจว่า IP อยู่หลัง proxy/CDN:

# ถ้าผ่าน Cloudflare ต้องใช้ CF-Connecting-IP แทน remote_addr
set_real_ip_from 103.21.244.0/22;  # Cloudflare IP range
real_ip_header CF-Connecting-IP;
limit_req_zone $realip_remote_addr zone=one:10m rate=10r/s;

Error: "zone size is too small"

10m zone รองรับได้ประมาณ 160,000 IP ถ้ามี traffic มากกว่านั้น เพิ่ม zone size:

limit_req_zone $binary_remote_addr zone=one:50m rate=10r/s;

Rate Limit ไม่ทำงานกับ upstream ที่ใช้ proxy_pass

limit_req ต้องอยู่ก่อน proxy_pass ใน location block หรืออยู่ใน server block level:

location /api/ {
    limit_req zone=one burst=10 nodelay;
    limit_req_status 429;
    proxy_pass http://backend;
}

คำถามที่พบบ่อย

rate limiting กับ fail2ban ต่างกันอย่างไร?

Nginx rate limiting ทำงาน real-time ทันทีที่ request เกิน limit จะ reject fail2ban วิเคราะห์ log หลังเกิดเหตุและ ban IP ด้วย iptables ทั้งสองทำงานร่วมกันได้ดี: rate limit รับภาระก่อน fail2ban จัดการ IP ที่พยายามซ้ำหลังถูก block

nodelay มีผลอย่างไร?

โดย default Nginx จะ delay request ที่เกิน rate แต่ยังอยู่ใน burst ให้ผ่านช้าๆ nodelay บังคับให้ process request ใน burst ทันทีโดยไม่ delay แต่ยังนับ counter อยู่ เหมาะสำหรับ API ที่ต้องการ low latency

Rate limit ต่อ user แทน IP ได้ไหม?

ได้ ใช้ $http_authorization หรือ cookie value แทน IP: limit_req_zone $http_x_api_key zone=api:10m rate=100r/s เหมาะสำหรับ API ที่ต้องการ limit ต่อ API key