Security

Chống tấn công Layer 7 cho VPS bằng Nginx rate limit và Cloudflare

Vấn đề: 1 con bot đánh chết cả server web

Bạn chạy một trang web trên VPS, đang yên đang lành thì server bắt đầu quá tải, CPU lên rất cao, HTTP trả 502 hoặc chậm như rùa. Kiểm tra log thấy vài nghìn request từ một địa chỉ IP riêng biệt liên tục gọi vào API hoặc endpoint login. Đây là tấn công Layer 7 (Application Layer), loại đơn giản nhưng hiệu quả vì nó tận dụng request HTTP hợp lệ, khó phân biệt với traffic thật. Trên một VPS full root, bạn cần ngăn chặn điều này ở 2 cấp độ: Cloudflare (từ xa) và Nginx (trên VPS).

Yêu cầu trước khi bắt đầu

  • Một VPS chạy Ubuntu 24.04 hoặc Debian 12, đã cài Nginx (nếu chưa, chạy apt update && apt install nginx -y).
  • Domain đã trỏ về Cloudflare (chế độ proxy, tức là có Cloudflare bảo vệ).
  • Quyền root hoặc sudo.
  • Kiến thức cơ bản về Nginx config và Cloudflare.

Bước 1, Lấy đúng IP thật từ Cloudflare

Nếu domain của bạn dùng Cloudflare proxy, tất cả request đến Nginx đều có IP của Cloudflare (các IP trong dải 1.1.1.0/24, 104.16.0.0/12...). Để lấy đúng IP của người dùng thật, cần cài module ngx_http_realip_module (có sẵn trong Nginx từ bản 1.20+).

Mở hoặc tạo file /etc/nginx/conf.d/cloudflare_realip.conf:

# Liệt kê tất cả dải Cloudflare (update định kỳ, nên viết script cập nhật)
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 104.16.0.0/12;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2c0f:f248::/32;
set_real_ip_from 2a06:98c0::/29;

# Đọc IP thật từ header CF-Connecting-IP
real_ip_header CF-Connecting-IP;
real_ip_recursive on;

Sau đó kiểm tra và reload Nginx:

nginx -t && systemctl reload nginx

Verify: Tạo 1 file PHP hoặc 1 endpoint trả log $_SERVER['REMOTE_ADDR'], nếu mở từ trình duyệt, IP hiển thị phải là IP của bạn, không phải IP Cloudflare.

Bước 2, Cấu hình Nginx Rate Limiting (limit_req)

Rate limiting ở Nginx dựa trên module ngx_http_limit_req_module. Bạn định nghĩa một vùng nhớ (zone) để đếm số request từ mỗi IP, sau đó áp vào các location. Chúng ta sẽ chặn: tối đa 5 request mỗi giây từ 1 địa chỉ IP. Nếu vượt quá, trả 503 ngay tức thì.

Trong file /etc/nginx/sites-enabled/default hoặc config server block của bạn, thêm vào trước thằng server {}:

limit_req_zone $binary_remote_addr zone=app_limit:10m rate=5r/s;

Giải thích: $binary_remote_addr là IP người dùng (đã fix qua Cloudflare), zone=app_limit:10m tạo vùng nhớ 10MB, rate=5r/s tối đa 5 request mỗi giây.

Sau đó, bên trong location / { ... } hoặc location /api/ { ... }, thêm dòng:

limit_req zone=app_limit burst=10 nodelay;

Ý nghĩa: burst=10 cho phép đột biến lên 10 request trong một thời điểm, nhưng nếu vượt quá, trả 503 ngay (nodelay). Nếu không có nodelay, Nginx sẽ làm chậm các request thừa (rate limit mềm).

Ví dụ đầy đủ location:

location / {
    # ... các config khác
    limit_req zone=app_limit burst=10 nodelay;
    proxy_pass http://localhost:3000;
}

Kiểm tra và reload:

nginx -t && systemctl reload nginx

Verify: Dùng curl mô phỏng tấn công:

for i in {1..20}; do curl -I https://domain.com/ & done; wait
# Bạn sẽ thấy một số request trả 503 Too Many Requests

Bước 3, Giới hạn số kết nối đồng thời từ 1 IP (limit_conn)

Ngoài giới hạn request, tấn công Layer 7 thường mở nhiều kết nối HTTP đồng thời (connection exhaustion). Dùng module ngx_http_limit_conn_module.

Thêm trong http {} block (file /etc/nginx/nginx.conf hoặc /etc/nginx/conf.d/*.conf):

limit_conn_zone $binary_remote_addr zone=addr_conn:10m;

Trong location / { ... } hoặc server { ... }:

limit_conn addr_conn 10;

(Tối đa 10 kết nối đồng thời từ 1 IP). Sau đó reload.

Bước 4, Kết hợp Cloudflare WAF và Challenge tự động

Nginx làm tốt việc chặn rate, nhưng Cloudflare có thể chặn từ xa, giảm tải cho VPS. Vào Cloudflare Dashboard → Security → WAF. Bạn cần bật:

  • Rate Limiting Rules: Tạo rule "chặn > 50 request từ 1 IP trong 10 giây". Action chọn Challenge (CAPTCHA) hoặc Block. Đây là tầng đầu tiên.
  • Bot Fight Mode: Bật (Block all bot traffic, nếu site bạn không cần bot).
  • Custom Rules: Tạo rule kiểm tra User-Agent, path, query string. Ví dụ: nếu request đến /wp-admin không có refer hợp lệ -> Challenge.

Lưu ý: Bài viết mang tính tham khảo, tổng hợp kiến thức chung. Mỗi hệ thống, hạ tầng và nhu cầu có đặc thù riêng, nên kiểm thử trong môi trường an toàn và tham vấn kỹ sư trước khi triển khai thực tế.