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 不會驗證任何人、不會加密任何內容,也無法阻止單次且有意的登入嘗試;它只能處理來自同一來源的重複嘗試。它是雜訊過濾器與速率限制工具,不是鎖定機制。它的作用是讓針對 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。」這項建議只適用於部分映像檔。標準 Ubuntu 24.04 伺服器或雲端映像檔仍會安裝 rsyslog。其預設規則會將內容寫入 auth,authpriv.* 和 /var/log/auth.log,因此在大多數 VPS 上,SSH 失敗記錄也會出現在該檔案中,以及 systemd journal 中。精簡映像檔(Ubuntu 24.04 minimal cloud image 未附帶 rsyslog)和大多數容器只會將 SSH 記錄寫入 journal;在這些環境中,文字檔確實不存在。無論是哪種情況,Ubuntu 24.04 的 Fail2ban 套件都已處理這項差異。套件會加入 /etc/fail2ban/jail.d/defaults-debian.conf。伺服器實際執行的是該檔案,而不是上游預設值:
[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 實際使用的防火牆,而不是傳統的 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,覆寫了原本可正常運作的預設值。第一種和第三種情況,只有在映像檔沒有 rsyslog 時才會導致 SSH 封鎖失效,例如精簡映像檔;因為在 rsyslog 存在的環境中,檔案後端可以找到 /var/log/auth.log 並正常運作。失效模式一節會精確說明每種情況的表現。
步驟 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。請勿編輯該檔案。套件升級可能會取代這個檔案,正如檔案標頭本身所警告的內容,您所做的修改也可能遺失。Fail2ban 會依固定順序讀取檔案:先讀取 jail.conf,接著依字母順序讀取 jail.d/*.conf,再讀取 jail.local,最後依字母順序讀取 jail.d/*.local;後讀取的值會覆寫先前的值。因此,jail.local 會覆寫套件提供的 defaults-debian.conf;但您放入 jail.d/ 的任何 *.local 檔案都會在其後讀取,並再次覆寫該值。請將覆寫設定集中在同一處,才能確認目前生效的值。.local 檔案由您管理,套件升級不會修改它。同樣的規則也適用於 filter:*.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: 203.0.113.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 203.0.113.66 - 2026-07-15 10:31:40
2026-07-15 10:31:44,118 fail2ban.actions [812]: NOTICE [sshd] Ban 203.0.113.66若不想等待,可手動封鎖文件專用的位址,切勿使用自己的位址,以端對端確認整套機制正常運作。203.0.113.66 位於 TEST-NET-3,這是保留給文件使用的網段,因此不會是實際主機,也不會是供應商網路上的私有位址:
sudo fail2ban-client set sshd banip 203.0.113.66畫面會輸出 1,而該位址會在 fail2ban-client status sshd 的 Banned IP list 下方出現。現在確認防火牆中確實存在封鎖規則。在 Ubuntu 24.04 上使用的是 nftables,而不是 iptables:
sudo nft list table inet f2b-table您會看到名為 addr-set-sshd 的集合,其中包含 203.0.113.66;也會看到 f2b-chain 鏈,拒絕該集合中的任何來源位址。若 fail2ban-client 顯示某個位址已遭封鎖,但 nft list 中沒有任何項目,表示您的封鎖動作與防火牆不相容。請參閱失敗模式中的 nftables/iptables 說明。
步驟 6:解除對自身的封鎖,並在被鎖定時復原
如果不慎封鎖了不該封鎖的位址,包括自己的位址,請將其移除:
sudo fail2ban-client set sshd unbanip 203.0.113.66成功時會回傳 1。若要清除所有 jail 中的所有封鎖:
sudo fail2ban-client unban --all不要依賴已開啟的 SSH 工作階段來保護自己:nftables 封鎖會拒絕來自該封鎖位址、前往連接埠 22 的所有封包,包括已建立連線的封包。因此,封鎖生效的瞬間,現有工作階段也會凍結。如果封鎖了自己的位址,且沒有 ignoreip 項目,您將無法登入,直到封鎖期限屆滿。請透過服務供應商的 Web 主控台(VNC 或序列主控台)復原;該主控台不會經過 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 上,只有在不存在 /var/log/auth.log 時才會遇到,例如映像檔不含 rsyslog(精簡映像檔或容器),而且系統日誌未被讀取:安裝了 pip 但沒有 defaults-debian.conf、容器沒有日誌,或是將多餘的 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 正在執行,系統日誌也正在讀取,但實際失敗次數持續累積在 journalctl -u ssh,計數器卻停在 0。先排除最常見的原因:你是從列在 ignoreip 中的位址進行測試,因此依設計會排除你自己的失敗嘗試。如果不是這個原因,可能是使用了 OpenSSH 9.8 以上版本,其中每個連線的 worker 是 sshd-session,其日誌中的 _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 判定正在生效。請依照步驟 6 修正:從不同且未遭封鎖的位址建立工作階段解除封鎖,或使用 provider console。從遭封鎖位址建立且已開啟的工作階段也會凍結。接著將你的位址加入 ignoreip,避免再次發生。
Fail2ban 顯示某個位址已遭封鎖,但該位址仍可連線。 status sshd 中的計數器持續增加,但該位址仍可連接到 22 埠。這表示封鎖 action 與防火牆不相容。在 Ubuntu 24.04 上,幾乎總是因為你在沒有 iptables 層的主機上,使用舊指南複製的 banaction = iptables-multiport 覆寫了可正常運作的 banaction = nftables。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,因此無論映像檔是否寫入 /var/log/auth.log,都會讀取 systemd journal;並設定 banaction = nftables,讓封鎖規則透過 Ubuntu 的實際防火牆套用。單純執行 apt install fail2ban,從第一次開機起就能保護 SSH。執行 sudo fail2ban-client status sshd 確認,並查看 Total failed 是否為非 0 值。
為什麼 Fail2ban 沒有在我的主機上封鎖任何連線?
請依序排除 3 個常見原因。您測試時使用的位址可能位於 ignoreip,這些位址依設計會獲豁免。您也可能根據舊指南,將 backend = auto 貼入 jail.local,覆寫了原本可正常運作的預設值;如果映像檔沒有 rsyslog,因此也沒有 auth.log,這會使 SSH 封鎖失效。另一個可能是您位於沒有任何 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 登入,請使用供應商提供的網頁或 VNC 主控台執行相同命令。封鎖會拒絕來自您位址、目的地為連接埠 22 的所有封包,因此即使連線已建立,現有的工作階段也會停止運作。接著將您的位址加入 ignoreip,避免再次發生。
jail.conf 和 jail.local 有什麼差異?
jail.conf 存放 Fail2ban 的上游預設值,套件升級時可能會被替換,因此直接修改該檔案有遺失風險。Debian/Ubuntu 套件會透過 jail.d/defaults-debian.conf 在這些設定之上加入自己的設定。您應將變更放在 jail.local;該檔案會在前兩者之後讀取,並覆寫其設定,套件升級也不會修改它。只有 jail.d/ 內的 *.local 檔案會更晚讀取,因此不要在該目錄留下多餘的檔案。請將 jail.conf 保留作為唯讀參考。
Fail2ban 會取代以金鑰為基礎的 SSH 驗證嗎?
不會。Fail2ban 會限制單一位址的重複失敗嘗試;對於緩慢且分散式的猜測攻擊,如果每個位址都低於門檻,Fail2ban 無法防禦。僅使用金鑰驗證(PasswordAuthentication no)可直接使密碼猜測失效,Fail2ban 則可進一步減少日誌雜訊,並提早封鎖掃描器。兩者應同時使用;理想情況下,還應完全避免讓 SSH 暴露在公開網際網路上。