Skip to content
View in the app

A better way to browse. Learn more.

PHP论坛人

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Debian 13 原生防火牆 nftables、Fail2ban入侵防護/Fail2ban Part 1

Featured Replies


Debian 13 原生防火牆 nftables、Fail2ban入侵防護/Fail2ban Part 1



******************************************************
Fail2ban Part 1

等待LNMP服務都安裝設置完,再做 Part 2
******************************************************



---------------
前言
---------------

為何選擇原生 nftables?

相較於 iptables、ufw 或 firewalld,nftables 具備以下優勢:

雙棧統一管理:使用 inet 位址族,一套規則同時覆蓋 IPv4 與 IPv6,不會有遺漏

原子性載入:規則集一次性套用,不會出現套用到一半的中間狀態

內建計量器:速率限制更精確,無需額外核心模組

語法預驗證:nft -c -f 可在套用前驗證語法,大幅降低鎖死SSH的風險

Fail2ban 整合:與 Fail2ban 1.1.0+ 完整整合,可動態封鎖攻擊IP



IPv4 與 IPv6 雙棧的必要性

許多管理員只設定 IPv4 防火牆,卻忽略了 IPv6。若伺服器持有 IPv6 位址而未設定對應規則,IPv6 流量將完全不受保護,形同開了一扇隱形後門

本文使用 inet 位址族,同一套規則自動涵蓋 IPv4 與 IPv6,杜絕此類遺漏



為何採用自訂 firewall.service 而非 nftables.service?

本文採用自訂 firewall.service 驅動腳本,而非直接依賴 nftables.service 載入靜態設定檔,原因如下:

腳本在每次啟動時動態建構規則,可整合環境變數、條件判斷與 Shell 邏輯

Before=network-pre.target 確保規則在網路啟動前就位,不留空窗期

方便日後擴充:直接修改 Shell 腳本即可,語法直觀



------------------
整體流量架構
------------------


外部流量
   │
   ▼
nftables (inet filter)
   ├── INPUT chain
   │     ├── 黑名單 set (f2b-blacklist4/6、blacklist4/6) → DROP  ← 最高優先
   │     ├── lo 介面 → ACCEPT
   │     ├── 已建立連線 (established/related) → ACCEPT           ← 效能優化
   │     ├── 無效封包 (invalid state) → DROP
   │     ├── 管理員 IP 白名單 → ACCEPT                           ← 無任何限速
   │     ├── 私有網段白名單 → ACCEPT                             ← VPC/監控/LB
   │     ├── 異常 TCP flags → DROP                               ← 防掃描/畸形封包
   │     ├── ICMPv4 速率限制 → ACCEPT
   │     ├── ICMPv6 必要類型 → ACCEPT                            ← NDP,IPv6 必需
   │     ├── SSH 速率限制 (10/min) → ACCEPT / DROP
   │     ├── Web (80/443) → ACCEPT                               ← 完全開放
   │     ├── 管理後台 (888) → 僅限白名單 IP
   │     └── 其餘 → LOG + DROP                                   ← 限速 2/min 避免日誌洪流
   ├── FORWARD chain → DROP                                       ← 此主機非路由器
   └── OUTPUT chain → ACCEPT                                      ← 主機主動對外連線
         │
         ▼
    Fail2ban(持續掃描日誌,偵測暴力攻擊)
         └── 操作 nftables set,動態加入封鎖 IP(含 timeout 自動過期)





---------------------------
持久化黑名單生命週期
---------------------------


Fail2ban 啟動
    └─> actionstart
           ├─ 建立 set(若不存在,冪等操作)
           ├─ flush set(清空避免重複累積)
           └─ 從 .ipset 檔案恢復黑名單(含 bantime timeout)

偵測到攻擊
    └─> actionban
           ├─ nft add element(加入 set,設定 timeout)
           └─ 追加寫入 .ipset 持久化檔案

Ban 過期或手動解封
    └─> actionunban
           ├─ nft delete element
           └─ sed 移除 .ipset 對應行

Fail2ban 正常停止
    └─> actionstop
           ├─ 從 nft 讀取目前黑名單
           └─ 原子性寫入 .ipset(.new 暫存 → 正式)

Cron(每小時整點)
    └─> 從 nft 讀取目前 set → 覆寫 .ipset
           └─ 確保強制重啟時(reboot、核心 panic)也能保留最近 1 小時內的封鎖



