Configuration
fail2ban.conf / fail2ban.local reference
fail2ban.conf configures the fail2ban server itself, not the jails: where it logs, how verbose it is, and where it keeps its ban database. Change it through fail2ban.local.
/etc/fail2ban/fail2ban.conf holds the server-wide settings: loglevel (default INFO), logtarget (default /var/log/fail2ban.log), the control socket, the pidfile, allowipv6, and the SQLite database (dbfile, dbpurgeage = 1d, dbmaxmatches = 10). Don't edit it. Create /etc/fail2ban/fail2ban.local with a [Definition] section containing only the options you change, then restart or reload fail2ban.
[Definition]
loglevel = INFO
logtarget = /var/log/fail2ban.log
allowipv6 = auto
dbpurgeage = 7dsudo systemctl restart fail2banJail settings (bantime, ignoreip, banaction…) don't belong here; they go in jail.local.
fail2ban.conf vs fail2ban.local#
The same override rules as for jails apply (load order):
fail2ban.conffail2ban.d/*.conffail2ban.localfail2ban.d/*.local
Later files win. The stock fail2ban.conf in 1.1.1 places its values in [DEFAULT] and leaves [Definition] empty; fail2ban reads the [Definition] section, which inherits from [DEFAULT]. In your fail2ban.local, put overrides under [Definition] and they take precedence over the stock values. [Thread] is a separate section.
All options#
| Option | Default | Values |
|---|---|---|
loglevel |
INFO |
CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG, TRACEDEBUG, HEAVYDEBUG, or 50–5 |
logtarget |
/var/log/fail2ban.log |
a file path, SYSTEMD-JOURNAL, SYSLOG, STDOUT, STDERR |
syslogsocket |
auto |
auto or a socket path; only used with logtarget = SYSLOG |
socket |
/var/run/fail2ban/fail2ban.sock |
path of the socket fail2ban-client talks to |
pidfile |
/var/run/fail2ban/fail2ban.pid |
path of the PID file |
allowipv6 |
auto |
auto, yes/on/true/1, no/off/false/0 |
dbfile |
/var/lib/fail2ban/fail2ban.sqlite3 |
a file path, :memory:, or None |
dbpurgeage |
1d |
time (seconds or 1d, 7d, 30d…) |
dbmaxmatches |
10 |
integer |
[Thread] stacksize |
0 |
thread stack size in KiB: 0 (system default) or ≥ 32 |
loglevel: how verbose fail2ban is#
$ sudo fail2ban-client get loglevel
Current logging level is 'INFO'| Level | Logs |
|---|---|
ERROR / CRITICAL |
Only errors |
WARNING |
Errors and warnings (missing log files, DNS warnings) |
NOTICE |
Plus every Ban / Unban |
INFO (default) |
Plus every Found failure, jail start/stop, config details |
DEBUG |
Plus regex processing details; very noisy |
Keep INFO for normal operation. NOTICE is the minimum if you use the recidive jail, because it counts the Ban lines; at WARNING it sees nothing. Use DEBUG only briefly, and change it at runtime so you don't forget to switch back:
sudo fail2ban-client set loglevel DEBUG
# reproduce the problem, then:
sudo fail2ban-client set loglevel INFOTypical log lines at INFO and NOTICE:
2026-10-25 18:36:10,238 fail2ban.filter [1997]: INFO [sshd] Found 203.0.113.42 - 2026-10-25 18:36:10
2026-10-25 18:36:11,027 fail2ban.actions [1997]: NOTICE [sshd] Ban 203.0.113.42
2026-10-25 19:36:11,031 fail2ban.actions [1997]: NOTICE [sshd] Unban 203.0.113.42logtarget: where fail2ban logs#
$ sudo fail2ban-client get logtarget
Current logging target is:
`- /var/log/fail2ban.log| logtarget | Result |
|---|---|
/var/log/fail2ban.log (default) |
Plain log file, rotated by /etc/logrotate.d/fail2ban on most distributions |
SYSTEMD-JOURNAL |
Directly into the journal; read with journalctl -u fail2ban |
SYSLOG |
Via syslog (rsyslog decides the file); syslogsocket sets the socket |
STDOUT / STDERR |
Standard output; under systemd this also ends up in the journal; common in Docker containers |
Things to change together with logtarget:
- recidive reads fail2ban's own log. If you move it to the journal, set
backend = systemdin[recidive]; if you move the file, update recidive'slogpath. - logrotate: a custom file path needs its own rotation rule. After rotating, logrotate should run
fail2ban-client flushlogsso fail2ban reopens the file.
Finding and reading the log is covered on fail2ban logs.
socket and pidfile#
fail2ban-client talks to the server through the Unix socket /var/run/fail2ban/fail2ban.sock. You only change it to run a second, independent fail2ban instance. If the client says Failed to access socket path: /var/run/fail2ban/fail2ban.sock. Is fail2ban running?, the server isn't running or uses a different socket; see could not find server.
allowipv6 and the "not defined" warning#
allowipv6 tells fail2ban whether IPv6 is available. auto (the default) checks the system: it treats IPv6 as unavailable when it's disabled via net.ipv6.conf.all.disable_ipv6 or an IPv6 socket can't be opened.
Some 0.11.x and 1.0.x packages print this warning at every start because their fail2ban.conf doesn't set the option:
WARNING 'allowipv6' not defined in 'Definition'. Using default one: 'auto'It's harmless. To silence it, set the option explicitly:
[Definition]
allowipv6 = autoDetails: allowipv6 not defined warning.
The database: dbfile, dbpurgeage, dbmaxmatches#
fail2ban keeps state in SQLite at /var/lib/fail2ban/fail2ban.sqlite3:
- Active bans, restored after a restart (that's why restarting doesn't unban anyone).
- Ban history per IP, used by incremental bans and the
<bancount>,<ipfailures>,<ipmatches>action tags. - Log file positions, so fail2ban continues where it stopped instead of re-reading old lines.
dbfile#
| Value | Effect |
|---|---|
/var/lib/fail2ban/fail2ban.sqlite3 |
Persistent database (default) |
:memory: |
Database in RAM only; all bans and history are lost on restart |
None |
No database: no ban restore, and bantime.increment doesn't work |
dbpurgeage#
How long old ban records are kept. The purge runs every hour. An IP's record is deleted once dbpurgeage plus three times its last ban length has passed since that ban; permanent bans are never purged. With the default 1d, an IP banned for an hour is forgotten about 27 hours later and its next ban counts as a first offence.
$ sudo fail2ban-client get dbpurgeage
Current database purge age is:
`- 86400secondsRaise it if you rely on bantime.increment or long recidive bans. A month is reasonable; the database holds one row per IP and jail, so it stays small:
[Definition]
dbpurgeage = 30dThe stock jail.conf comment above [recidive] suggests at least 648000 (7.5 days).
dbmaxmatches#
The number of matched log lines stored per ban in the database (default 10). They're what <ipmatches> and <ipjailmatches> return in actions, for example in emails. Lower it to keep the database small on very busy servers; it doesn't affect banning.
Look inside the database#
sudo sqlite3 /var/lib/fail2ban/fail2ban.sqlite3 \
"SELECT jail, ip, datetime(timeofban,'unixepoch'), bantime, bancount FROM bips ORDER BY timeofban DESC LIMIT 10;"bips holds the latest ban per IP and jail (with the ban count used for incremental bans); bans holds individual ban events. Prefer fail2ban-client commands to change anything. Edit the file only with fail2ban stopped.
If the database grows to hundreds of megabytes or fail2ban gets slow on start, see high CPU or memory.
[Thread] stacksize#
[Thread]
stacksize = 512Sets the stack size in KiB for fail2ban's threads. Leave it at 0 unless you run on a very memory-constrained system and know you need it.
Change server settings at runtime#
Most server options can be changed without a restart (they revert to the file values on the next restart):
sudo fail2ban-client set loglevel NOTICE
sudo fail2ban-client set logtarget /var/log/fail2ban.log
sudo fail2ban-client set dbpurgeage 7d
sudo fail2ban-client flushlogs # reopen the log file after rotationFAQ#
What is the difference between fail2ban.conf and jail.conf?#
fail2ban.conf configures the server process: logging, socket, PID file and the ban database. jail.conf configures what fail2ban watches and how it bans: jails, filters, actions and times. Override each through its own .local file, fail2ban.local and jail.local.
What does dbpurgeage do?#
It sets how long fail2ban keeps old ban records in its SQLite database (default 1d). It decides how long a previously banned IP is remembered for incremental bans. Active bans are kept until they expire regardless. Raise it, for example to 30d, in fail2ban.local.
Where is the fail2ban database?#
At /var/lib/fail2ban/fail2ban.sqlite3, set by dbfile in fail2ban.conf. It stores active bans (restored after restarts), ban history and log positions. Setting dbfile = :memory: keeps it in RAM only; None disables it.
Spotted something wrong or out of date? Tell us — every page is checked against the current fail2ban release.