Ubuntu 24.04 安裝 Fail2ban 教學:防禦 SSH 暴力破解
在 Ubuntu 24.04 使用 apt install 安裝 Fail2ban 即可自動防禦 SSH 攻擊。本文介紹如何透過 fail2ban-client status sshd 確認狀態,並解決 Total failed 數值維持為 0 的常見問題,確保系統能正確讀取 systemd journal 日誌。
Fail2ban 的實際功能
Fail2ban 是一個讀取日誌的守護行程 (daemon)。它會監控 SSH 驗證訊息;若單一來源位址在短時間內發生多次失敗,它會執行防火牆指令來暫時封鎖該位址。這就是其核心原理。其設定檔僅約 30 行,在 Ubuntu 24.04 上,只需執行單一 apt 指令即可完成安裝,在您進行任何編輯前即可提供保護。
請明確了解其功能範圍。Fail2ban 不負責驗證身份,不負責加密,也無法阻止單次且具備決心的登入嘗試——它僅能阻擋來自同一來源的重複嘗試。它是一個雜訊過濾器與速率限制器 (rate limiter),而非鎖頭。其任務是停止針對 port 22 的持續背景掃描,以避免浪費 CPU、頻寬與日誌空間,並減緩必須逐一從單一位址發動攻擊的攻擊者。
Fail2ban 無法取代的機制
Fail2ban 是第三層防禦,而非第一層。若您的伺服器仍接受 SSH 密碼驗證,分散在數千個位址的 botnet 仍能持續嘗試猜測,因為每個位址的嘗試次數皆低於 ban threshold,從未觸發封鎖機制。針對此問題的真正防禦手段是僅限金鑰驗證 (key-only authentication),這能讓密碼猜測變得不可能,無論嘗試次數多少。在僅限金鑰驗證之上使用 Fail2ban 有兩項功能:它可以清除日誌中的 brute-force 雜訊,並能提早驅逐掃描器,使其停止對 port 的持續攻擊。請將其視為深度防禦 (defence in depth) 的一部分。它位於金鑰驗證與 firewall 之後,而非位於其前方。
前置作業與 Ubuntu 24.04 的現況
您需要一台執行 Ubuntu 24.04 且具備 root 或 sudo 權限的 VPS,並已設定好 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,且伺服器實際執行的是該檔案,而非原始預設值:
[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 brute-force 攻擊。您大部分的工作僅在於確認此狀態、調整策略,並確保不會將自己鎖在系統外。
舊有的 auth.log 陷阱在以下三種情況仍會發生,請務必辨識:您使用 pip 而非 apt 安裝 Fail2ban,導致缺少 defaults-debian.conf;您位於無權限的 container 中且無法讀取 systemd journal;或者您參考了舊教學並將 backend = auto 貼入您的 jail.local,進而覆蓋了原本可用的預設設定。故障排除章節會詳細說明各項錯誤的表現。
Step 1: 安裝並確認已啟動阻擋功能
sudo apt update
sudo apt install -y fail2banUbuntu 24.04 內建 Fail2ban 1.0.2,且該套件將 python3-systemd 列為必要依賴項目,因此 journal backend 已具備所需環境。該服務會自動啟用並啟動:
sudo systemctl status fail2ban您需要 active (running)。接著檢查正在運作中的 jail:
sudo fail2ban-client status sshd若公用 VPS 已連網數分鐘,通常會看到失敗次數統計與 IP 被阻擋的紀錄,因為網路掃描會持續掃描 port 22。這證明預設配置可正常運作。接下來您只需進行優化,而非從零開始建置。
Step 2: Edit jail.local,切勿編輯 jail.conf
Fail2ban 將其原始預設值儲存在 /etc/fail2ban/jail.conf。請勿編輯該檔案。套件中的任何 apt upgrade 都可能取代該檔案,且您的修改會在無預警的情況下消失。Fail2ban 依據固定順序讀取檔案:先讀取 jail.conf,接著是 jail.d/ 中的所有內容,最後是 jail.local,並以最後讀取的數值為準。.local 檔案由使用者掌控,且套件升級不會更動此檔案。此規則同樣適用於 filters,其中 *.local 檔案會覆蓋內建的 filter.d/*.conf。
因此,您只需撰寫一個簡短的 jail.local,僅覆蓋您需要的少數設定,並保留 jail.conf 與套件內建的 jail.d/defaults-debian.conf 以供參考。
Step 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,然後將其貼入檔案中:
Step 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 單元實際上是 ssh.service,但內建的 filter 也會比對 _COMM=sshd;此外,OpenSSH 在 24.04 版本中會從名為 sshd 的程序記錄錯誤,因此比對功能正常。此細節僅在您使用較新版本的 OpenSSH(9.8 或更高版本,其單次連線工作程序為 sshd-session)時才重要;故障排除章節已涵蓋此情況。
Step 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若不想等待,可以手動封鎖一個文件地址來測試整個流程 —— 切勿封鎖您自己的地址:
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 的 set,以及一個會拒絕該 set 中所有來源的 chain f2b-chain。如果 fail2ban-client 顯示地址已被封鎖,但 nft list 中卻沒有任何內容,代表您的封鎖動作與防火牆不匹配 —— 請參閱 failure modes 中的 nftables/iptables 說明。
Step 6: 解除封鎖自身,並在被鎖定時進行復原
若您錯誤地封鎖了不該封鎖的位址(例如您自己的位址),請將其移除:
sudo fail2ban-client set sshd unbanip 10.0.0.66成功執行時會回傳 1。若要清除所有 jail 中的所有封鎖紀錄:
sudo fail2ban-client unban --all請勿依賴現有的 SSH 連線來救命:nftables 封鎖會拒絕來自被封鎖位址的所有傳送到 port 22 的封包(包含已建立的連線),因此現有連線會在封鎖生效的瞬間凍結。若您封鎖了自己且沒有 ignoreip 紀錄,您將會被鎖定直到封鎖過期;請透過供應商的網頁控制台(VNC 或 serial)進行復原,因為該方式不經過 SSH,您可以選擇等待 bantime 結束,或直接在該控制台執行解除封鎖指令。
Step 7: 讓封鎖持久化並升級
Fail2ban 會將活動封鎖儲存在 /var/lib/fail2ban/fail2ban.sqlite3 的 SQLite 資料庫中,因此在服務重啟或系統重新開機後,封鎖狀態仍會保留,不會遺失。您先前新增的 bantime.increment 設定會讓重複違規者面臨升級的懲罰,封鎖時間會從 1 小時逐漸增加至約 1 週。
若要實施全系統的「三次警告」政策,Fail2ban 提供了一個 recidive jail,它會監控自身的 /var/log/fail2ban.log,並針對在所有 jail 中被重複封鎖的 IP 位址執行長期封鎖。由於您的 [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,而紀錄並不在該處。
Step 8: 搭配僅限金鑰的 SSH,或更佳的 VPN 方案
Fail2ban 必須搭配金鑰驗證(key authentication)才能發揮作用。請在 /etc/ssh/sshd_config.d/ 下的置換檔(drop-in file)中(例如 /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 應用程式已部署於 使用 Let's Encrypt 憑證的 nginx 網站 後方,即可比照 SSH jail 指向 journal 的方式,將 Fail2ban 篩選器指向該服務的 access log。
錯誤模式與您會看到的精確字串
出現 "Have not found any log file for sshd jail",且 Fail2ban 無法啟動。 這是舊有的 auth.log 問題。在 Ubuntu 24.04 上,只有在覆蓋了套件預設設定時才會發生:例如沒有 defaults-debian.conf 的 pip 安裝、沒有 journal 的 container,或是貼錯位置的 backend = auto 導致 jail.local 錯誤。若使用沒有 /var/log/auth.log 的 file backend,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 找不到日誌而導致服務從未啟動。在 [DEFAULT] 中設定 backend = systemd(Ubuntu 套件預設已為您設定)即可同時修復這兩個訊息。
Jail 處於 active 狀態,但 Total failed 從未變動。 Daemon 正在執行且正在讀取 journal,但 journalctl -u ssh 中的實際失敗次數不斷增加,而計數器卻停留在 0。首先排除明顯原因:您正從 ignoreip 列出的位址進行測試,因此您的失敗會被設計為排除在外。若非如此,您使用的 OpenSSH 版本中,每個連線的 worker 為 sshd-session (9.8 或更高版本),其 journal _COMM 是 sshd-session 而非 sshd,導致預設的 match 規則無法匹配。請擴大 [sshd] 區塊中的 match 範圍:
[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 進行修復:從另一個未被封鎖的位址或供應商控制台進行 session 登入來解除封鎖;請注意,從已被封鎖位址開啟的 session 也會凍結。接著將您的位址加入 ignoreip 以防止再次發生。
Fail2ban 顯示位址已被封鎖,但仍可連線。 status sshd 中的計數器在增加,但該位址仍能連線至 port 22。這是 ban-action 與 firewall 不匹配的問題。在 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 管理防火牆並希望封鎖規則顯示在其中,請在 [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 是否大於 0。
為什麼 Fail2ban 沒有封鎖我主機上的任何攻擊?
請依序排除以下三個常見原因。首先,您可能正從 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 主控台執行相同指令。封鎖會拒絕來自您位址的所有 port 22 封包,因此即使是已建立的連線也會中斷。接著請將您的位址加入 ignoreip 以防止再次被封鎖。
jail.conf 與 jail.local 有何差異?
jail.conf 包含 Fail2ban 的原始預設值,且在每次套件升級時都會被覆寫,因此任何修改最終都會遺失。Debian/Ubuntu 套件會透過 jail.d/defaults-debian.conf 疊加其自身的設定。您的修改應寫在 jail.local,該檔案最後被讀取並擁有最高優先權,且升級時不會被更動。請將 jail.conf 視為唯讀參考。
Fail2ban 可以取代金鑰式 SSH 驗證嗎?
不行。Fail2ban 是針對單一位址的重複失敗進行頻率限制;對於每個位址都低於門檻的慢速分散式攻擊則無效。僅使用金鑰驗證 (PasswordAuthentication no) 能完全杜絕密碼猜測,而 Fail2ban 則用於減少日誌雜訊並及早驅逐掃描器。建議同時使用兩者,並理想情況下將 SSH 完全關閉於公網。