為何需要 Cron 備份?

Fail2ban 的 nftables set 是記憶體狀態。actionstop 只在 Fail2ban 正常停止時觸發

若發生強制重啟或電源中斷,actionstop 不會執行,若無 Cron 備份,黑名單將全部消失



--------------------
操作前安全提醒
--------------------

錯誤的防火牆規則會導致SSH連線立即中斷,操作前請務必閱讀


開啟帶外管理備援:在套用規則前,請先透過雲端主控台開啟 VNC / Serial Console / IPMI 等帶外管理通道,確保即使SSH中斷也能進行補救

記下所有管理IP(含 IPv6):務必將目前的管理IP(包含 IPv6 位址)加入允許清單,缺一不可。動態IP用戶每次操作前都應重新確認

善用測試模式:腳本提供 test 指令,規則套用後 120 秒自動復原,可安全驗證而不影響後續連線。務必先用 test,確認SSH正常後再用 start 正式套用

雲端內網IP需加入白名單:AWS、GCP、阿里雲、騰訊雲、Hetzner 等平台的內網 IP(如 10.x.x.x)若有負載平衡器或監控系統

需填入 PRIVATE_NETS_V4,否則健康檢查可能被誤封

修改前備份:重要資料請在操作前完成備份





--------------------------
事前準備:收集必要資訊
--------------------------

在開始前,請收集以下資訊並記錄備用


查看目前SSH連線的來源IP

確認你目前透過哪個IP 連入伺服器(包含 IPv6),此IP必須填入防火牆白名單
ss -tnp | grep :22 | grep ESTAB



查詢本機對外 IPv4 位址(必填)
curl -4 ifconfig.me


查詢本機對外 IPv6 位址(若有則填)
curl -6 ifconfig.me


請記下輸出結果,稍後需填入防火牆腳本的 ADMIN_IP4 與 ADMIN_IP6




確認 IPv6 是否已啟用(預期輸出為 0,代表已啟用)
sysctl net.ipv6.conf.all.disable_ipv6



確認本機的 IPv6 位址
ip -6 addr show



查詢 VPS 私有IP

雲端平台的負載平衡器、監控系統會透過私有IP通訊,需加入白名單
ip addr show | grep 'inet ' | grep -v 127.0.0.1




---------------------------------
安裝 nftables 並清除衝突工具
---------------------------------

更新套件清單並升級
apt update -y && apt upgrade -y



安裝 nftables 防火牆主體、conntrack 用於連線追蹤統計(firewall.sh stats 指令會用到)
apt install -y nftables conntrack



確認nftables版本,預期 nftables v1.1.3 以上
nft --version






-------------------------
停用衝突的防火牆工具
-------------------------

同時啟用多套防火牆工具會造成規則衝突,請依實際安裝情況停用

2>/dev/null || true 的作用:若該服務本就不存在,指令不會報錯中止




停用 ufw(若有安裝)
systemctl disable --now ufw 2>/dev/null || true



停用 firewalld(若有安裝)
systemctl disable --now firewalld 2>/dev/null || true




停用 iptables / ip6tables(若有安裝)

systemctl disable --now iptables 2>/dev/null || true


systemctl disable --now ip6tables 2>/dev/null || true



確認無殘留規則,若有殘留 iptables 規則,執行以下清空

iptables -F 2>/dev/null || true


ip6tables -F 2>/dev/null || true




-------------------------------
清空 nftables 預設設定檔
-------------------------------

nftables.service 預設在開機時載入 /etc/nftables.conf

後續我們將停用 nftables.service,但為了防止它被意外啟用時載入空規則而清掉防火牆,建議將此檔案改為僅執行 flush ruleset:


以下幾行一起貼上

cat > /etc/nftables.conf << 'EOF'
#!/usr/sbin/nft -f
# 此檔案由 firewall.service 接管,請勿直接編輯
# 若 nftables.service 意外被啟用,flush ruleset 可避免載入錯誤規則
flush ruleset
EOF

--------------------

建立防火牆腳本

--------------------

建立目錄

mkdir -p /usr/local/bin

建立防火牆腳本

vi /usr/local/bin/firewall.sh

firewall.sh

貼入以下完整內容,務必修改使用者配置區塊

ADMIN_IP4="請改為您的IPv4"

ADMIN_PORT="888"

# 內網白名單(請根據 ip addr 查詢後填寫)

