SSD Nodes Learn Hosting plans →
Hướng dẫn Matt ConnorBởi Matt Connor · Cập nhật ngày 2026-08-07

Cài Fail2ban trên Ubuntu 24.04 để chặn bot SSH

Trên Ubuntu 24.04, cài apt mặc định đã chặn brute force SSH. Dùng fail2ban-client status sshd để kiểm tra và xử lý lỗi Total failed vẫn là 0.

Fail2ban thực sự làm gì

Fail2ban là một daemon đọc log. Nó theo dõi các thông báo xác thực SSH. Sau một số lần đăng nhập thất bại từ cùng một địa chỉ trong một khoảng thời gian ngắn, nó chạy lệnh firewall để chặn địa chỉ đó trong một thời gian. Đó là toàn bộ nguyên lý. Cấu hình chỉ khoảng 30 dòng trong một file. Trên Ubuntu 24.04, quá trình cài đặt chỉ cần một lệnh apt và Fail2ban đã bắt đầu bảo vệ hệ thống trước khi bạn chỉnh sửa bất kỳ cấu hình nào.

Cần hiểu rõ Fail2ban làm được gì và không làm được gì. Fail2ban không xác thực người dùng, không mã hóa dữ liệu và không ngăn được một lần đăng nhập đơn lẻ có chủ đích. Nó chỉ xử lý các lần thử lặp lại từ cùng một nguồn. Đây là bộ lọc nhiễu và công cụ giới hạn tốc độ, không phải một cơ chế khóa. Nhiệm vụ của nó là ngăn hoạt động quét liên tục trong nền trên cổng 22 tiêu tốn CPU, băng thông và dung lượng log, đồng thời làm chậm kẻ tấn công khi chúng phải lần lượt sử dụng từng địa chỉ.

Fail2ban không thay thế được gì

Fail2ban là lớp bảo vệ thứ ba, không phải lớp đầu tiên. Nếu server vẫn chấp nhận đăng nhập SSH bằng password, một botnet phân tán trên hàng nghìn địa chỉ có thể tiếp tục thử đoán password, vì mỗi địa chỉ vẫn nằm dưới ngưỡng ban và không bao giờ kích hoạt ngưỡng đó. Biện pháp phòng vệ thực sự là chỉ cho phép xác thực bằng key. Khi đó, việc đoán password là không thể, bất kể có bao nhiêu lần thử. Fail2ban chạy bên trên cơ chế xác thực chỉ bằng key sẽ làm được 2 việc hữu ích: loại bớt nhiễu brute-force khỏi log và loại scanner từ sớm để chúng ngừng liên tục truy cập vào port. Hãy xem Fail2ban là một lớp phòng thủ bổ sung. Nó nằm sau xác thực bằng key và sau firewall, không bao giờ thay thế hoặc đứng trước 2 lớp này.

Điều kiện cần và thực tế trên Ubuntu 24.04

Bạn cần một VPS chạy Ubuntu 24.04 với quyền root hoặc sudo, và SSH đã hoạt động, tốt nhất là dùng xác thực bằng key. Fail2ban tiết kiệm tài nguyên: chỉ cần vài chục megabyte RAM, không cần điều chỉnh các giới hạn.

Bây giờ là phần mà mọi hướng dẫn cũ đều dễ sai. Trong nhiều năm, lời khuyên phổ biến là "cài Fail2ban, rồi thêm backend = systemd, vì Ubuntu đã ngừng ghi vào /var/log/auth.log." Lời khuyên này mô tả một thay đổi có thật: các image server và cloud hiện đại không có sẵn rsyslog, nên SSH chỉ ghi log vào systemd journal và file văn bản đó không còn nữa. Tuy nhiên, trên Ubuntu 24.04, package Fail2ban đã xử lý trường hợp này. Package cài sẵn /etc/fail2ban/jail.d/defaults-debian.conf, và chính file đó, không phải cấu hình mặc định từ upstream, là cấu hình thực sự được server của bạn sử dụng:

[DEFAULT]
banaction = nftables
banaction_allports = nftables[type=allports]
backend = systemd

[sshd]
enabled = true

