Security

Cấu hình fail2ban bảo vệ nhiều dịch vụ trên VPS

SSH vào VPS của bạn, vài phút sau kiểm tra journalctl -u sshd đã thấy cả tá dòng "Failed password". Ai đó đang rà quét cổng 22, thử từng tài khoản root, admin, user. Nếu bạn chỉ dựa vào password mạnh, bạn đã chậm một bước. fail2ban là lớp phòng thủ đầu tiên: đọc log, phát hiện các lần thử sai, và chặn IP đó bằng firewall. Bài này tôi sẽ hướng dẫn bạn cấu hình fail2ban để bảo vệ ba mục tiêu chính trên VPS Linux: SSH, Nginx (web server) và WordPress (wp-login). Mục tiêu cuối cùng là giảm thiểu tối đa lượng brute-force, giữ cho VPS nhẹ và an toàn hơn.

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

  • Một VPS chạy Ubuntu 24.04 LTS hoặc Debian 12, đã kết nối qua SSH với user sudo (không dùng root).
  • Nginx đã được cài đặt và hoạt động, có thể đang chạy WordPress hoặc bất kỳ trang web nào.
  • Quyền sudo hoặc root.
  • Đã hiểu cơ bản về log file (/var/log/) và cấu hình firewall.

Vì sao dùng fail2ban thay vì chỉ dựa vào firewall tĩnh?

Firewall tĩnh (như ufw, firewalld, iptables) chỉ đóng/mở cổng. Nếu bạn mở cổng 22, nó mở cho tất cả mọi người, kể cả kẻ tấn công. fail2ban hoạt động động: nó theo dõi log real-time, đếm số lần thất bại. Khi vượt ngưỡng, nó tự động thêm rule firewall chặn IP đó trong một khoảng thời gian. Sau khi hết giờ, rule tự động được gỡ. Đây là giải pháp thông minh, giảm tải cho hệ thống và bảo vệ ngay cả các dịch vụ không có cơ chế tự chặn như WordPress (nếu bạn không dùng plugin brute-force).

Bước 1 - Cài đặt fail2ban và cấu hình cơ bản

Đầu tiên, cài đặt gói fail2ban từ kho lưu trữ Ubuntu/Debian. Phiên bản trong kho 24.04/12 là fail2ban 0.11.x, đã hỗ trợ systemd journal ở mức cơ bản.

sudo apt update
sudo apt install fail2ban -y

Sau khi cài, không bật ngay. Tôi luôn tạo file cấu hình riêng /etc/fail2ban/jail.local (thay vì sửa file jail.conf gốc, vì file gốc sẽ bị ghi đè khi nâng cấp gói).

sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

Mở file jail.local bằng trình soạn thảo (tôi dùng nano cho gọn):

sudo nano /etc/fail2ban/jail.local

Kiểm tra và sửa các tham số mặc định ở phần [DEFAULT]:

[DEFAULT]
ignoreip = 127.0.0.1/8 ::1
bantime = 3600
findtime = 600
maxretry = 3
banaction = nftables-multiport
backend = systemd
  • ignoreip: Địa chỉ IP hiếm khi bị ban. Luôn giữ loopback. Nếu bạn có IP tĩnh từ văn phòng, hãy thêm vào đây.
  • bantime: Thời gian ban IP (tính bằng giây). 3600 giây = 1 giờ. Bạn có thể để 86400 (24h) cho các dịch vụ nhạy cảm.
  • findtime: Khoảng thời gian (giây) mà fail2ban ghi nhớ các lần thử. Ví dụ: trong 600 giây, nếu có 3 lần thử sai thì ban.
  • maxretry: Số lần thử sai tối đa trước khi bị ban.
  • banaction: Tôi chọn nftables-multiport vì Ubuntu 24.04 và Debian 12 dùng nftables làm firewall mặc định (thay cho iptables). Nếu bạn đã chuyển sang iptables, hãy dùng iptables-multiport.
  • backend: systemd là tối ưu cho các dịch vụ dùng journal (sshd, nginx). Với các log file cũ, dùng pyinotify.

Thoát và lưu file (Ctrl+X, Y, Enter). Sau đó kích hoạt fail2ban chạy cùng hệ thống và khởi động:

sudo systemctl enable fail2ban
sudo systemctl start fail2ban

Verify:

sudo systemctl status fail2ban

Bạn sẽ thấy trạng thái active (running). Không có lỗi.

Bước 2 - Cấu hình jail bảo vệ SSH

fail2ban đã có filter mặc định cho SSH. Bạn chỉ cần kích hoạt jail [sshd] trong jail.local. Tìm đến phần [sshd] và sửa thành:

[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
maxretry = 3
bantime = 3600

Giải thích:

  • enabled = true: Bật jail này.
  • port = ssh: fail2ban sẽ tự lấy port SSH từ file cấu hình (mặc định 22). Nếu bạn đã đổi SSH sang port khác, hãy ghi số port cụ thể (vd: port = 1222).
  • logpath: %(sshd_log)s là macro của fail2ban, tự động ánh xạ đến /var/log/auth.log (Ubuntu/Debian).
  • backend: %(sshd_backend)s cũng là macro, thường là systemd.

Sau khi sửa, reload fail2ban để áp dụng:

sudo fail2ban-client reload

Verify:

sudo fail2ban-client status sshd

Output sẽ hiển thị "Status for the jail: sshd" kèm số IP đang bị ban (nếu có). Nếu chưa có, hãy thử SSH sai password vài lần từ một IP khác để kiểm tra.

Bước 3 - Cấu hình jail bảo vệ Nginx

Nginx có thể bị tấn công brute-force vào các trang web, hoặc bị scan tìm đường dẫn nhạy cảm. fail2ban có filter cho Nginx, nhưng tôi sẽ hướng dẫn thêm filter cho các trường hợp phổ biến:

  • nginx-http-auth: Bảo vệ các vùng xác thực HTTP Basic Auth (thường dùng cho wp-admin, phpMyAdmin).
  • nginx-botsearch: Phát hiện bot gửi request đến các đường dẫn không tồn tại (có thể là dấu hiệu của scan).

Kích hoạt jail [nginx-http-auth][nginx-botsearch] trong jail.local. Tìm hoặc thêm phần:

[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 5
bantime = 3600

[nginx-botsearch]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 10
bantime = 86400
findtime = 600

Giải thích:

  • nginx-http-auth: Nếu có request đến vùng được bảo vệ bởi HTTP Basic Auth và thất bại, Nginx ghi vào error.log. fail2ban sẽ đọc và ban IP sau 5 lần thử.
  • nginx-botsearch: Lọc các request đến các đường dẫn lạ như /wp-admin, /admin, /phpMyAdmin mà không tồn tại, thường là bot. Ban lâu hơn (24 giờ) vì bot hiếm khi dừng.

Lưu ý: Filter mặc định nginx-botsearch có thể chặn cả Google bot nếu bạn không cẩn thận. Hãy đảm bảo IP của Googlebot (72.14.192.0/18 và các dải khác, thay đổi theo thời gian) hoặc các bot hợp lệ được thêm vào ignoreip hoặc whitelist riêng. Cách hàng đầu là tạo một whitelist riêng trong jail.local:

ignoreip = 127.0.0.1/8 ::1 66.249.64.0/19 72.14.192.0/18

Hoặc bạn có thể tắt nginx-botsearch nếu không thực sự cần.

Sau khi sửa, reload:

sudo fail2ban-client reload

Verify:

sudo fail2ban-client status nginx-http-auth
sudo fail2ban-client status nginx-botsearch

Bước 4 - Cấu hình fail2ban bảo vệ WordPress

WordPress không có filter mặc định trong fail2ban vì log vào thất bại phụ thuộc vào plugin hoặc cách cấu hình. Tôi sẽ hướng dẫn cách tạo filter riêng cho WordPress khi có kẻ cố gắng đăng nhập vào /wp-login.php.

fail2ban có một filter có sẵn tên wordpress nhưng nó chỉ hoạt động khi bạn log login thất bại vào một file log riêng. Cách đơn giản và ổn định hơn là dùng plugin WP fail2ban (do Charles Lecklider phát triển, có trong kho plugin WordPress) hoặc dùng Firewall thông minh của WordPress. Nhưng tự viết filter cũng được:

Tạo file /etc/fail2ban/filter.d/wordpress-login.conf:

sudo nano /etc/fail2ban/filter.d/wordpress-login.conf

Nội dung:

[Definition]
failregex = ^<HOST>.*POST.*/wp-login\.php.* 200
ignoreregex =

Giải thích: filter trên sẽ bắt tất cả các request POST đến /wp-login.php trả về HTTP status 200 (thành công), nhưng chú ý: điều này có thể đánh lừa vì có thể là request đăng nhập thành công hoặc request load form. Tôi khuyên bạn dùng cách chuyên nghiệp hơn: ghi login thất bại của WordPress ra một file log riêng.

Cách dễ nhất: dùng WP fail2ban plugin

Cài plugin WP fail2ban (từ kho plugin WordPress, search "wp fail2ban"). Plugin này ghi tất cả các lần login thất bại vào /var/log/auth.log (theo dạng syslog), và fail2ban có filter mặc định wordpress đã hiểu. Kích hoạt jail:

[wordpress]
enabled = true
port = http,https
logpath = /var/log/auth.log
backend = %(syslog_backend)s
maxretry = 5
bantime = 86400

Giải thích:

  • Plugin ghi login thất bại vào /var/log/auth.log (cùng file với SSH).
  • Backend dùng %(syslog_backend)s vì log là syslog.
  • Ngưỡng 5 lần thử trong 600 giây, ban 24 giờ.

Sau khi cài plugin, reload fail2ban:

sudo fail2ban-client reload

Verify:

sudo fail2ban-client status wordpress

Bước 5 - Rà soát và tối ưu với whitelist

Whitelist rất quan trọng nếu bạn có dịch vụ cần truy cập thường xuyên (IP văn phòng, VPN, API server, Google Bot). Nếu bạn không whitelist, có thể bạn sẽ tự chặn chính mình hoặc chặn dịch vụ hợp lệ. Cách thêm:

sudo nano /etc/fail2ban/jail.local

Thêm dải IP vào ignoreip ở phần [DEFAULT] hoặc trong từng jail cụ thể:

ignoreip = 127.0.0.1/8 ::1 203.0.113.0/24 198.51.100.5

Sau khi thêm, reload:

sudo fail2ban-client reload

Mẹo hay: Nếu bạn quản lý nhiều VPS hoặc có IP động, hãy dùng Cloudflare hoặc một VPN trung gian để giữ IP ổn định, rồi whitelist IP đó. Nếu bạn thuê VPS Linux tại thueVPS, bạn có thể yêu cầu IP tĩnh và ghi nhớ nó để whitelist.

Bước 6 - Giám sát và gỡ IP bị ban sai

Đôi khi bạn vô tình bị ban do gõ sai password nhiều lần hoặc do IP của dịch vụ tự động (như monitor). Các lệnh kiểm tra:

  • Xem trạng thái tất cả jail đang chạy: sudo fail2ban-client status
  • Xem chi tiết jail cụ thể: sudo fail2ban-client status sshd (thay sshd bằng tên jail khác).
  • Gỡ ban một IP: sudo fail2ban-client set sshd unbanip 192.0.2.15
  • Gỡ ban tất cả IP trong một jail: sudo fail2ban-client set sshd unbanip --all

Các lệnh này hữu ích khi bạn cần khôi phục truy cập nhanh cho một IP hợp lệ bị nhầm lẫn.

Xử lý lỗi thường gặp

LỗiNguyên nhân và cách khắc phục
fail2ban không khởi độngKiểm tra lỗi cú pháp file jail: sudo fail2ban-client -t. Lỗi thường do sai logpath hoặc filter.
Jail không bắt được IPKiểm tra logpath có tồn tại không: ls -l /var/log/nginx/access.log. Kiểm tra filter có đúng regex không: sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-botsearch.conf
banaction lỗi (iptables/nftables)Xem backend nào đang chạy: iptables --version hay nft --version. Thay đổi banaction cho phù hợp.
WordPress jail không hoạt độngĐảm bảo plugin WP fail2ban đã kích hoạt và có ghi log vào /var/log/auth.log. Thử login sai và kiểm tra log: sudo tail -f /var/log/auth.log.

Câu hỏi thường gặp

fail2ban có thể tự ban IP của tôi không?

Có, nếu bạn nhập sai password quá số lần quy định. Để tránh, hãy thêm IP của bạn vào ignoreip trong jail.local hoặc dùng SSH key thay vì password. Nếu lỡ bị ban, sử dụng lệnh sudo fail2ban-client set sshd unbanip <IP_của_bạn> từ VPS (qua console hoặc IP khác).

fail2ban có ảnh hưởng đến hiệu năng VPS không?

Rất ít. fail2ban chạy nền, chỉ đọc log và ghi một vài rule firewall. Với VPS 2GB RAM, bạn không thấy bất kỳ sự khác biệt nào. Bạn có thể yên tâm chạy fail2ban trên mọi VPS giá rẻ mà không lo ảnh hưởng hiệu năng.

Làm sao biết fail2ban đang chặn IP nào?

Dùng lệnh sudo fail2ban-client status để xem danh sách jail. Sau đó dùng sudo fail2ban-client status sshd (thay tên jail) để xem IP cụ thể. Các IP bị ban sẽ hiển thị trong phần "Currently banned".

Tôi có cần plugin WordPress để dùng fail2ban không?

Không bắt buộc. Bạn có thể tự viết filter dùng regex bắt request vào /wp-login.php, nhưng dễ bị sai sót. Plugin WP fail2ban là giải pháp được bảo trì tốt, ghi log chuẩn syslog, fail2ban hiểu ngay. Tôi khuyên nên dùng plugin.

fail2ban có thể chặn DDoS không?

fail2ban không được thiết kế để chống DDoS. Nó chặn dựa trên log, nghĩa là phải có yêu cầu đến ứng dụng trước đã. Với DDoS lớp 3/4 (SYN flood, UDP flood), bạn cần firewall mạnh hơn (iptables rate limit, nftables) hoặc Cloudflare. fail2ban chỉ giúp giảm tải brute-force, không phải DDoS.

Bài viết liên quan

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ế.