PRIVATE_NETS_V4=""

PRIVATE_NETS_V6=""

儲存檔案並離開vi編輯器

按 Esc,輸入 :wq,按 Enter

----------------
設定權限
----------------

設定腳本權限 (700 表示僅 root 可讀寫執行,防止其他使用者查看或修改)

chmod 700 /usr/local/bin/firewall.sh


chown root:root /usr/local/bin/firewall.sh






--------------------------------
測試防火牆
--------------------------------

執行測試模式
/usr/local/bin/firewall.sh test



測試模式流程:
1. 產生規則至暫存檔
2. 語法預驗證(通過才繼續)
3. 原子性載入規則(無空窗期)
4. 啟動 120 秒緊急還原計時器
5. 若 SSH 正常 → 按 Enter 取消還原並永久保留規則
6. 若 SSH 異常中斷 → 120 秒後自動還原至套用前狀態



---------------------------------------
另開終端機確認連線 (測試期間進行)
---------------------------------------

在測試期間,另開一個終端機視窗進行以下驗證


測試SSH連線 (應成功)
ssh 你的伺服器IP


測試 IPv4 對外連線 (應成功)
ping -c 3 8.8.8.8


測試 IPv6 對外連線(若有 IPv6)
ping6 -c 3 2001:4860:4860::8888




--------------------------
正式套用規則
--------------------------

確認測試無誤後,正式套用規則

/usr/local/bin/firewall.sh start





---------------------
確認規則已套用
---------------------

查看完整規則集
nft list ruleset



查看 input chain
nft list chain inet filter input




查看統計資訊
/usr/local/bin/firewall.sh stats



----------------------------------------
建立 systemd 服務(開機自動啟動)
----------------------------------------

本文採用自訂 firewall.service 驅動腳本,而非直接依賴 nftables.service 載入靜態設定


建立
vi /etc/systemd/system/firewall.service



貼上以下內容


[Unit]
Description=Custom nftables Firewall (IPv4 + IPv6 Dual Stack)
After=network-pre.target
Before=network.target network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/firewall.sh start
ExecStop=/usr/local/bin/firewall.sh stop
RemainAfterExit=yes
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target





儲存檔案並離開vi編輯器
按 Esc,輸入 :wq,按 Enter




------------------
啟用並啟動服務
------------------

重新載入 systemd 設定(每次修改 .service 檔案後必須執行)
systemctl daemon-reload



設定開機自動啟動
systemctl enable firewall.service




立即啟動
systemctl start firewall.service




確認狀態,(應顯示 active (exited),oneshot 類型服務執行完畢後正常顯示此狀態)
systemctl status firewall.service




查看啟動日誌
journalctl -u firewall.service --no-pager




---------------------------------------
停用 nftables.service 避免衝突
---------------------------------------

重要:nftables.service 預設在開機時載入 /etc/nftables.conf

若讓它與自訂 firewall.service 並存,可能發生規則衝突或重複載入,必須停用


停用 nftables.service

systemctl disable nftables.service


systemctl stop nftables.service



確認已停用,預期輸出 disabled
systemctl is-enabled nftables.service

-----------------------------------

持久化核心參數 (sysctl)

-----------------------------------

防火牆腳本本身不含 sysctl 調整。sysctl -w 的臨時調整重開機後會恢復預設值,需建立設定檔以持久化

建立

vi /etc/sysctl.d/99-hardening.conf

99-hardening.conf.txt

貼上內容

儲存檔案並離開vi編輯器

按 Esc,輸入 :wq,按 Enter

----------------------
立即套用並驗證
----------------------


立即套用
sysctl --system



驗證,應顯示: = 1
sysctl net.ipv4.tcp_syncookies



驗證,應顯示: = 0
sysctl net.ipv4.conf.all.accept_redirects




-----------------
安裝Fail2ban
-----------------

Fail2ban 持續掃描系統日誌,偵測到多次登入失敗時,自動將來源IP加入nftables封鎖規則,提供動態的入侵防護

同時安裝 whois 以便查詢被封鎖IP的WHOIS資訊,方便排查攻擊來源


apt update -y


apt install -y fail2ban whois





確認版本,預期 Fail2Ban v1.1.0 以上
fail2ban-client --version

------------------------------------------------

設定 Fail2ban × nftables 整合 Action

------------------------------------------------

