Test a Fail2ban Filter Safely with fail2ban-regex

Before you trust a new failregex against live traffic, fail2ban-regex lets you fire it at sample log lines and see exactly what matches. It is a repeatable way to test a pattern or an ignoreregex without banning anyone. Allow about fifteen minutes. You need the fail2ban package, a shell, and representative log lines. The examples use fail2ban-regex 1.0.2, installed here as package version 1.0.2-3ubuntu0.1.

This is a read-only test. fail2ban-regex analyses input; it does not enable a jail, add a firewall rule or ban an address. Do not confuse it with fail2ban-client, which can change the running service when used with administrative commands.

1. Confirm the installed command

Check the binary and version before relying on option details. These are ordinary commands and do not need elevated privileges:

$ command -v fail2ban-regex
/usr/bin/fail2ban-regex
$ fail2ban-regex --version
fail2ban-regex 1.0.2
$ dpkg-query -W -f='${Package} ${Version}\n' fail2ban
fail2ban 1.0.2-3ubuntu0.1

The installed manual describes the command as fail2ban-regex <LOG> <REGEX> [IGNOREREGEX]. The first two arguments are positional. LOG can be a log-line string, a filename, or systemd-journal. REGEX can be a regular expression, a filter name such as sshd, or a filter file. The optional third argument is an ignoreregex or ignore filter file.

Checkpoint: run fail2ban-regex --help if an example behaves differently. This machine's help output is the authority for the installed 1.0.2 command, especially for less common options.

2. Prepare a small test log

Start with a fixture that contains both failures and a successful login. Use synthetic addresses reserved for documentation. Writing a file in a directory you control is unprivileged:

$ cat > /tmp/fail2ban-regex.log <<'EOF'
Jan 01 12:00:00 host sshd[123]: Failed password for invalid user alice from 203.0.113.7 port 22 ssh2
Jan 01 12:00:05 host sshd[124]: Accepted password for bob from 198.51.100.22 port 22 ssh2
Jan 01 12:00:10 host sshd[125]: Failed password for root from 203.0.113.7 port 22 ssh2
EOF

Replace the file with a copy of real log data only when your handling rules allow it. Logs can contain usernames, addresses and other personal data. Keep the test copy protected and remove it when the investigation is over:

$ rm -- /tmp/fail2ban-regex.log

That removal is optional, but it is irreversible. Do not use a broad wildcard in the cleanup command.

3. Test the installed sshd filter

Pass the log path and the filter name as the two positional arguments. The --raw option stops host-name resolution in the report, which makes test output more predictable and avoids unnecessary lookups:

$ fail2ban-regex /tmp/fail2ban-regex.log sshd --raw --print-all-matched

Running tests
=============

Use   failregex filter file : sshd, basedir: /etc/fail2ban
Use         maxlines : 1
Use         log file : /tmp/fail2ban-regex.log

Results
=======

Failregex: 2 total
Ignoreregex: 0 total

Lines: 3 lines, 1 ignored, 2 matched, 0 missed

The exact report includes the expanded expressions and matching lines. For this fixture, the two failed-password lines match the installed sshd filter. The accepted-password line is ignored by that filter, so it is not a failure. A non-zero matched count is not a ban count: this command has not changed Fail2ban state.

Checkpoint: look at the final line first. A useful test has the expected number of matched and missed lines. If every line is missed, check the log format, date prefix, filter name and package configuration before changing the expression.

4. Test a new expression directly

Use a quoted expression when you are developing a filter rather than testing the installed filter file. The expression below recognises the SSH failure shape and uses Fail2ban's <HOST> tag to identify the address:

$ fail2ban-regex /tmp/fail2ban-regex.log \
    'sshd\[[0-9]+\]: Failed password for .* from <HOST> port [0-9]+ ssh2' \
    --raw --print-all-matched

Failregex: 2 total
Ignoreregex: 0 total
Lines: 3 lines, 0 ignored, 2 matched, 1 missed

Shell quoting matters. Single quotes keep brackets, backslashes and spaces together, while the angle-bracket tag remains visible to Fail2ban. In HTML, the tag is written as &lt;HOST&gt;; in a terminal, type the literal <HOST>. Do not paste the HTML entity into the shell.

A missed line is useful evidence. Here it is the accepted login, which should not match this failure expression. If a genuine failure is missed, add one representative line at a time and tighten the expression around the stable parts of the message.

5. Add an ignoreregex for an intentional exception

An ignoreregex removes matching lines from the failure result. This example keeps ordinary failed passwords as failures but ignores the invalid-user variant:

$ fail2ban-regex /tmp/fail2ban-regex.log \
    'sshd\[[0-9]+\]: Failed password for .* from <HOST> port [0-9]+ ssh2' \
    'sshd\[[0-9]+\]: Failed password for invalid user .* from <HOST> port [0-9]+ ssh2' \
    --raw

Failregex: 1 total
Ignoreregex: 1 total
Lines: 3 lines, 1 ignored, 1 matched, 1 missed

Use this only when the exception is deliberate and justified. An overly broad ignore can cancel the protection you are trying to test. Review the Ignored line(s) section with --print-all-ignored before putting an ignore into a filter configuration.

The third positional argument is not another failregex. If you need several expressions, put them in a filter file or use the filter's documented configuration structure. Do not solve an unexpected match by ignoring all lines from an address range.

6. Reduce noisy output while diagnosing

Once the counts make sense, choose the report detail you need. These options affect output, not matching:

Keep the full report for the first test. Suppressing misses too early is a common distraction trap: a filter can appear successful because the output is short while real failures are still being missed.

7. Use journal input only when the backend is available

For a systemd journal, use the literal systemd-journal as the log argument and supply a filter name or expression as the next argument. The manual says this requires the systemd Python support, and -m/--journalmatch applies only to this input mode:

$ fail2ban-regex systemd-journal sshd --raw --print-no-missed
Use   failregex filter file : sshd, basedir: /etc/fail2ban
Use systemd journal : systemd-journal
Failregex: ...

Output varies with journal contents and the installed Python integration. If the command reports that journal support is unavailable, test a journal export or ordinary log file instead. Do not grant elevated privileges merely to hide a backend or permission error. If the journal is restricted, follow your host's access policy and record which account performed the test.

8. Check a failing result without changing the service

First rerun with --verbose or a numerical --verbosity value from 0 to 4, then inspect the input and the filter source. The following checks are read-only:

$ fail2ban-regex --verbose /tmp/fail2ban-regex.log sshd --raw
$ sed -n '1,220p' /etc/fail2ban/filter.d/sshd.conf
$ test -r /tmp/fail2ban-regex.log && echo 'log is readable'

Use -c CONFIG when the filter lives under an alternate Fail2ban configuration directory. Use -e ENCODING when the log is not in the system locale's encoding, and -d DATEPATTERN only when the normal date detector cannot parse the log prefix. These options change how the test interprets input; they do not edit the filter.

If a multi-line filter needs more context, inspect its configured maximum and test with --maxlines. Keep the value no larger than the evidence requires, because broad multi-line matching can make both the report and a later jail harder to reason about.

Done means