fail2ban 1.1 配置参数详解

fail2ban 1.1.1 配置体系详解:/etc/fail2ban 文件树与覆盖顺序、fail2ban.conf 与 jail 核心参数、bantime.increment 递增禁时实测、filter.d 过滤器与 action.d nftables 动作内幕、配置校验与热生效,全程实测。

fail2ban安全测试2026/10/24

fail2ban 1.1 配置参数详解

目标:系统讲清 fail2ban 1.1.1 的配置体系——/etc/fail2ban 下五类配置文件的结构、加载顺序与覆盖规则,[DEFAULT] 与 jail 段核心参数、filter.d 过滤器与 action.d 动作的内幕,以及配置校验与热生效方法。全部内容在 Ubuntu 22.04 + fail2ban 1.1.1(源码安装,安装步骤见《Ubuntu 22.04 安装 fail2ban 1.1.1 指南》)实测通过,配置片段与回显均为实测原文。

一、环境信息

  • 操作系统:Ubuntu Server 22.04 LTS(x86_64),systemd 249;
  • fail2ban:1.1.1(2026-08-15 官方稳定版,源码安装于 /usr/local);
  • 配置目录:/etc/fail2ban/;数据库:/var/lib/fail2ban/fail2ban.sqlite3;
  • 被保护对象:openssh-server 1:8.9p1,sshd jail 走 systemd journal 后端(Debian 系默认);
  • 封禁动作:nftables(1.1.1 在 Debian/Ubuntu 系的默认值,实测确认)。

二、配置文件树总览

ls -la /etc/fail2ban/ 实测:

drwxr-xr-x 2 root root 4096 action.d
-rw-rw-r-- 1 root root 3017 fail2ban.conf
drwxr-xr-x 2 root root 4096 fail2ban.d
drwxr-xr-x 3 root root 4096 filter.d
-rw-rw-r-- 1 root root 25907 jail.conf
drwxr-xr-x 2 root root 4096 jail.d
-rw-r--r-- 1 root root  149 jail.local
-rw-rw-r-- 1 root root  645 paths-arch.conf
-rw-rw-r-- 1 root root 2897 paths-common.conf
-rw-rw-r-- 1 root root  744 paths-debian.conf
-rw-rw-r-- 1 root root  930 paths-fedora.conf
-rw-rw-r-- 1 root root  982 paths-freebsd.conf
-rw-rw-r-- 1 root root  738 paths-opensuse.conf
-rw-rw-r-- 1 root root  286 paths-osx.conf

五类文件的职责与数量(1.1.1 实测清点):

文件/目录数量职责
fail2ban.conf1服务端全局配置:日志、socket、数据库
jail.conf + jail.local + jail.d/主文件 + 覆盖文件jail(关押室)定义:看什么、怎么算违规、怎么封
filter.d/103 个 .conf过滤器:从日志行识别「失败/攻击」的正则集
action.d/69 个 .conf/.py动作:封禁、解封、通知的命令集
paths-*.conf7 个各发行版的路径与默认值差异层

加载顺序与覆盖规则(以 jail 为例,同名参数后者覆盖前者):

jail.conf  →  jail.d/*.conf  →  jail.local  →  jail.d/*.local
  • .conf 是发行版/上游维护的默认值,升级会被覆盖;.local 与 jail.d/*.local 是给用户的定制层,升级不覆盖;
  • 所以定制永远写 jail.local 或 jail.d/*.local,不要直接改 jail.conf;
  • filter.d、action.d 同理存在 <名称>.conf 与 <名称>.local 覆盖机制;
  • 每个配置文件只识别 [DEFAULT](全局默认)与具体段名;[INCLUDES] 段的 before/after 用于文件级拼接(详见 paths 与 filter 小节)。

💡 说明:jail.d/defaults-debian.conf 是 Debian/Ubuntu 打包自带的启用文件,实测内容仅三行:

[sshd]
enabled = true

这就是「apt 装完什么都不配,sshd jail 也在运行」的原因。

三、主配置 fail2ban.conf

全局唯一的服务端配置(1.1.1 实测全文参数,逐个列出):

参数默认值(实测)说明
loglevelINFO日志级别:CRITICAL / ERROR / WARNING / NOTICE / INFO / DEBUG
logtarget/var/log/fail2ban.log日志去向,可选 STDOUT / STDERR / SYSLOG / SYSOUT / SYSTEMD-JOURNAL / FILE,只能设一个
syslogsocketauto仅 logtarget = SYSLOG 时生效
socket/var/run/fail2ban/fail2ban.sockfail2ban-client 与服务端的通信套接字,运行期不可删
pidfile/var/run/fail2ban/fail2ban.pid服务端 PID 文件
allowipv6auto(注释行)IPv6 支持:auto / yes / no
dbfile/var/lib/fail2ban/fail2ban.sqlite3持久化数据库;设 :memory: 则数据不落盘,设 None 禁用数据库
dbpurgeage1d数据库中封禁记录的清理年龄
dbmaxmatches10每 ticket 在库中保留的命中行数上限

实测数据库表结构(sqlite3 .tables 输出:bans bips fail2banDb jails logs),其中复犯计数表:

CREATE TABLE bips(ip TEXT NOT NULL, jail TEXT NOT NULL, timeofban INTEGER NOT NULL,
bantime INTEGER NOT NULL, bancount INTEGER NOT NULL default 1, data JSON,
PRIMARY KEY(ip, jail), FOREIGN KEY(jail) REFERENCES jails(name) );

bancount 是递增禁时(见 4.3)的计数依据,data 以 JSON 存每次命中的日志行(上限即 dbmaxmatches)。

⚠️ 注意:修改 fail2ban.conf 后用 systemctl restart fail2ban 生效(改 logtarget 等热参数也可用 reload,但 socket/pidfile/dbfile 类改动必须重启)。

四、jail 配置(jail.conf / jail.local / jail.d)

4.1 [DEFAULT] 核心参数

以下行号均实测自 1.1.1 的 jail.conf(源文件),未加 # 的为该文件中的生效默认值:

行号参数默认值含义
87ignoreselftrue(注释行)自动忽略本机自身地址(127.0.0.0/8、::1 等),命中不封禁
92ignoreip127.0.0.1/8 ::1(注释行)白名单:IP、CIDR、DNS 名,空格/逗号分隔
96ignorecommand空外部命令白名单,返回 true 则忽略
103bantime10m封禁时长,支持 s/m/h/d/w/mo/y 缩写;启用递增后为首次封禁时长基数
107findtime10m计数窗口:该时间内失败达到 maxretry 即封
110maxretry5窗口内允许的失败次数阈值
112maxmatches(跟在 maxretry 后)ticket 内保留的命中行数
132backendauto日志读取后端:auto / pyinotify / polling / systemd
143usednswarn反向 DNS 解析策略:yes / no / warn
150logencodingauto日志文件编码
189protocoltcp封禁动作的协议参数
192chain<known/chain>防火墙链
196port0:65535封禁端口范围
208/209banaction / banaction_allports注释行:iptables-multiport / iptables-allportsjail.conf 内置默认;Debian/Ubuntu 被 paths-debian.conf 覆盖为 nftables(见 4.6)
260action%(action_)s最终动作链,默认只引用 banaction 本体

各参数的运行期实测验证(fail2ban-client get,在未定制的 sshd jail 上):

$ fail2ban-client get sshd bantime
600
$ fail2ban-client get sshd findtime
600
$ fail2ban-client get sshd maxretry
5

10m 被换算为 600 秒,证明时长缩写解析正确。

4.2 bantime.increment 递增禁时

jail.conf 第 47~70 行的注释块(实引)定义了整套递增禁时参数:

参数默认说明
bantime.incrementfalse总开关:开启后查数据库复犯记录加长禁时
bantime.rndtime空给禁时加随机秒数,防 botnet 精确计算解封时刻
bantime.maxtime空禁时增长上限(封顶)
bantime.factor1增长系数
bantime.formulaban.Time * (1<<(ban.Count if ban.Count<20 else 20)) * banFactor默认公式:按 1,2,4,8,16… 增长,位移封顶 20
bantime.multipliers(注释示例 1 2 4 8 16 32 64)用乘数表替代公式计算
bantime.overalljailsfalse复犯计数是否跨 jail 汇总
bantime.resetbancount(注释)何时重置复犯计数

实测验证(jail.local 设 bantime = 5、bantime.increment = true、bantime.factor = 2):

$ fail2ban-client set sshd banip 198.51.100.7
1
$ fail2ban-client get sshd banip --with-time
198.51.100.7 	2026-10-23 20:44:49 + 5 = 2026-10-23 20:44:54

等待 6 秒自动解封后再次封禁同一 IP:

$ fail2ban-client set sshd banip 198.51.100.7
1
$ fail2ban-client get sshd banip --with-time
198.51.100.7 	2026-10-23 20:44:55 + 20 = 2026-10-23 20:45:15

禁时从 5 秒增长到 20 秒,数据库复犯计数同步增长:

$ sqlite3 /var/lib/fail2ban/fail2ban.sqlite3 'select ip,jail,bancount,bantime from bips;'
198.51.100.7|sshd|2|20

⚠️ 注意:递增依赖数据库(dbfile 设为 None 时失效);且复犯计数在 bantime 到期自动解封的循环中持续累积,实测用 set unbanip 手动解封后再封时,时长未按倍数增长——手动解封场景的计数语义与自动解封不同,验证递增策略时请让禁时自然到期。

4.3 jail 段定义与 [sshd] 实例

每个 jail 段继承 [DEFAULT] 全部参数,再按需覆盖。1.1.1 jail.conf 中 sshd 段原文(第 271~280 行):

[sshd]

# To use more aggressive sshd modes set filter parameter "mode" in jail.local:
# normal (default), ddos, extra or aggressive (combines all).
# See "tests/files/logs/sshd" or "filter.d/sshd.conf" for usage example and details.
#mode   = normal
port    = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s

要点:

  • mode = normal|ddos|extra|aggressive:sshd 过滤器内置多档正则集,aggressive 合并全部(含连接断开类弱信号);
  • logpath = %(sshd_log)s:从 paths 层插值取得路径(见 4.6);
  • backend = %(sshd_backend)s:Debian/Ubuntu 的 paths-debian.conf 实测值为 systemd,故 sshd jail 默认读 journal 而非 auth.log 文件——fail2ban-client get sshd logpath 显示 No file is currently monitored 即为该机制的表现;
  • filter 参数缺省等于 jail 名(sshd jail → filter.d/sshd.conf),要换过滤器时显式写 filter = <名称>。

实战 jail.local(本文实测环境使用的完整文件,149 字节):

[DEFAULT]
ignoreip =
ignoreself = false
bantime  = 2m
findtime = 10m
maxretry = 3
bantime.increment = true
bantime.factor = 2

[sshd]
enabled = true

逐行解读:清空白名单与关闭自身忽略(为让本机 127.0.0.1 也能被实验封禁)、禁时缩到 2 分钟、窗口 10 分钟内失败 3 次即封、递增禁时系数 2、显式启用 sshd jail。重载后实测:

$ fail2ban-client reload
OK
$ fail2ban-client status
Status
|- Number of jail:	1
`- Jail list:	sshd

4.4 jail.d 额外 jail

颗粒化管理时,与其堆一个大 jail.local,不如按服务拆 jail.d/:

cat > /etc/fail2ban/jail.d/sshd.local <<'EOF'
[sshd]
enabled = true
maxretry = 3
EOF
fail2ban-client reload sshd

实测回显(单 jail 热重载):

OK

4.5 paths-*.conf 与变量插值

fail2ban 用 ini 的 %(变量名)s 语法做配置插值,paths 层集中定义各发行版差异:

# paths-debian.conf [DEFAULT] 实测(节选)
banaction = nftables
banaction_allports = nftables[type=allports]

sshd_backend = systemd
postfix_backend = systemd

syslog_daemon = /var/log/daemon.log

三个插值链务必理清:

  • jail.conf 的 backend = %(sshd_backend)s → paths-debian.conf 的 systemd(所以 Debian 系 sshd jail 读 journal);
  • jail.conf 第 212 行 action_ = %(banaction)s[port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] → banaction 在 Debian 系被 paths 覆盖为 nftables(jail.conf 第 208 行的 iptables-multiport 只是注释掉的内置默认);
  • 第 260 行 action = %(action_)s 把上面拼好的动作挂到每个 jail 上。

[INCLUDES] 段控制文件级拼接:before = paths-common.conf 表示先加载 common 再加载本文件(本文件同名变量覆盖 common);paths-debian.conf 还有 after = paths-overrides.local,给本地覆盖留口。

五、filter.d 过滤器详解

5.1 文件结构

以 filter.d/sshd.conf 为例(1.1.1 实引):

[INCLUDES]

# Read common prefixes. If any customizations available -- read them from
# common.local
before = common.conf

[DEFAULT]

_daemon = sshd(?:-session)?

# optional prefix (logged from several ssh versions) like "error: ", "error: PAM: " or "fatal: "
__pref = (?:(?:error|fatal): (?:PAM: )?)?
__suff = (?: (?:port \d+|on \S+|\[preauth\])){0,3}\s*

[Definition]

prefregex = ^<F-MLFID>%(__prefix_line)s</F-MLFID>%(__pref)s<F-CONTENT>.+</F-CONTENT>$

三层结构:

  • [INCLUDES]:before = common.conf 拼入通用前缀正则 __prefix_line(时间戳 + 主机名 + 进程名模式);
  • [DEFAULT]:_daemon、__pref、__suff 等下划线开头的内部变量(不会成为 jail 参数),供 [Definition] 段组合复用;
  • [Definition]:prefregex(多行日志的预归类正则,把 "sshd:" 前缀后的业务内容抽出来)+ 一组 failregex 失败正则 + journalmatch(journal 模式下的单元过滤)。

实测该 prefregex 在 journal 模式下的生效形态(fail2ban-client -d 节选):

['set', 'sshd', 'prefregex', '^(?P<mlfid>(?:\\[\\])?\\s*(?:<[^.]+\\.[^.]+>\\s+)?(?:\\S+\\s+)?(?:kernel:\\s?\\[ *\\d+\\.\\d+\\]:?\\s+)?(?:@vserver_\\S+\\s+)?(?:(?:(?:\\[\\d+\\])?:\\s+[\\[\\(]?sshd(?:-session)?(?:\\(\\S+\\))?\\]\\)]?:?|[\\[\\(]?sshd(?:-session)?(?:\\(\\S+\\))?\\]\\)]?:?(?:\\[\\d+\\])?:?)\\s+)?(?:\\[ID \\d+ \\S+\\]\\s+)?)(?:(?:error|fatal): (?:PAM: )?)?(?P<content>.+)$']

5.2 failregex 语法要点

  • <HOST>:捕获 IPv4/IPv6/主机名的标准占位符;<ADDR> 与 <IP4>/<IP6> 是 1.x 细分变体;
  • <F-USER>...</F-USER>、<F-NOFAIL>、<F-MLFFORGET>:fail2ban 扩展标签,用于提取用户名、标记「命中但不封禁」(如 pam 认证失败行)等;
  • 1.1.1 的 sshd 过滤器实测含 21 条 failregex,用 fail2ban-regex 可看到命中分布(详测见《fail2ban 1.1 常用 CLI 命令与工具详解》):#4(Failed password 类)7 次、#14(PAM authentication failure)7 次、#20(Connection closed/disconnect 类)7 次;
  • mode 参数切换正则集档位;自定义服务写过滤器时,正则必须匹配「去掉日期前缀后的行」,且要考虑多行日志(maxlines)。

5.3 journalmatch 实测

$ fail2ban-client get sshd journalmatch
Current match filter:
_SYSTEMD_UNIT=sshd.service + _COMM=sshd + _COMM=sshd-session

这是 sshd jail 在 journal 模式下的读取范围声明:只取 sshd.service 单元、进程名 sshd/sshd-session 的日志。改用其他服务时,过滤器自带 journalmatch 会随之切换。

5.4 自定义过滤器模板

新增自定义服务过滤器(示例骨架,字段与 1.1.1 风格一致):

# /etc/fail2ban/filter.d/myapp.conf
[Definition]
failregex = ^.*myapp\[\d+\]: Auth failure for user .* from <HOST> port \d+.*$
ignoreregex =
journalmatch = _SYSTEMD_UNIT=myapp.service

先用 fail2ban-regex 离线验证再上线(实测输出解读见 D1 篇):

fail2ban-regex /path/to/myapp.log /etc/fail2ban/filter.d/myapp.conf

六、action.d 动作详解

6.1 文件结构

action.d/nftables.conf(1.1.1 实引,节选):

[INCLUDES]

after = nftables-common.local

[Definition]

# Values:  [ multiport | allports ]  Default: multiport
type = multiport

rule_match-multiport = $proto dport \{ $(echo '<port>' | sed s/:/-/g) \}

rule_stat = %(match)s <addr_family> saddr @<addr_set> <blocktype>

结构要点:[Definition] 放 actionstart/actionstop/actioncheck/actionban/actionunban 命令与内部变量;[Init] 段定义动作级参数(nftables 的 table_family、chain_type、blocktype 等),用户可在 nftables-common.local 或 jail 引用行内参数覆盖。

6.2 nftables 默认动作全链

1.1.1 在 Debian/Ubuntu 的默认封禁动作是 nftables(不是老教程里的 iptables-multiport)。jail 实际挂载的动作与封禁/解封命令实测:

$ fail2ban-client get sshd actions
The jail sshd has the following actions:
nftables
$ fail2ban-client get sshd action nftables actionban
nft add element inet f2b-table <addr_set> \{ <ip> \}
$ fail2ban-client get sshd action nftables actionunban
nft delete element inet f2b-table <addr_set> \{ <ip> \}

封禁一个 IP 后,内核侧实际生成的 nftables 结构实测(nft list ruleset):

table inet f2b-table {
	set addr-set-sshd {
		type ipv4_addr
		flags interval
		elements = { 203.0.113.66 }
	}

	chain f2b-chain {
		type filter hook input priority filter - 1; policy accept;
		tcp dport 22 ip saddr @addr-set-sshd reject with icmp port-unreachable
	}
}

解读:fail2ban 建 inet f2b-table 表、按 jail 建 addr-set-sshd 集合、f2b-chain 链挂在 input 钩子上(优先级 filter-1,先于常规规则),命中 tcp dport 22 + 集合内源地址 即 reject。封禁/解封只是对集合做 add/delete element,性能好、规则稳定。

6.3 常用动作分类(69 个实测清点,节选)

  • 防火墙类:nftables、iptables-common 族(allports/multiport/ipset)、firewalld 族(7 个)、ufw、shorewall、pf、ipfw、ipfilter;
  • 云与第三方 API:cloudflare、csf、apf、blocklist_de、abuseipdb、dshield、badips;
  • 通知类:mail-whois、sendmail、apprise、xarf-login-attack;
  • 调试类:dummy(空动作,验证 jail 逻辑用,本文实验即用它做动态 jail 测试);
  • 系统类:hostsdeny(写 /etc/hosts.deny)、myip、iptables-multiport(兼容老配置)。

七、配置校验与生效

fail2ban-client -t

实测回显(全量校验配置语法与引用完整性):

OK: configuration test is successful

生效三档:

命令影响范围使用场景
fail2ban-client reload全部 jail 重读配置改 jail.local 后
fail2ban-client reload sshd单 jail只改了一个 jail
systemctl restart fail2ban服务级改 fail2ban.conf/socket/数据库参数

配置兜底查看:fail2ban-client -d 输出展开全部插值后的最终配置(transmitter 命令流),是排查「到底哪层覆盖了哪层」的终极手段:

$ fail2ban-client -d | grep "'sshd'" | head -3
['add', 'sshd', 'systemd']
['set', 'sshd', 'addlogpath']
['set', 'sshd', 'addfailregex', <21 条展开后的正则>]

实测确认 sshd jail 以 systemd 后端创建、携带 21 条展开后的 failregex。

八、常见误区与坑(实测案例)

  1. 直接改 jail.conf:升级即丢配置;一切定制进 .local(jail.local / jail.d/.local / filter.d/.local / action.d/*.local)。
  2. 本机测试永远封不掉:1.1.x 默认 ignoreself = true,对 127.0.0.1 的失败不会触发封禁(实测 fail2ban.log 记 Ignore 127.0.0.1 by ignoreself rule)。本机联调时在 jail.local 显式设 ignoreself = false,上线记得改回。
  3. 以为 sshd jail 读 /var/log/auth.log:Debian/Ubuntu 系 1.1.1 默认 sshd_backend = systemd,get sshd logpath 显示 No file is currently monitored 是正常现象;文件后端需显式 backend = polling(或 pyinotify)+ logpath。
  4. 老教程的 iptables-multiport 默认动作不再适用:Debian 系 1.1.1 默认 banaction = nftables;老机器迁移时注意防火墙栈差异(查看 get sshd actions 确认实际挂载)。
  5. 测试日志时间戳超前:给 jail 喂手工构造的日志行时,时间戳晚于当前时钟会触发时区告警(实测 fail2ban.log:Detected a log entry 1m 57s after the current time ... Treating such entries as if they just happened),构造测试数据务必用实时时间。
  6. .bak 后缀不参与加载:配置目录里放 jail.local.bak 不会被读取(fail2ban 只匹配 .conf/.local 模式),但注意 jail.d/ 下的 .conf 任何名字都会被当 jail 片段加载。
  7. bantime.increment 看似不生效:多因手动 unban 清了复犯语境或数据库被禁用(dbfile = None);验证时让禁时自然到期再复犯(实测流程见 4.2)。

九、参考链接

站内相关:《fail2ban 介绍与选型指南》、《fail2ban 1.1 配置参数详解》