此設定檔讓 Fail2ban 直接操作 nftables 的 f2b-blacklist4 / f2b-blacklist6 set,並在重啟時從磁碟恢復黑名單

建立

vi /etc/fail2ban/action.d/nftables-set.conf

nftables-set.conf.txt

貼上以下內容(確認以下設置的內容,若你的VPS沒有IPv6,則設置 enable_ipv6 = false)

# 是否啟用 IPv6 支援

# 若伺服器確認無 IPv6 可設為 false,減少 nft 操作與潛在錯誤

enable_ipv6 = false

儲存檔案並離開vi編輯器

按 Esc,輸入 :wq,按 Enter

------------------
設定 jail.local
------------------

為何不直接修改 jail.conf?

/etc/fail2ban/jail.conf 是套件提供的預設設定,套件更新時會被覆蓋

正確做法是建立 /etc/fail2ban/jail.local,Fail2ban啟動時 .local 的設定會覆蓋 .conf,這樣可以在套件更新後保留你的自訂設定

建立

vi /etc/fail2ban/jail.local

jail.local.txt

貼上以下內容

修改 ignoreip 中的佔位文字(你的管理員IPv4、你的管理員IPv6、你VPS的私有IP網段)請替換為實際IP

不存在的項目直接刪除,不要留下佔位文字,否則 fail2ban-client -t 會報錯

儲存檔案並離開vi編輯器

按 Esc,輸入 :wq,按 Enter

-------------------------------
確認 nftables Sets 已建立
-------------------------------

在啟用 Fail2ban 之前,需確認 nftables 的 f2b-blacklist4 與 f2b-blacklist6 sets 已存在(由 firewall.sh start 建立)

若 sets 不存在,Fail2ban 啟動時 actioncheck 會失敗




確認 sets,應看到 f2b-blacklist4 與 f2b-blacklist6
nft list sets








-------------------------------------
設定 fail2ban.local(IPv6 選項)
-------------------------------------

簡單來說:加入 allowipv6 = auto 是為了讓 Fail2ban 能正確處理 IPv6 連線,避免 IPv6 的封鎖失效或產生錯誤

在較舊的 Fail2ban 版本中,如果沒有明確設定 allowipv6,當系統啟用 IPv6 時,可能會導致一些問題

auto 的意義:讓程式自己判斷

結論:加入 allowipv6 = auto 是最佳實務,讓 Fail2ban 自適應系統的網路設定,既能處理 IPv6 攻擊,又不會在無 IPv6 環境中出錯,確保封鎖規則完整生效






建立
vi /etc/fail2ban/fail2ban.local



貼入以下內容


[Definition]
# 選項:allowipv6
# 說明:允許 Fail2ban 使用 IPv6 介面
# 可選值:auto | yes | no
allowipv6 = auto





儲存檔案並離開vi編輯器
按 Esc,輸入 :wq,按 Enter






--------------------------
Cron 定期備份封鎖清單
--------------------------

Fail2ban 的 nftables set 是記憶體狀態,actionstop 雖然會在 Fail2ban 正常停止時將黑名單寫入磁碟

但若發生強制重啟(reboot、核心 panic、電源中斷),actionstop 不會被觸發

搭配 Cron 定期備份,可確保最多只損失 1小時 內的新增封鎖記錄





建立目錄
mkdir -p /var/lib/fail2ban




設置權限
chmod 750 /var/lib/fail2ban


chown root:root /var/lib/fail2ban



注意:/var/lib/fail2ban 應由 root 擁有並限制存取,避免非特權使用者竄改黑名單檔案

-----------------

建立備份腳本

-----------------

使用獨立腳本比直接在 crontab 中塞長指令更容易維護與排查

建立

vi /usr/local/bin/backup-blacklist.sh

backup-blacklist.sh

貼上內容

儲存檔案並離開vi編輯器

按 Esc,輸入 :wq,按 Enter

----------------------
設定腳本權限
----------------------

chmod 700 /usr/local/bin/backup-blacklist.sh


chown root:root /usr/local/bin/backup-blacklist.sh


----------------------------------
手動執行一次確認
----------------------------------

手動執行一次,確認無誤
/usr/local/bin/backup-blacklist.sh



確認備份結果已寫入,預期有兩個 .ipset 檔案

cd /var/lib/fail2ban/

ls -l



確認已有這 2個 備份檔
nftables-blacklist4.ipset
nftables-blacklist6.ipset







-----------------------
啟用Cron
-----------------------

啟用
systemctl enable --now cron



檢查狀態,確認已運行 active (running)
systemctl status cron





編輯 Cron 任務
crontab -e



在尾部 貼上以下內容


# =====================================
#  備份 Fail2ban 黑名單 相關動作
# =====================================

# 每小時整點備份 nftables Fail2ban 黑名單(IPv4 + IPv6)
0 * * * * /usr/local/bin/backup-blacklist.sh

# 每日凌晨 2:00 清理超過 10000 行的持久化檔案(防止異常成長)
# truncate 只截斷,不能移除過期IP;實務上 Fail2ban actionunban 會即時從檔案移除已解封IP
# 此任務作為最後防線,確保檔案大小可控
0 2 * * * for f in /var/lib/fail2ban/*.ipset; do [ -f "$f" ] && [ "$(wc -l < "$f")" -gt 10000 ] && tail -n 10000 "$f" > "$f.tmp" && mv "$f.tmp" "$f"; done







儲存檔案並離開vi編輯器
按 Esc,輸入 :wq,按 Enter




-------------------------
驗證
-------------------------

檢視目前所有的Cron任務
crontab -l





-----------------------------
設定 journald 持久化
-----------------------------

預設情況下,systemd-journald 日誌儲存在記憶體中(/run/log/journal),重開機後消失

設定持久化後,日誌會寫入磁碟(/var/log/journal),有利於事後追查攻擊記錄



mkdir -p /var/log/journal


systemd-tmpfiles --create --prefix /var/log/journal



編輯
vi /etc/systemd/journald.conf


找到並修改以下內容(位於 [Journal] 區塊內)


[Journal]

Storage=persistent

# 限制日誌佔用磁碟空間(2GB VPS建議500M)
SystemMaxUse=500M

# 保留7天日誌(604800 秒)
MaxRetentionSec=604800






儲存檔案並離開vi編輯器
按 Esc,輸入 :wq,按 Enter




說明:
SystemMaxUse=500M 限制日誌佔用磁碟空間,避免在 2GB RAM 的小型 VPS 上因磁碟不足造成問題

MaxRetentionSec=604800 保留 7天 日誌







-----------------------------
重啟 journald 使設定生效
-----------------------------


重啟
systemctl restart systemd-journald



確認日誌目錄已建立
ls /var/log/journal/




------------------------
啟用 Fail2ban
------------------------


測試設定檔語法,預期輸出:OK: configuration test is successful
若出現錯誤,請仔細檢查 jail.local 中是否有留下未替換的佔位文字(如 你的管理員IPv4)

fail2ban-client -t






啟用
systemctl enable --now fail2ban



確認狀態,應顯示 active (running)
systemctl status fail2ban






-----------------------
重開機驗證
-----------------------


重開機
reboot



驗證所有服務是否正確自動啟動


確認防火牆服務狀態,應顯示 active (exited)
systemctl status firewall.service



確認 nftables.service 已停用,應顯示 disabled
systemctl is-enabled nftables.service




確認防火牆規則已自動載入

nft list ruleset


nft list chain inet filter input


nft list ruleset | grep -E "whitelist4|blacklist4|f2b"




確認 fail2ban 服務狀態,應顯示為 active (running)
systemctl status fail2ban.service



查看所有啟用的監獄
fail2ban-client status



查看 SSH 監獄狀態
fail2ban-client status sshd



確認 Fail2ban 已整合 nftables(兩個 set 應存在)

nft list set inet filter f2b-blacklist4


nft list set inet filter f2b-blacklist6




確認 Fail2ban 已整合 nftables,應顯示 f2b- 開頭的規則
nft list ruleset | grep f2b




確認白名單已正確載入(應顯示你的管理員IP 與 VPS 私有IP)
fail2ban-client get sshd ignoreip



核心參數驗證

已啟用,應顯示  = 1
sysctl net.ipv4.tcp_syncookies


已禁用,應顯示  = 0
sysctl net.ipv4.conf.all.accept_redirects




確認 SSH 服務監聽狀態(IPv4 + IPv6 雙棧)


ss -tlnp | grep :22


0.0.0.0:22 → IPv4 監聽
[::]:22         → IPv6 監聽

兩個都有才代表雙棧正常




備份腳本驗證

確認 Cron 每小時備份腳本正常運作

ls -lh /var/lib/fail2ban/*.ipset










------------------
測試封鎖功能
------------------

使用 RFC 5737 / RFC 3849 保留的文件用 IP 進行測試,不影響任何真實主機


手動封鎖測試 IPv4 (RFC 5737 文件用IP)
fail2ban-client set sshd banip 192.0.2.100


手動封鎖測試 IPv6 (RFC 3849 文件用IP)
fail2ban-client set sshd banip 2001:db8::100


查看監獄狀態 (Banned IP 欄位應顯示上述被封鎖的IP)
fail2ban-client status sshd



確認 nftables set 中已加入封鎖IP
nft list set inet filter f2b-blacklist4


nft list set inet filter f2b-blacklist6





測試完畢後,解除封鎖
fail2ban-client set sshd unbanip 192.0.2.100


fail2ban-client set sshd unbanip 2001:db8::100



---------------------
常見陷阱與排錯指南
---------------------

陷阱 1:IPv6 防火牆未設定

症狀:IPv4 連線正常,IPv6 流量完全開放

說明:使用 inet 位址族已同時涵蓋 IPv4 與 IPv6,本教學不會有此問題。若自行修改規則只用 ip 族,則需額外建立 ip6 族規則

驗證:
nft list ruleset | grep 'inet\|ip6'


應看到 table inet filter,代表雙棧皆受保護




陷阱 2:ICMPv6 被封鎖

症狀:IPv6 連線時通時不通,或無法取得 IPv6 位址 (SLAAC 失效)

解決:確認 IN_ICMPV6_ALLOWED 包含 133-136 (NDP 鄰居探索) 類型

nft list chain inet filter input | grep icmpv6





陷阱 3:雲端內網IP被封鎖

症狀:重開機後負載平衡器或監控系統無法連線 (常見於 AWS/GCP/Hetzner)

解決:在腳本的 PRIVATE_NETS_V4 填入對應的私有網段 (如 10.0.0.0/8)


查看VPS的私有IP
ip addr show | grep 'inet '




陷阱 4:忘記加入管理 IP

症狀:執行 firewall.sh start 後SSH立即斷線

解決:透過帶外管理 (VNC/Console) 執行:

nft flush ruleset

然後修正腳本中的管理IP再重新測試




陷阱 5:服務只監聽 IPv4

症狀:nftables 規則正確,但 IPv6 用戶仍無法連線論壇

解決:確認 NGINX 監聽 ::80 而非 0.0.0.0:80

ss -tlnp | grep :80

# :::80  → 雙棧(正確)

# 0.0.0.0:80 → 僅 IPv4(需修改 NGINX 設定)



NGINX 設定應包含:
listen 80;
listen [::]:80;
listen 443 ssl;
listen [::]:443 ssl;





陷阱 6:sysctl 參數重開機後消失

症狀:重開機後 net.ipv4.tcp_syncookies 回到預設值 0

解決:確認已完成 持久化核心參數sysctl的設定,建立 /etc/sysctl.d/99-hardening.conf






陷阱 7:nftables.service 與 firewall.service 衝突

症狀:重開機後規則被 nftables.service 覆蓋或清空

解決:確認已停用 nftables.service:

systemctl is-enabled nftables.service


若顯示 enabled,執行:
systemctl disable nftables.service






陷阱 8:Fail2ban 白名單未加入 VPS私有IP

症狀:Fail2ban 誤封鎖雲端平台的健康檢查IP,導致服務中斷

解決:在 jail.local 的 ignoreip 加入VPS分配的私有IP

查看VPS的私有IP
ip addr show | grep 'inet '


確認白名單
fail2ban-client get sshd ignoreip






陷阱 9:論壇靜態資源或 API 被速率限制誤封

症狀:正常用戶在短時間內大量載入頁面(CDN 回源、搜尋爬蟲)被速率限制

解決:針對已知的 CDN / 爬蟲 IP 段加入 PRIVATE_NETS_V4 白名單

例如 Cloudflare 最新 IP 段:https://www.cloudflare.com/ips/(需定期更新)






陷阱 10:網卡名稱不是 eth0

症狀:NAT 規則套用後,SNAT 功能無效

解決:Debian 13 在部分主機商的網卡名稱可能為 ens3、ens18、enp1s0 等,需先確認

ip route | grep default


腳本中 IFACE 變數已使用 ip route 自動偵測,若仍有問題請手動設定






陷阱 11:bantime 單位問題(nftables timeout)

症狀:Fail2ban 封鎖後封鎖時間不符預期,IP提早或延遲解封

說明:nftables timeout 接受帶單位的字串(如 3600s、1h)

nftables-set.conf 中 actionban 的 <bantime> 變數由 Fail2ban 傳入的是秒數整數,需在 action 中手動加上 s 後綴:

nft add element inet filter f2b-blacklist4 { <ip> timeout <bantime>s }




陷阱 12:Fail2ban 重啟後黑名單消失

說明:Fail2ban 的 nftables set 為記憶體狀態,actionstop 只在 Fail2ban 正常停止時觸發

若遇到強制重啟(reboot、電源中斷、核心 panic),actionstop 不會被執行,黑名單無法寫入磁碟

解決:確認已完成 Cron 備份腳本設定。Cron 每小時備份一次,最多只損失 1小時內的新增封鎖






陷阱 13:Debian 13 無 /var/log/auth.log

症狀:Fail2ban 啟動後 sshd jail 無法偵測到任何登入失敗

說明:Debian 13 預設使用 systemd-journald,SSH登入失敗記錄在 journal 而非傳統的 /var/log/auth.log

解決:確認 jail.local 中設定 backend = systemd

驗證SSH登入失敗是否有被 journald 記錄
journalctl -u ssh --since "10 minutes ago" | grep -i fail





陷阱 14:Cron 備份腳本寫入中途被讀取(競態條件)

說明:若不使用原子性寫入,Cron 腳本寫入 .ipset 檔案的過程中若 Fail2ban 重啟,可能讀到寫到一半的不完整內容

解決:本文的備份腳本已使用 mktemp + mv -f 的原子性寫入方式,先寫暫存檔,完成後再搬移,確保讀取到的永遠是完整的備份





陷阱 15:fail2ban-client -t 失敗,顯示 ignoreip 解析錯誤

症狀:執行 fail2ban-client -t 時出現 "IP" is not a valid IP 或類似錯誤

原因:ignoreip 中仍保留了佔位文字(如 你的管理員IPv4),或填入了無效格式的IP

解決:重新檢查 /etc/fail2ban/jail.local,確認所有佔位文字已替換為實際IP或完全刪除










------------------------
日常維護指令速查
------------------------



----------------
管理防火牆
----------------

手動啟動防火牆
/usr/local/bin/firewall.sh start


手動停止防火牆 (清除所有規則)
/usr/local/bin/firewall.sh stop


測試模式 (修改規則後先測試)
/usr/local/bin/firewall.sh test

查看統計
/usr/local/bin/firewall.sh stats


透過 systemd
systemctl start firewall.service

systemctl stop  firewall.service

systemctl restart firewall.service

systemctl status firewall.service


----------------------
查看 nftables 規則
----------------------


查看完整規則集
nft list ruleset


查看 input chain
nft list chain inet filter input


即時監控被丟棄的封包
journalctl -k -f | grep "FW_DROP"


查看核心日誌
dmesg -w | grep "FW_DROP"



--------------------
管理 Fail2ban
--------------------

查看所有監獄
fail2ban-client status


查看特定監獄 (如 sshd)
fail2ban-client status sshd


手動封鎖 IP
fail2ban-client set sshd banip 1.2.3.4


解除封鎖 IP
fail2ban-client set sshd unbanip 1.2.3.4


重新載入設定
fail2ban-client reload


查看日誌(最近 50 筆)
journalctl -u fail2ban.service --no-pager -n 50




------------------
查看服務日誌
------------------

防火牆服務日誌 (本次開機)
journalctl -u firewall.service --boot


Fail2ban 服務日誌 (本次開機)
journalctl -u fail2ban.service --boot


即時監控所有相關日誌
journalctl -f | grep -E "fail2ban|nftables|FW_DROP"


-----------------
管理封鎖清單
-----------------

查看目前 IPv4 黑名單
nft list set inet filter f2b-blacklist4


查看目前 IPv6 黑名單
nft list set inet filter f2b-blacklist6


手動觸發備份
/usr/local/bin/backup-blacklist.sh


查看備份檔案
ls -lh /var/lib/fail2ban/*.ipset

wc -l /var/lib/fail2ban/nftables-blacklist4.ipset




-----------------------
Part 2
-----------------------


等待LNMP服務都安裝配置完畢

再來做 Fail2ban Part 2

Edited by Jack

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.