Ubuntu 24.04 安裝 Fail2ban 阻擋 SSH 機器人
在 Ubuntu 24.04 上,直接執行 apt install 即可封鎖 SSH 暴力破解。用 fail2ban-client status sshd 查看結果,並修正 Total failed 一直是 0 的問題。
Fail2ban 實際上會做什麼
Fail2ban 是讀取日誌的 daemon。它會監控 SSH 驗證訊息;如果同一個位址在短時間內連續失敗數次,就執行防火牆命令,暫時封鎖該位址。這就是它的全部原理。設定檔只有約 30 行,而在 Ubuntu 24.04 上,安裝只需執行一個 apt 命令。即使尚未修改任何設定,安裝完成後也會立即受到保護。
請明確了解它的功能與限制。Fail2ban 不會驗證使用者身分、不會加密資料,也無法阻止單次的登入嘗試;它只能阻止來自同一來源的重複嘗試。它是雜訊過濾器與速率限制工具,不是鎖定機制。它的作用是讓對 port 22 的持續背景掃描不再浪費 CPU、網路流量與日誌空間,並拖慢必須逐一從不同位址發動攻擊的攻擊者。
Fail2ban 無法取代的措施
Fail2ban 是第三層防護,不是第一層。如果伺服器仍接受 SSH 密碼驗證,分布在數千個來源位址的殭屍網路仍可持續猜測密碼,因為每個位址都低於封鎖門檻,不會觸發封鎖。真正能防止這種攻擊的是僅限 cryptographic key 驗證。無論攻擊者嘗試多少次,都無法猜測密碼。
在僅限 cryptographic key 驗證的基礎上使用 Fail2ban,有兩項實際作用:從日誌中排除暴力破解產生的雜訊,並及早驅逐掃描器,讓它們停止持續敲擊連接埠。應將它視為縱深防禦的一環。它位於 cryptographic key 驗證與防火牆之後,絕不能取代這兩者。
先決條件,以及 Ubuntu 24.04 的實際情況
您需要一台執行 Ubuntu 24.04 的 VPS,具備 root 或 sudo 權限,且 SSH 已可正常使用,最好採用金鑰驗證。Fail2ban 的資源需求低,只需數十 MB 的 RAM,無須調整限制。
接著是所有較舊指南都容易誤導的部分。多年來,標準建議是「安裝 Fail2ban,然後加入 backend = systemd,因為 Ubuntu 已停止寫入 /var/log/auth.log。」這項建議描述的是確實發生過的變更:現代伺服器與雲端映像檔通常不再提供 rsyslog,因此 SSH 只會寫入 systemd journal,該文字檔也已不存在。但在 Ubuntu 24.04 中,Fail2ban 套件已經處理這個情況。套件會加入 /etc/fail2ban/jail.d/defaults-debian.conf;實際在伺服器上執行的是這個檔案,而不是 upstream 預設值:
[DEFAULT]
banaction = nftables
banaction_allports = nftables[type=allports]
backend = systemd
[sshd]
enabled = true請仔細閱讀這段內容,因為在進行任何設定前,它已回答兩個問題。backend = systemd 表示 SSH jail 會讀取 journal,因此缺少 auth.log 並不影響運作。banaction = nftables 表示封鎖會透過 nftables 強制執行;Ubuntu 24.04 實際使用的是 nftables,而不是舊版 iptables。[sshd] enabled = true 則表示此 jail 從第一次開機起便已啟用。換句話說,在 Ubuntu 24.04 上,標準的 apt install fail2ban 預設即可封鎖 SSH 暴力破解。您大部分的工作是確認這項設定、調整政策,並確保自己不會被鎖在系統外。
舊的 auth.log 陷阱仍會在以下 3 種情況造成問題,值得加以辨識:您使用 pip 而不是 apt 安裝 Fail2ban,因此不存在 defaults-debian.conf;您位於沒有可供讀取之 systemd journal 的非特權容器內;或您依照舊版教學,將 backend = auto 貼到自己的 jail.local 中,覆寫了原本可正常運作的預設值。故障模式一節會準確說明每種情況的表現。
步驟 1:安裝並確認系統已開始封鎖
sudo apt update
sudo apt install -y fail2banUbuntu 24.04 隨附 Fail2ban 1.0.2,而套件會將 python3-systemd 納入硬性相依性,因此 journal 後端具備所需的一切。服務會自行啟用並啟動:
sudo systemctl status fail2ban您應看到 active (running)。接著查看已在運作的 jail:
sudo fail2ban-client status sshd對於已公開連線幾分鐘的 VPS,通常已可看到失敗次數與遭封鎖的位址。網際網路會持續掃描連接埠 22。這表示預設設定正常運作。接下來是進行調整,而不是從零開始建置。
步驟 2:編輯 jail.local,絕不要編輯 jail.conf
Fail2ban 將上游預設值保留在 /etc/fail2ban/jail.conf。請勿編輯該檔案。套件的每次 apt upgrade 都可能取代該檔案,且您的變更會在沒有任何警告的情況下消失。Fail2ban 會依固定順序讀取檔案,先讀取 jail.conf,接著讀取 jail.d/ 中的所有檔案,最後讀取 jail.local,並以最後讀取的值為準。.local 檔案由您管理,套件升級絕不會修改它。同一規則也適用於篩選器:*.local 檔案會覆寫套件隨附的 filter.d/*.conf。
因此,請建立一個小型 jail.local,只覆寫您需要的少數設定,並將 jail.conf 與套件提供的 jail.d/defaults-debian.conf 都保留為參考,不要修改。
步驟 3:撰寫 /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local將以下內容寫入檔案,並將 ignoreip 行中的位址改為您自己的公開 IP:
[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每一行都有其用途:
bantime、findtime、maxretry是政策設定。隨附的預設值bantime只有 10 分鐘;設定為 1 小時更為合理。單一位址在 10 分鐘內失敗 5 次,就會遭到封鎖。一般使用者可能會輸入錯誤密碼 1、2 次;10 分鐘內失敗 5 次通常代表是腳本。ignoreip是安全措施。請在此填入您用來連線的公開位址,讓 Fail2ban 永遠不會將您鎖在自己的伺服器之外。家用連線若使用浮動 IP,表示您應優先採用文末的 VPN 方式,而不是省略此行。bantime.increment = true會讓每次重複封鎖的時間比上次更長,依序為 1 小時、2 小時、4 小時,最長可達bantime.maxtime。持續重返的位址會逐步遭到更長時間的封鎖。
請從您用來 SSH 連線的機器查找要加入白名單的位址,而不是從伺服器查找:
curl -s ifconfig.me您可以在此產生依照連接埠與封鎖政策調整的 jail.local,再將內容貼入檔案:
步驟 4:重新啟動,並確認它正在讀取 journal
sudo fail2ban-client -t
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd-t 會先執行設定測試,因此 jail.local 中的拼寫錯誤會在此處明確顯示失敗,不會讓服務維持停止狀態。正常的 jail 狀態如下:
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能證明 Fail2ban 確實正在讀取登入記錄的數值是 Total failed。如果該數值大於 0,或你從另一台機器刻意登入失敗時數值上升,表示 journal 正在被讀取,設定已完成。如果無論登入失敗多少次,數值都維持在 0,而且你確定測試來源不是 ignoreip 中的位址,請跳至下方的失敗模式。
請注意,Journal matches 行仍然使用 sshd.service。在 Ubuntu 上,SSH unit 實際上是 ssh.service,但隨附的 filter 也會比對 _COMM=sshd;此外,OpenSSH 24.04 會從名為 sshd 的程序記錄失敗,因此比對仍可運作。只有在使用較新版本的 OpenSSH(9.8 或更新版本)時,這項細節才重要;在該版本中,每個連線的 worker 是 sshd-session。失敗模式涵蓋這種情況。
步驟 5:監看實際封鎖,或強制執行一次進行測試
在任何公開 VPS 上,實際封鎖通常會在幾分鐘內自行發生。若要監看,請持續顯示日誌:
sudo tail -f /var/log/fail2ban.log封鎖記錄如下:
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若不想等待,可手動封鎖文件使用的 IP 位址進行端對端測試,但絕對不要封鎖自己的位址:
sudo fail2ban-client set sshd banip 10.0.0.66此命令會輸出 1,而該位址會出現在 fail2ban-client status sshd 的 Banned IP list 下方。現在確認防火牆中確實存在封鎖規則。在 Ubuntu 24.04 上使用的是 nftables,而不是 iptables:
sudo nft list table inet f2b-table你會看到名為 addr-set-sshd 的集合,其中包含 10.0.0.66,以及名為 f2b-chain 的鏈,會拒絕來源位於該集合中的所有連線。若 fail2ban-client 顯示某個位址已遭封鎖,但 nft list 中沒有任何內容,表示你的封鎖動作與防火牆不相容。請參閱故障模式中的 nftables/iptables 說明。
步驟 6:解除自身封鎖,並在遭鎖定時復原
如果不慎封鎖了不應封鎖的位址,包括自己的位址,請將其移除:
sudo fail2ban-client set sshd unbanip 10.0.0.66成功時會回傳 1。若要清除所有 jail 中的所有封鎖:
sudo fail2ban-client unban --all不要依賴已開啟的 SSH 工作階段來避免失聯:nftables 封鎖規則會拒絕來自該封鎖位址、前往連接埠 22 的所有封包,包括已建立連線的封包,因此封鎖規則生效後,現有工作階段會立即停止回應。如果封鎖了自己的位址,且沒有 ignoreip 項目,您會持續無法登入,直到封鎖到期為止。請透過供應商的 Web 主控台(VNC 或 serial)復原;該主控台不會經由 SSH 連線。您可以等待 bantime 到期,或在該主控台中執行解除封鎖命令。
步驟 7:讓封鎖持續生效並逐步升級
Fail2ban 會將目前的封鎖狀態儲存在 /var/lib/fail2ban/fail2ban.sqlite3 的小型 SQLite 資料庫中,因此服務重新啟動或系統重新開機後,封鎖仍會保留,不會遺失。你先前加入的 bantime.increment 設定會讓每個重複違規者面臨逐步升級的處置,封鎖時間大致會從 1 小時加倍延長至 1 週。
如果要在此基礎上實作全系統的「三振」政策,Fail2ban 提供一個 recidive jail。它會監控自己的 /var/log/fail2ban.log,並將長時間封鎖套用至在所有 jail 中反覆遭到封鎖的位址。由於你的 [DEFAULT] 現在使用 systemd backend,請將此 jail 指定回它設計用來讀取的日誌檔案:
[recidive]
enabled = true
backend = auto
logpath = /var/log/fail2ban.log
bantime = 1w
findtime = 1d
maxretry = 5使用明確的 logpath 的 backend = auto 會讓 recidive 讀取純文字的 fail2ban.log。這正是它要計算的 Ban 設定實際出現的位置;你全域設定的 systemd 預設值則會將其指向 journal,而這些設定並不在其中。
步驟 8:搭配僅限金鑰的 SSH,最好再加上 VPN
Fail2ban 只有搭配金鑰驗證才能發揮作用。在 /etc/ssh/sshd_config.d/ 下建立 drop-in 檔案,例如 /etc/ssh/sshd_config.d/00-hardening.conf,並設定:
PasswordAuthentication no
KbdInteractiveAuthentication no接著執行 sudo systemctl restart ssh。停用密碼驗證後,暴力破解完全無法成功;Fail2ban 的用途則是減少日誌雜訊,並及早封鎖掃描器。更安全的做法是完全不讓 SSH 暴露在公開網際網路上:讓 SSH 僅透過自架 WireGuard VPN 存取,並設定防火牆,使 22 埠只在通道上接受連線。攻擊者無法暴力破解無法連線的埠,因此 Fail2ban 只需作為後備防線,而非第一道防線。
Fail2ban 不只適用於 SSH。任何會記錄登入失敗的服務都能設定 jail,例如郵件伺服器、nginx 網站,或是 自架的 Vaultwarden 密碼管理器;對於後者,通常不應讓 Web 登入介面暴露於憑證填充攻擊。一旦 Web 應用程式放在 使用 Let's Encrypt 憑證的 nginx 網站後方,就能以 SSH jail 指向 journal 的相同方式,讓 Fail2ban filter 讀取其存取日誌。
失效情況與實際顯示的完整字串
「Have not found any log file for sshd jail」,且 Fail2ban 不會啟動。 這是舊版 auth.log 問題。在 Ubuntu 24.04 上,只有下列情況才會遇到:某些設定覆寫了套件提供的預設值、安裝了 pip 但沒有 defaults-debian.conf、容器沒有 journal,或將多餘的 backend = auto 貼到 jail.local。在沒有 /var/log/auth.log 的檔案後端上,sshd jail 找不到其日誌,整個 daemon 便會中止。fail2ban.log 會顯示:
ERROR Failed during configuration: Have not found any log file for sshd jail由於這是致命錯誤,服務完全不會啟動,接著 fail2ban-client status 會回報下游症狀:
ERROR Failed to access socket path: /var/run/fail2ban/fail2ban.sock. Is fail2ban running?這行「socket path」不表示 Fail2ban 損壞,而是表示某個 jail 找不到日誌,導致 Fail2ban 根本沒有啟動。在 [DEFAULT] 中設定 backend = systemd;Ubuntu 套件已替你完成此設定,因此兩則訊息會同時修正。
Jail 處於啟用狀態,但 Total failed 從未變動。 daemon 正在執行,也正在讀取 journal,但實際失敗事件持續累積在 journalctl -u ssh,計數器卻停留在 0。先排除最常見的原因:你是從列在 ignoreip 的位址進行測試,因此依設計,你自己的失敗嘗試會被排除。如果不是這個原因,可能是你使用的 OpenSSH 建置版本將每個連線的 worker 設為 sshd-session(9.8 及更新版本);其 journal _COMM 是 sshd-session,而不是 sshd,因此套件提供的比對規則無法命中。請在 [sshd] 區塊中放寬比對規則:
[sshd]
enabled = true
backend = systemd
journalmatch = _SYSTEMD_UNIT=ssh.service + _COMM=sshd + _COMM=sshd-session重新啟動,接著從不在 ignoreip 中的位址故意讓登入失敗,確認 Total failed 終於增加。
你封鎖了自己:Connection refused。 你沒有將自己的位址加入 ignoreip,測試了幾次錯誤登入,現在會看到:
ssh: connect to host 10.0.0.10 port 22: Connection refused這是拒絕連線,而不是無聲逾時,表示 nftables action 的預設 reject verdict 正在生效,且套用到了你自己。請依照步驟 6 修正:從另一個未遭封鎖的位址開啟工作階段解除封鎖,或使用 provider console;從遭封鎖位址建立且已開啟的工作階段也會凍結。接著將你的位址加入 ignoreip,避免再次發生。
Fail2ban 表示某個位址已遭封鎖,但該位址仍可連線。 status sshd 中的計數器持續增加,但該位址仍可連到 port 22。這表示封鎖動作與防火牆不相符。在 Ubuntu 24.04 上,幾乎總是因為你以舊指南中的 banaction = iptables-multiport 覆寫了原本可運作的 banaction = nftables,而該主機沒有 iptables 層。fail2ban.log 會顯示:
fail2ban.actions [812]: ERROR Failed to execute ban jail 'sshd' action 'iptables-multiport'刪除該覆寫設定,讓套件提供的 nftables action 生效。或者,如果你完全透過 ufw 管理防火牆,且希望封鎖規則顯示在 ufw 中,請在 [DEFAULT] 設定 banaction = ufw。重新啟動,並使用 sudo nft list ruleset | grep f2b 確認規則已出現。
編輯 jail.local 後 Fail2ban 不會啟動。 拼字錯誤、多餘的標題或錯誤的時間值,都可能使服務拒絕啟動。請先要求 Fail2ban 檢查設定,再啟動服務:
sudo fail2ban-client -t它會指出發生問題的檔案與 jail,例如 Errors in jail 'sshd'. Skipping...,讓你直接修正來源,而不必猜測。
FAQ
Ubuntu 24.04 預設安裝的 Fail2ban 真的會封鎖 SSH 攻擊嗎?
會。套件包含 /etc/fail2ban/jail.d/defaults-debian.conf,會啟用 sshd jail,設定 backend = systemd,讓它讀取 systemd journal,而不是不存在的 /var/log/auth.log;同時設定 banaction = nftables,讓封鎖透過 Ubuntu 實際使用的防火牆套用。單純執行 apt install fail2ban,就能從首次開機起保護 SSH。使用 sudo fail2ban-client status sshd 確認,並查看 Total failed 是否為非零值。
為什麼 Fail2ban 沒有在我的主機上封鎖任何來源?
請依序排除3個常見原因。您可能是從 ignoreip 中的位址進行測試;這些位址依設計會獲豁免。您可能依照舊指南,將 backend = auto 貼到 jail.local,覆寫了可正常運作的預設值;在沒有 auth.log 的映像檔上,這會導致 journal 無法讀取。您也可能位於完全沒有 systemd journal 可讀取的容器中。檢查 fail2ban-client status sshd 中的 Total failed:如果 journalctl -u ssh 顯示確實的失敗記錄時,該值仍未增加,表示 jail 正在讀取錯誤的位置。
如何解除對自己 IP 位址的封鎖?
執行 sudo fail2ban-client set sshd unbanip YOUR.IP.HERE;成功時會回傳 1。也可以執行 sudo fail2ban-client unban --all 清除所有封鎖。如果您已被鎖在 SSH 外,請使用供應商提供的 Web 或 VNC 主控台執行相同命令。封鎖會拒絕從您位址傳送到連接埠22的所有封包,因此即使是已建立的工作階段也會停止運作。接著將您的位址加入 ignoreip,避免再次被封鎖。
jail.conf 與 jail.local 有何差異?
jail.conf 儲存 Fail2ban 的上游預設值,且每次套件升級都會覆寫,因此其中的任何修改最終都會遺失。Debian/Ubuntu 套件會透過 jail.d/defaults-debian.conf 疊加自己的設定。您的修改應放在 jail.local;該檔案最後讀取,會覆寫前兩者的設定,而且不會在升級時被修改。請將 jail.conf 保留為唯讀參考。
Fail2ban 會取代以金鑰為基礎的 SSH 驗證嗎?
不會。Fail2ban 會限制來自單一位址的重複失敗嘗試速率;如果攻擊者以分散且緩慢的方式猜測,讓每個位址都低於門檻,Fail2ban 對此無法發揮作用。僅限金鑰驗證(PasswordAuthentication no)可直接讓密碼猜測失效,Fail2ban 則能減少日誌雜訊,並及早排除掃描程式。兩者應同時使用;理想情況下,SSH 也不應直接暴露在公用網際網路上。