Hãy đọc kỹ phần này, vì nó giải đáp 2 câu hỏi trước khi bạn thay đổi bất cứ thứ gì. backend = systemd nghĩa là SSH jail đọc journal, nên việc thiếu auth.log không ảnh hưởng. banaction = nftables nghĩa là lệnh ban được thực thi thông qua nftables, là firewall thực sự được Ubuntu 24.04 sử dụng, thay vì iptables legacy. Còn [sshd] enabled = true nghĩa là jail được bật ngay từ lần boot đầu tiên. Tóm lại: apt install fail2ban mặc định trên Ubuntu 24.04 sẽ chặn brute-force SSH ngay khi cài xong. Phần lớn công việc của bạn là xác nhận điều đó, tinh chỉnh policy và bảo đảm bạn không tự khóa quyền truy cập của mình.

Lỗi auth.log cũ vẫn xảy ra trong 3 trường hợp, và bạn nên nhận biết chúng: bạn cài Fail2ban bằng pip thay vì apt, nên không có defaults-debian.conf; bạn đang ở trong một container không có quyền với systemd journal để đọc log; hoặc bạn đã làm theo hướng dẫn cũ và dán backend = auto vào jail.local của mình, khiến cấu hình mặc định đang hoạt động bị ghi đè. Phần xử lý lỗi sẽ cho thấy chính xác biểu hiện của từng trường hợp.

Bước 1: Cài đặt và xác nhận Fail2ban đã ban IP

sudo apt update
sudo apt install -y fail2ban

Ubuntu 24.04 phát hành kèm Fail2ban 1.0.2. Package này kéo theo python3-systemd dưới dạng dependency bắt buộc, nên journal backend đã có đủ mọi thứ cần thiết. Service tự enable và start:

sudo systemctl status fail2ban

Bạn cần thấy active (running). Sau đó kiểm tra jail đang hoạt động:

sudo fail2ban-client status sshd

Trên một VPS public đã có thể truy cập trong vài phút, bạn thường sẽ thấy các lần đăng nhập thất bại đã được đếm và các địa chỉ đã bị ban. Internet liên tục scan cổng 22. Đây là bằng chứng cho thấy config mặc định hoạt động. Từ đây, bạn chỉ cần tinh chỉnh config, không phải xây dựng từ đầu.

Bước 2: Chỉnh sửa jail.local, không chỉnh sửa jail.conf

Fail2ban lưu các giá trị mặc định của nhà phát hành trong /etc/fail2ban/jail.conf. Không chỉnh sửa file đó. Mỗi apt upgrade của package có thể thay thế file này, khiến các thay đổi của bạn biến mất mà không có cảnh báo. Fail2ban đọc các file theo thứ tự cố định: đầu tiên là jail.conf, sau đó là mọi file trong jail.d/, rồi đến jail.local; giá trị đọc sau cùng sẽ được áp dụng. File .local là file dành cho bạn và các lần nâng cấp package không bao giờ chạm vào file này. Quy tắc tương tự áp dụng cho filter: file *.local sẽ ghi đè file filter.d/*.conf được package cung cấp.

Vì vậy, bạn chỉ cần viết một jail.local nhỏ để ghi đè vài thiết lập cần dùng, đồng thời giữ nguyên cả jail.confjail.d/defaults-debian.conf của package làm tài liệu tham chiếu.

Bước 3: Tạo /etc/fail2ban/jail.local

sudo nano /etc/fail2ban/jail.local

Thêm nội dung này vào file, thay địa chỉ trên dòng ignoreip bằng public IP của bạn:

[DEFAULT]
# Ubuntu 24.04 already sets these two in jail.d/defaults-debian.conf.
# Pinning them here documents the dependency and survives if that
# file is ever removed or changed by an upgrade.
backend   = systemd
banaction = nftables

# Ban for one hour ...
bantime  = 1h
# ... if an address fails ...
maxretry = 5
# ... 5 times within 10 minutes.
findtime = 10m

# Never ban these. PUT YOUR OWN IP HERE.
ignoreip = 127.0.0.1/8 ::1 10.0.0.24

# Longer bans for repeat offenders: 1h, 2h, 4h ... up to a week.
bantime.increment = true
bantime.maxtime   = 1w

[sshd]
enabled = true

Mỗi dòng đều có lý do:

  • bantime, findtime, maxretry là chính sách. Giá trị mặc định đi kèm bantime chỉ là mười phút; đặt một giờ sẽ hợp lý hơn. Năm lần thất bại từ cùng một địa chỉ trong vòng mười phút sẽ bị ban. Người dùng thật có thể gõ sai mật khẩu một hoặc hai lần; năm lần thất bại trong mười phút thường là script.
  • ignoreip là biện pháp an toàn. Thêm public address mà bạn kết nối từ đó vào đây để Fail2ban không thể khóa chính bạn khỏi server. Nếu kết nối tại nhà dùng IP thay đổi, đó là lý do nên ưu tiên phương án VPN ở cuối bài, không phải lý do bỏ qua dòng này.
  • bantime.increment = true khiến mỗi lần ban lặp lại dài hơn lần trước: một giờ, rồi hai giờ, rồi bốn giờ, tối đa đến bantime.maxtime. Những địa chỉ liên tục quay lại sẽ bị khóa dần lâu hơn.

Tìm địa chỉ cần whitelist trên máy mà bạn SSH từ đó, không phải trên server:

curl -s ifconfig.me

Bạn có thể tạo một jail.local được tinh chỉnh theo các cổng và chính sách ban của mình tại đây, rồi dán vào file:

ToolFail2ban jail generator

Bước 4: Khởi động lại và xác minh dịch vụ đang đọc journal

sudo fail2ban-client -t
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd

-t chạy kiểm tra cấu hình trước, nên lỗi gõ sai trong jail.local sẽ báo lỗi rõ ràng tại đây thay vì khiến service không hoạt động. Trạng thái jail bình thường có dạng sau:

Status for the jail: sshd
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     14
|  `- Journal matches:  _SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
   |- Currently banned: 1
   |- Total banned:     3
   `- Banned IP list:   10.0.0.66

Giá trị chứng minh Fail2ban thực sự đang đọc các lần đăng nhập là Total failed. Nếu giá trị này lớn hơn 0 hoặc tăng lên khi bạn cố ý đăng nhập sai từ một máy khác, journal đang được đọc và bạn đã hoàn tất. Nếu giá trị vẫn là 0 dù bạn đăng nhập sai bao nhiêu lần, đồng thời bạn chắc chắn không kiểm tra từ địa chỉ nằm trong ignoreip, hãy chuyển đến phần các chế độ lỗi bên dưới.

Lưu ý rằng dòng Journal matches vẫn ghi sshd.service. Trên Ubuntu, unit SSH thực tế là ssh.service, nhưng filter được cung cấp cũng khớp với _COMM=sshd, và OpenSSH trên 24.04 ghi các lần đăng nhập thất bại từ một tiến trình có tên sshd, nên việc khớp vẫn hoạt động. Chi tiết này chỉ quan trọng nếu bạn dùng OpenSSH mới hơn (9.8 trở lên, trong đó worker cho từng kết nối là sshd-session); phần các chế độ lỗi sẽ xử lý trường hợp đó.

Bước 5: Theo dõi một lệnh ban thực tế hoặc buộc tạo một lệnh để kiểm thử

Trên mọi VPS public, các lệnh ban thực tế thường tự xuất hiện trong vài phút. Để theo dõi, hãy tail log:

sudo tail -f /var/log/fail2ban.log

Một lệnh ban có dạng như sau:

2026-07-15 10:31:40,502 fail2ban.filter  [812]: INFO    [sshd] Found 10.0.0.66 - 2026-07-15 10:31:40
2026-07-15 10:31:44,118 fail2ban.actions [812]: NOTICE  [sshd] Ban 10.0.0.66

Để kiểm thử toàn bộ quy trình mà không phải chờ, hãy ban thủ công một địa chỉ dùng cho tài liệu, tuyệt đối không dùng địa chỉ của bạn:

sudo fail2ban-client set sshd banip 10.0.0.66

Lệnh này in ra 1, và địa chỉ xuất hiện bên dưới Banned IP list trong fail2ban-client status sshd. Bây giờ hãy xác nhận block thực sự tồn tại trong firewall. Trên Ubuntu 24.04, firewall là nftables, không phải iptables:

sudo nft list table inet f2b-table

Bạn sẽ thấy một set có tên addr-set-sshd chứa 10.0.0.66, cùng một chain f2b-chain từ chối mọi source nằm trong set đó. Nếu fail2ban-client cho biết một địa chỉ đã bị ban nhưng không có gì xuất hiện trong nft list, ban action của bạn không khớp với firewall. Xem ghi chú về nftables/iptables trong phần các chế độ lỗi.

Bước 6: Gỡ ban cho chính bạn và khôi phục quyền truy cập khi bị khóa

Nếu bạn đã ban nhầm một địa chỉ, bao gồm địa chỉ của chính mình, hãy gỡ địa chỉ đó:

sudo fail2ban-client set sshd unbanip 10.0.0.66

Lệnh trả về 1 nếu thành công. Để xóa mọi ban trên tất cả các jail:

sudo fail2ban-client unban --all

Đừng dựa vào một phiên SSH đã mở để giữ kết nối: nftables ban sẽ từ chối mọi packet từ địa chỉ bị ban đến port 22, kể cả các kết nối đã được thiết lập, nên phiên hiện tại sẽ treo ngay khi ban được áp dụng. Nếu bạn tự ban chính mình và không có entry ignoreip, bạn sẽ bị khóa quyền truy cập cho đến khi ban hết hạn. Hãy khôi phục quyền truy cập qua web console của nhà cung cấp (VNC hoặc serial), vì kết nối này không đi qua SSH, rồi chờ bantime hết hạn hoặc chạy lệnh gỡ ban tại đó.

Bước 7: Giữ ban tồn tại và tăng dần mức phạt

Fail2ban lưu các ban đang hoạt động trong một cơ sở dữ liệu SQLite nhỏ tại /var/lib/fail2ban/fail2ban.sqlite3, nên chúng vẫn tồn tại sau khi service restart hoặc reboot; bạn không bị mất chúng. Các dòng bantime.increment bạn đã thêm sẽ biến mỗi nguồn tái phạm thành một vấn đề ngày càng nghiêm trọng đối với chính nguồn đó, với thời gian ban tăng gần gấp đôi từ một giờ lên khoảng một tuần.

Để áp dụng chính sách "ba lần vi phạm" trên toàn hệ thống, Fail2ban cung cấp jail recidive. Jail này theo dõi /var/log/fail2ban.log của chính nó và áp dụng ban dài hạn cho mọi địa chỉ đã bị ban nhiều lần trên tất cả các jail. Vì [DEFAULT] của bạn hiện dùng backend systemd, hãy cố định jail này trở lại file log mà nó được thiết kế để đọc:

[recidive]
enabled  = true
backend  = auto
logpath  = /var/log/fail2ban.log
bantime  = 1w
findtime = 1d
maxretry = 5

backend = auto cùng với logpath rõ ràng sẽ giữ cho recidive đọc fail2ban.log dạng plain. Đây là nơi các dòng Ban mà nó đếm thực sự xuất hiện. Nếu dùng mặc định systemd đã đặt trên toàn cục, jail sẽ đọc journal, nơi các dòng đó không xuất hiện.

Bước 8: Kết hợp với SSH chỉ dùng key, và tốt hơn nữa là VPN

Fail2ban chỉ phát huy tác dụng khi đi cùng xác thực bằng key. Trong một file drop-in dưới /etc/ssh/sshd_config.d/, chẳng hạn /etc/ssh/sshd_config.d/00-hardening.conf, hãy đặt:

PasswordAuthentication no
KbdInteractiveAuthentication no

Sau đó sudo systemctl restart ssh. Khi tắt đăng nhập bằng password, brute force hoàn toàn không thể thành công; Fail2ban khi đó chủ yếu dùng để giảm log nhiễu và loại scanner sớm. Tốt hơn nữa là không để SSH xuất hiện trên Internet công cộng: đặt SSH phía sau WireGuard VPN tự host và cấu hình firewall để cổng 22 chỉ phản hồi trên tunnel. Không ai có thể brute-force một cổng mà họ không thể truy cập, và Fail2ban trở thành lớp dự phòng thay vì tuyến phòng thủ chính.

Fail2ban không chỉ dùng cho SSH. Bất kỳ service nào ghi log các lần đăng nhập thất bại đều có thể dùng một jail, chẳng hạn mail server, một site nginx hoặc trình quản lý password Vaultwarden tự host có web login mà bạn không muốn để mở cho credential stuffing. Khi một web app nằm phía sau site nginx có chứng chỉ Let's Encrypt, hãy trỏ một Fail2ban filter đến access log của nó theo cách tương tự như SSH jail trỏ đến journal.

Các trường hợp lỗi và chuỗi chính xác bạn sẽ thấy

"Have not found any log file for sshd jail", và Fail2ban không khởi động. Đây là vấn đề auth.log cũ. Trên Ubuntu 24.04, lỗi này chỉ xảy ra khi có thứ gì đó ghi đè cấu hình mặc định của package, khi cài pip nhưng không có defaults-debian.conf, khi chạy trong container không có journal, hoặc khi bạn dán nhầm backend = auto vào jail.local. Với file backend không có /var/log/auth.log, jail sshd không tìm thấy log và toàn bộ daemon dừng khởi động. fail2ban.log hiển thị:

ERROR   Failed during configuration: Have not found any log file for sshd jail

Vì đây là lỗi nghiêm trọng, service không bao giờ khởi động được. Sau đó fail2ban-client status báo triệu chứng phát sinh:

ERROR  Failed to access socket path: /var/run/fail2ban/fail2ban.sock. Is fail2ban running?

Dòng "socket path" không có nghĩa Fail2ban bị hỏng. Nó có nghĩa Fail2ban chưa khởi động vì một jail không tìm thấy log. Đặt backend = systemd trong [DEFAULT], vốn đã được package Ubuntu cấu hình sẵn, sẽ sửa cả hai thông báo cùng lúc.

Jail đang active nhưng Total failed không bao giờ tăng. Daemon đang chạy và journal đang được đọc, nhưng các lần đăng nhập thất bại thực tế tích lũy trong journalctl -u ssh trong khi bộ đếm vẫn ở 0. Trước tiên, hãy loại trừ nguyên nhân dễ thấy: bạn đang kiểm tra từ một địa chỉ có trong ignoreip, nên các lần thất bại của chính bạn được miễn theo thiết kế. Nếu không phải trường hợp đó, bạn đang dùng bản OpenSSH mà worker xử lý từng connection là sshd-session (9.8 trở lên). Trong bản này, journal _COMMsshd-session chứ không phải sshd, nên pattern mặc định không khớp. Mở rộng pattern trong block [sshd]:

[sshd]
enabled      = true
backend      = systemd
journalmatch = _SYSTEMD_UNIT=ssh.service + _COMM=sshd + _COMM=sshd-session

Khởi động lại service, cố ý làm một lần đăng nhập thất bại từ địa chỉ không có trong ignoreip, rồi xác nhận Total failed cuối cùng đã tăng.

Bạn đã tự ban chính mình: Connection refused. Bạn không đưa địa chỉ của mình vào ignoreip, thử vài lần đăng nhập sai, và bây giờ:

ssh: connect to host 10.0.0.10 port 22: Connection refused

Thay vì timeout im lặng, kết nối bị từ chối vì verdict mặc định reject của action nftables đang hoạt động, và nó áp dụng cho chính bạn. Hãy sửa theo Step 6: unban từ một session trên địa chỉ khác chưa bị ban, hoặc từ provider console. Một session đã mở từ địa chỉ bị ban cũng sẽ bị đóng băng. Sau đó thêm địa chỉ của bạn vào ignoreip để lỗi này không lặp lại.

Fail2ban báo một địa chỉ đã bị ban nhưng địa chỉ đó vẫn kết nối được. Bộ đếm trong status sshd tăng, nhưng địa chỉ đó vẫn truy cập được port 22. Đây là tình trạng không khớp giữa ban action và firewall. Trên Ubuntu 24.04, nguyên nhân gần như luôn là bạn đã ghi đè banaction = nftables đang hoạt động bằng banaction = iptables-multiport sao chép từ một hướng dẫn cũ, trên máy không có lớp iptables. fail2ban.log hiển thị:

fail2ban.actions [812]: ERROR  Failed to execute ban jail 'sshd' action 'iptables-multiport'

Xóa phần ghi đè đó và để action nftables do package cung cấp tiếp tục được dùng. Hoặc, nếu bạn quản lý firewall hoàn toàn bằng ufw và muốn các lệnh ban xuất hiện trong ufw, hãy đặt banaction = ufw trong [DEFAULT]. Khởi động lại service và xác nhận rule xuất hiện bằng sudo nft list ruleset | grep f2b.

Fail2ban không khởi động sau khi chỉnh sửa jail.local. Lỗi chính tả, heading thừa hoặc giá trị thời gian không hợp lệ có thể khiến service từ chối khởi động. Hãy yêu cầu Fail2ban kiểm tra cấu hình trước khi chạy:

sudo fail2ban-client -t

Lệnh sẽ cho biết file và jail gặp lỗi, ví dụ Errors in jail 'sshd'. Skipping.... Nhờ đó, bạn sửa đúng nguồn cấu hình thay vì phải đoán.

FAQ

Bản cài Fail2ban mặc định trên Ubuntu 24.04 có thực sự chặn các cuộc tấn công SSH không?

Có. Gói này cung cấp /etc/fail2ban/jail.d/defaults-debian.conf, bật jail sshd, đặt backend = systemd để đọc systemd journal thay vì /var/log/auth.log không tồn tại, và đặt banaction = nftables để áp dụng lệnh ban thông qua firewall thực tế của Ubuntu. Một apt install fail2ban đơn giản đã bảo vệ SSH ngay từ lần boot đầu tiên. Xác nhận bằng sudo fail2ban-client status sshd và kiểm tra xem Total failed có giá trị khác 0 hay không.

Vì sao Fail2ban không chặn gì trên máy của tôi?

Hãy lần lượt loại trừ 3 nguyên nhân phổ biến. Có thể bạn đang kiểm tra từ một địa chỉ nằm trong ignoreip, vốn được miễn ban theo thiết kế. Có thể bạn đã ghi đè cấu hình mặc định đang hoạt động bằng cách dán backend = auto vào jail.local theo một hướng dẫn cũ, khiến việc đọc journal hỏng trên image không có auth.log. Hoặc bạn đang ở trong một container hoàn toàn không có systemd journal để đọc. Kiểm tra Total failed trong fail2ban-client status sshd: nếu giá trị này không tăng trong khi journalctl -u ssh hiển thị các lần lỗi thực tế, jail đang đọc sai nơi.

Làm cách nào để bỏ ban địa chỉ IP của chính tôi?

Chạy sudo fail2ban-client set sshd unbanip YOUR.IP.HERE. Lệnh này trả về 1 nếu thành công. Bạn cũng có thể chạy sudo fail2ban-client unban --all để xóa mọi ban. Nếu bị khóa khỏi SSH, hãy dùng web console hoặc VNC console của nhà cung cấp để chạy cùng lệnh đó. Ban sẽ loại bỏ mọi packet từ địa chỉ của bạn đến port 22, nên ngay cả session đang mở cũng sẽ ngừng hoạt động. Sau đó thêm địa chỉ của bạn vào ignoreip để địa chỉ này không bị ban lại.

jail.conf và jail.local khác nhau như thế nào?

jail.conf chứa các giá trị mặc định từ upstream của Fail2ban và bị ghi đè sau mỗi lần package upgrade, nên mọi chỉnh sửa tại đó cuối cùng sẽ bị mất. Package Debian/Ubuntu áp dụng các thiết lập riêng lên trên thông qua jail.d/defaults-debian.conf. Bạn phải đặt các thay đổi trong jail.local. File này được đọc sau cùng, có hiệu lực ưu tiên hơn cả hai file trên và không bị các lần upgrade chỉnh sửa. Hãy giữ jail.conf ở trạng thái chỉ đọc để tham khảo.

Fail2ban có thay thế xác thực SSH bằng key không?

Không. Fail2ban giới hạn rate các lần đăng nhập thất bại lặp lại từ một địa chỉ. Nó không xử lý được kiểu đoán mật khẩu chậm và phân tán, trong đó mỗi địa chỉ vẫn nằm dưới ngưỡng. Xác thực chỉ bằng key (PasswordAuthentication no) khiến việc đoán mật khẩu hoàn toàn không thể thực hiện, còn Fail2ban giúp giảm log noise và loại các scanner sớm. Hãy dùng cả hai, và tốt nhất là không để SSH trên Internet công khai.