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.

Updated 6 min readChecked against fail2ban 1.1.1

/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.

/etc/fail2ban/fail2ban.local
[Definition]
loglevel   = INFO
logtarget  = /var/log/fail2ban.log
allowipv6  = auto
dbpurgeage = 7d
bash
sudo systemctl restart fail2ban

Jail 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):

  1. fail2ban.conf
  2. fail2ban.d/*.conf
  3. fail2ban.local
  4. fail2ban.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#

output
$ 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:

bash
sudo fail2ban-client set loglevel DEBUG
# reproduce the problem, then:
sudo fail2ban-client set loglevel INFO

Typical log lines at INFO and NOTICE:

log
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.42

logtarget: where fail2ban logs#

output
$ 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 = systemd in [recidive]; if you move the file, update recidive's logpath.
  • logrotate: a custom file path needs its own rotation rule. After rotating, logrotate should run fail2ban-client flushlogs so 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:

log
WARNING 'allowipv6' not defined in 'Definition'. Using default one: 'auto'

It's harmless. To silence it, set the option explicitly:

/etc/fail2ban/fail2ban.local
[Definition]
allowipv6 = auto

Details: 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.

output
$ sudo fail2ban-client get dbpurgeage
Current database purge age is:
`- 86400seconds

Raise 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:

/etc/fail2ban/fail2ban.local
[Definition]
dbpurgeage = 30d

The 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#

bash
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#

/etc/fail2ban/fail2ban.local
[Thread]
stacksize = 512

Sets 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):

bash
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 rotation

FAQ#

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.