Nginx GeoIP Blocking: Cách mình chặn 80% traffic rác từ quốc gia lạ

Security tutorial - IT technology blog
Security tutorial - IT technology blog

Cú điện thoại lúc 2 giờ sáng và những dòng log “đỏ lòm”

2 giờ sáng, điện thoại mình rung liên hồi trên bàn. Hệ thống giám sát “la hét” khi CPU server nhảy vọt lên 95%. Với một con VPS chuyên chạy WordPress và API cho người dùng Việt Nam, đây rõ ràng là điềm chẳng lành. Vừa SSH vào kiểm tra access.log, mình lạnh gáy khi thấy hàng chục nghìn request đổ về mỗi phút. Các dải IP lạ hoắc đang liên tục “giã” vào đường dẫn /wp-login.php/xmlrpc.php.

tail -f /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -nr | head -n 20

Tra nhanh vài IP, mình phát hiện chúng đến từ những nơi mà dự án chưa bao giờ đặt chân tới. Đây là một cuộc tấn công Brute-force quy mô lớn từ botnet quốc tế. Thay vì ngồi chặn từng IP thủ công – việc vốn dĩ không bao giờ xuể – mình quyết định triển khai GeoIP Blocking ngay lập tức. Mục tiêu rất đơn giản: táng thẳng tay toàn bộ lưu lượng từ các quốc gia không nằm trong tệp khách hàng.

Ba phương án chặn IP phổ biến

Trước khi gõ lệnh, mình đã cân nhắc ba cách tiếp cận quen thuộc của anh em kỹ thuật:

1. Chặn bằng Firewall (UFW/IPTables)

Cách này chặn từ tầng mạng nên cực nhẹ cho server. Thế nhưng, quản lý danh sách hàng chục nghìn dải IP theo quốc gia bằng IPTables là một cực hình. Mỗi lần cập nhật database, script chạy dài dằng dặc rất dễ gây treo hệ thống.

2. Dùng Cloudflare GeoIP

Nếu bạn đang dùng Cloudflare làm proxy thì mọi chuyện dễ như ăn kẹo. Bạn chỉ cần vào tab Security, tạo Rule là xong. Nhưng thực tế, không phải dự án nào mình cũng muốn đẩy qua Cloudflare. Có những hệ thống cần tối ưu độ trễ (latency) hoặc yêu cầu bảo mật nội bộ khắt khe.

3. Nginx kết hợp Module GeoIP2

Đây là lựa chọn cân bằng nhất giữa hiệu năng và sự linh hoạt. Nginx sẽ đọc trực tiếp cơ sở dữ liệu nhị phân (.mmdb) của MaxMind để định danh quốc gia chỉ trong vài mili giây. Bạn có thể chặn ở tầng http, server hoặc tùy biến thông báo trả về cho người dùng rất chuyên nghiệp.

Tại sao MaxMind GeoLite2 là đủ?

MaxMind cung cấp bản GeoLite2 miễn phí với độ chính xác khoảng 99% cho cấp quốc gia. Dù bản trả phí chính xác hơn, nhưng để chặn botnet và giảm tải cho server thì bản Lite đã quá dư dùng.

Một mẹo nhỏ cho anh em: Ngoài việc chặn IP, hãy nhớ đổi mật khẩu quản trị sang dạng siêu khó. Mình hay dùng password generator tại toolcraft.app/vi/tools/security/password-generator. Công cụ này chạy 100% trên trình duyệt nên không lo bị lộ mật khẩu qua môi trường mạng.

Các bước triển khai thực tế

Bước 1: Cài đặt Module GeoIP2

Trên Ubuntu 22.04, bạn chỉ cần một dòng lệnh để cài module:

sudo apt update && sudo apt install libnginx-mod-http-geoip2 -y

Cài xong, hãy chạy lệnh này để chắc chắn module đã nằm trong Nginx:

nginx -V 2>&1 | grep --color geoip2

Bước 2: Lấy Database từ MaxMind

Hiện tại, MaxMind yêu cầu bạn đăng ký tài khoản để tải database. Sau khi đăng ký, hãy tạo một “License Key”. Để khỏe cái thân, mình khuyến khích anh em dùng công cụ geoipupdate để tự động cập nhật dữ liệu hàng tuần:

sudo apt install geoipupdate -y

Cấu hình file /etc/GeoIP.conf với thông tin Key của bạn, sau đó gõ lệnh geoipupdate. File database chuẩn sẽ xuất hiện tại /usr/share/GeoIP/GeoLite2-Country.mmdb.

Bước 3: Dạy Nginx cách nhận diện quốc gia

Mở file /etc/nginx/nginx.conf và thêm đoạn sau vào trong khối http { ... }:

http {
    geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
        auto_reload 5m;
        $geoip2_data_country_code default=XX source=$remote_addr country iso_code;
    }

    map $geoip2_data_country_code $allowed_country {
        default yes;
        CN no; # Chặn Trung Quốc
        RU no; # Chặn Nga
        BR no; # Chặn Brazil
    }
}

Biến $allowed_country lúc này đóng vai trò như một cái lọc. Nếu IP từ Nga (RU) hay Trung Quốc (CN) đi vào, nó sẽ lập tức bị gắn nhãn no.

Bước 4: Thiết lập chốt chặn

Bây giờ, hãy áp dụng vào file cấu hình website của bạn:

server {
    listen 80;
    server_name itfromzero.com;

    if ($allowed_country = no) {
        return 403;
    }

    location / {
        # Code web của bạn ở đây
    }
}

Cuối cùng, kiểm tra lại cú pháp và bắt Nginx nhận lệnh mới:

sudo nginx -t && sudo systemctl reload nginx

Thành quả ngọt ngào

Ngay sau khi reload Nginx, lượng request rác trong log giảm từ 10,000 req/phút xuống còn chưa tới 100. CPU server hạ nhiệt từ 95% xuống mức 10% ổn định.

Tuy nhiên, đừng quên ba lưu ý sống còn sau:

  • Đừng chặn Googlebot: Nếu bạn quan tâm đến SEO, hãy luôn cho phép US vì bot của Google chủ yếu xuất phát từ Mỹ.
  • VPN vẫn có thể lọt: GeoIP Blocking không chặn được người dùng dùng VPN đầu ra tại Việt Nam. Nó chỉ là lớp lọc rác công nghiệp từ botnet quốc tế.
  • Lên lịch cập nhật: Dải IP các nước thay đổi thường xuyên. Hãy set cronjob chạy geoipupdate mỗi tuần một lần.

Bảo mật server là cuộc chiến trường kỳ. GeoIP Blocking giống như việc bạn đóng bớt cửa sổ để tránh bụi, nhưng cửa chính vẫn cần khóa xịn. Chúc anh em có những đêm ngon giấc, không còn nỗi lo bị botnet đánh thức!

Share: