# fail2ban.conf / fail2ban.local reference

> Every fail2ban.conf option explained: loglevel, logtarget, socket, allowipv6, dbfile, dbpurgeage, dbmaxmatches. How to override them safely in fail2ban.local.
>
> Source: https://fail2ban.dev/config/fail2ban-conf/ · Updated 2026-10-25 · Checked against fail2ban 1.1.1
> fail2ban.dev is an independent guide, not the official fail2ban project.

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

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

## fail2ban.conf vs fail2ban.local

The same override rules as for jails apply ([load order](/config/)):

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

```text
$ sudo fail2ban-client get loglevel
Current logging level is 'INFO'
```
|---|---|
| `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](/config/recidive/), 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
# reproduce the problem, then:
sudo fail2ban-client set loglevel INFO
```

```log
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
```

```text
$ sudo fail2ban-client get logtarget
Current logging target is:
`- /var/log/fail2ban.log
```
|---|---|
| `/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](/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](/troubleshooting/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
```

```ini
[Definition]
allowipv6 = auto
```

## 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](/config/bantime-increment/) 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.

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

```ini
[Definition]
dbpurgeage = 30d
```

### 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
  "SELECT jail, ip, datetime(timeofban,'unixepoch'), bantime, bancount FROM bips ORDER BY timeofban DESC LIMIT 10;"
```

If the database grows to hundreds of megabytes or fail2ban gets slow on start, see [high CPU or memory](/troubleshooting/high-cpu/).

## [Thread] stacksize

```ini
[Thread]
stacksize = 512
```

## 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 logtarget /var/log/fail2ban.log
sudo fail2ban-client set dbpurgeage 7d
sudo fail2ban-client flushlogs       # reopen the log file after rotation
```

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