Chỉ vài phút sau khi VPS có IP công khai, log SSH thường đã xuất hiện các lượt đăng nhập thất bại từ bot quét mạng. Cấu hình Fail2ban giúp tự động chặn những IP đó: công cụ này đọc log, đếm số lần thất bại trong một khoảng thời gian và thêm quy tắc tường lửa để cấm IP vi phạm. Bài này hướng dẫn cài Fail2ban trên Ubuntu, viết jail.local cho SSH và Nginx, kiểm tra trạng thái và gỡ chặn IP.
Fail2ban hoạt động thế nào
Fail2ban có ba khái niệm chính:
- Filter: tập biểu thức chính quy để nhận diện dòng log thất bại, nằm trong
/etc/fail2ban/filter.d/. - Action: việc cần làm khi phát hiện vi phạm, thường là thêm IP vào iptables hoặc nftables, nằm trong
/etc/fail2ban/action.d/. - Jail: kết hợp một filter, một action và các thông số như số lần thất bại, thời gian cấm.
Fail2ban đọc jail.conf trước, sau đó đến các file trong jail.d/ và jail.local. Giá trị trong file .local ghi đè file .conf. Vì vậy không sửa jail.conf, mọi tùy chỉnh đặt trong jail.local để không bị mất khi cập nhật gói.
Cài đặt Fail2ban trên Ubuntu
sudo apt update
sudo apt install fail2ban -y
sudo systemctl enable --now fail2ban
sudo systemctl status fail2ban
Xem cấu hình mặc định mà gói Ubuntu thêm vào:
cat /etc/fail2ban/jail.d/defaults-debian.conf
Trên Ubuntu 24.04, file này bật sẵn jail sshd và cho jail đọc log từ systemd journal. Điều đó có nghĩa Fail2ban vẫn bảo vệ SSH ngay sau khi cài, kể cả khi hệ thống không có /var/log/auth.log. Tuy vậy, thông số mặc định khá nhẹ, nên tự viết jail.local sẽ rõ ràng hơn.
Mẫu jail.local cho SSH
Tạo file /etc/fail2ban/jail.local:
sudo nano /etc/fail2ban/jail.local
[DEFAULT]
# Không bao giờ chặn các IP này (thêm IP tĩnh của bạn)
ignoreip = 127.0.0.1/8 ::1 203.0.113.10
# Thời gian cấm, khoảng tính và số lần thất bại cho phép
bantime = 1h
findtime = 10m
maxretry = 5
# Tăng dần thời gian cấm với IP tái phạm
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 1w
[sshd]
enabled = true
port = ssh
backend = systemd
maxretry = 3
Giải thích các thông số:
| Thông số | Ý nghĩa |
|---|---|
ignoreip | Danh sách IP hoặc dải mạng không bao giờ bị chặn, cách nhau bằng dấu cách |
bantime | Thời gian cấm IP. Hỗ trợ đơn vị m, h, d, w. Giá trị âm là cấm vĩnh viễn |
findtime | Khoảng thời gian dùng để đếm số lần thất bại |
maxretry | Số lần thất bại trong findtime trước khi bị cấm |
bantime.increment | Bật tăng dần thời gian cấm cho IP đã từng bị cấm |
backend | Nguồn đọc log. systemd đọc từ journal, auto đọc file log |
port | Cổng sẽ bị chặn. Phải khớp cổng SSH thực tế |
Nếu bạn đã đổi cổng SSH, ví dụ sang 2222, hãy ghi port = 2222. Nếu để ssh (cổng 22), Fail2ban sẽ chặn sai cổng.
Kiểm tra cú pháp và nạp lại cấu hình:
sudo fail2ban-client -t
sudo systemctl restart fail2ban
Thêm jail cho Nginx
Fail2ban có sẵn một số filter cho Nginx. Các jail tương ứng đã được định nghĩa trong jail.conf, bạn chỉ cần bật trong jail.local:
[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
[nginx-botsearch]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 2
[nginx-limit-req]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
- nginx-http-auth: chặn IP nhập sai user/mật khẩu nhiều lần ở các trang bảo vệ bằng HTTP Basic Auth.
- nginx-botsearch: chặn IP dò tìm các đường dẫn không tồn tại thường gặp ở bot quét lỗ hổng.
- nginx-limit-req: chặn IP liên tục vượt giới hạn tốc độ. Jail này chỉ có tác dụng khi bạn đã cấu hình
limit_req_zonevàlimit_reqtrong Nginx, vì filter đọc thông báo "limiting requests" trong error log.
Với website WordPress, trang wp-login.php là mục tiêu dò mật khẩu phổ biến. Cách gọn nhất là áp limit_req cho riêng location này, rồi để jail nginx-limit-req chặn IP vi phạm. Nếu bạn đang chạy WordPress trên Nginx, xem thêm cấu trúc server block trong bài cài LEMP Nginx, PHP-FPM, MariaDB cho WordPress.
Ví dụ giới hạn tốc độ cho trang đăng nhập. Đặt limit_req_zone trong khối http, và limit_req trong server block của site:
# /etc/nginx/nginx.conf, trong khối http
limit_req_zone $binary_remote_addr zone=wplogin:10m rate=5r/m;
# Trong server block của site
location = /wp-login.php {
limit_req zone=wplogin burst=3 nodelay;
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
Đường dẫn socket PHP-FPM tùy phiên bản PHP trên máy của bạn. Sau khi sửa, chạy sudo nginx -t rồi sudo systemctl reload nginx.
Kiểm tra trạng thái và IP bị chặn
Liệt kê các jail đang chạy:
sudo fail2ban-client status
Xem chi tiết một jail, gồm số lần thất bại, tổng số IP bị cấm và danh sách IP hiện tại:
sudo fail2ban-client status sshd
Xem toàn bộ IP đang bị cấm ở mọi jail:
sudo fail2ban-client banned
Theo dõi log của chính Fail2ban để thấy các sự kiện Ban/Unban:
sudo tail -f /var/log/fail2ban.log
Gỡ chặn IP (unban)
Gỡ chặn một IP khỏi jail cụ thể:
sudo fail2ban-client set sshd unbanip 198.51.100.25
Gỡ chặn một IP ở mọi jail, hoặc gỡ toàn bộ:
sudo fail2ban-client unban 198.51.100.25
sudo fail2ban-client unban --all
Chặn thủ công một IP mà bạn thấy đáng ngờ:
sudo fail2ban-client set sshd banip 198.51.100.25
Nếu chính bạn bị chặn và không SSH được, hãy dùng console VNC/web console trong trang quản trị của nhà cung cấp VPS để đăng nhập, rồi chạy lệnh unban. Sau đó thêm IP của mình vào ignoreip. Lưu ý IP nhà mạng gia đình tại Việt Nam thường thay đổi, nên chỉ đưa vào ignoreip những IP tĩnh mà bạn chắc chắn.
Kiểm thử filter bằng fail2ban-regex
Trước khi bật một jail mới, nên kiểm tra filter có bắt đúng dòng log hay không. Lệnh fail2ban-regex chạy filter trên file log và báo số dòng khớp:
sudo fail2ban-regex /var/log/nginx/error.log /etc/fail2ban/filter.d/nginx-limit-req.conf
Với SSH đọc từ journal:
sudo fail2ban-regex systemd-journal /etc/fail2ban/filter.d/sshd.conf
Nếu kết quả có dòng "Matched" lớn hơn 0 khi bạn biết chắc đã có lượt thất bại, filter đang hoạt động. Nếu bằng 0, kiểm tra lại đường dẫn log và định dạng log.
Chặn lâu hơn với jail recidive
Ngoài bantime.increment, Fail2ban còn có jail recidive dành cho IP tái phạm. Jail này không đọc log của SSH hay Nginx, mà đọc chính file /var/log/fail2ban.log. Nếu một IP bị cấm nhiều lần ở bất kỳ jail nào trong khoảng thời gian định trước, recidive sẽ cấm IP đó trên mọi cổng trong thời gian dài hơn. Thêm vào jail.local:
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
bantime = 1w
findtime = 1d
maxretry = 3
Chỉ nên dùng một trong hai cơ chế tăng nặng (increment hoặc recidive) nếu bạn muốn cấu hình dễ hiểu. Dùng cả hai cũng được, nhưng khi cần tra cứu vì sao một IP bị chặn, bạn sẽ phải xem nhiều jail hơn.
Fail2ban chỉ là một lớp bảo vệ
Fail2ban giảm rủi ro dò mật khẩu, nhưng không thay thế các biện pháp nền tảng. Nên kết hợp với:
- Đăng nhập bằng SSH key và tắt
PasswordAuthentication. - Tắt đăng nhập trực tiếp bằng root qua SSH.
- Bật UFW, chỉ mở các cổng thực sự cần dùng.
- Cập nhật hệ thống thường xuyên.
Các bước này được trình bày trong bài bảo mật VPS Ubuntu 24.04 trong 30 phút đầu. Nếu bạn cần một VPS để thực hành, Canh Deal đề xuất VPS giá rẻ TDCloud từ 55.000đ/tháng cho gói 1 vCPU/1GB/20GB (giá tham khảo ngày 24/10/2026, chưa gồm VAT). Bạn cũng có thể so sánh thêm các gói tại trang dịch vụ VPS.