Fail2ban monitors your service logs for repeated failures and blocks offending IPs using your firewall. This guide explains the concept and gives copy paste jails for SSH on 22, HTTP on 80 or 443, and MySQL or MariaDB on 3306.

How Fail2ban works

  • Reads logs from services (for example: /var/log/auth.log, web server error or access logs, MySQL error log).
  • Filters match suspicious lines.
  • If failures exceed maxretry within findtime, Fail2ban bans the source IP for bantime via nftables on Debian 12.

Key terms:

  • jail: the rule that ties a filter and an action to specific logs and ports
  • filter: regex rules that match bad events in logs
  • action: how to ban (we use nftables-multiport)

Install Fail2ban

sudo apt update
sudo apt install -y fail2ban
sudo systemctl enable --now fail2ban
sudo systemctl status fail2ban

Install rsyslog

Fail2ban only works if it can see login failures in your logs. On Debian 12, the system journal (journald) already captures them, but many Fail2ban jails still expect a traditional log file like /var/log/auth.log. To keep things simple, install rsyslog so those logs are written out automatically:

sudo apt install rsyslog
sudo systemctl enable --now rsyslog

Base configuration

Do not edit jail.conf. Create your own overrides.

/etc/fail2ban/jail.local

[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5
ignoreip = 127.0.0.1/8 ::1
banaction = nftables-multiport
logtarget = /var/log/fail2ban.log
Code language: PHP (php)

Reload after changes:

sudo fail2ban-client reload

Jail 1, protect SSH on port 22

/etc/fail2ban/jail.d/sshd.local

[sshd]
enabled  = true
port     = 22
backend  = auto
logpath  = /var/log/auth.log
maxretry = 5
findtime = 10m
bantime  = 1h
Code language: JavaScript (javascript)

Check status:

sudo fail2ban-client status sshd
sudo tail -f /var/log/fail2ban.log
Code language: JavaScript (javascript)

Jail 2, protect HTTP on ports 80 and 443

Fail2ban reacts to patterns in logs. Two common web auth cases are below. Use only the one that applies to your stack.

Nginx basic auth:
/etc/fail2ban/jail.d/nginx-http-auth.local

[nginx-http-auth]
enabled  = true
port     = http,https
filter   = nginx-http-auth
logpath  = /var/log/nginx/error.log
maxretry = 3
findtime = 10m
bantime  = 1h
Code language: JavaScript (javascript)

Apache basic auth:
/etc/fail2ban/jail.d/apache-auth.local

[apache-auth]
enabled  = true
port     = http,https
filter   = apache-auth
logpath  = /var/log/apache2/error.log
maxretry = 3
findtime = 10m
bantime  = 1h
Code language: JavaScript (javascript)

Tip: run ls /etc/fail2ban/filter.d to see other web filters such as nginx-noscript or apache-badbots, then point a jail at the filter and the correct log path.

Jail 3, watch MySQL or MariaDB on port 3306

Best practice is not to expose 3306 publicly. Bind to localhost or a private network and restrict with your firewall. If you must watch for brute force on 3306:

/etc/fail2ban/jail.d/mysqld-auth.local

[mysqld-auth]
enabled  = true
port     = 3306
filter   = mysqld-auth
logpath  = /var/log/mysql/error.log
maxretry = 3
findtime = 10m
bantime  = 6h
Code language: JavaScript (javascript)

Confirm the error log path inside MariaDB or MySQL:

SHOW VARIABLES LIKE 'log_error';
Code language: JavaScript (javascript)

If your DB logs only to the journal, you can switch a jail to use systemd:

[mysqld-auth]
enabled   = true
port      = 3306
filter    = mysqld-auth
backend   = systemd
journalmatch = _SYSTEMD_UNIT=mariadb.service + _COMM=mysqld
maxretry  = 3
findtime  = 10m
bantime   = 6h
Code language: JavaScript (javascript)

Optional, recidive jail for repeat offenders

/etc/fail2ban/jail.d/recidive.local

[recidive]
enabled  = true
logpath  = /var/log/fail2ban.log
bantime  = 1d
findtime = 1d
maxretry = 5
Code language: JavaScript (javascript)

Apply and verify

Check configuration syntax:

sudo fail2ban-client -d

Reload Fail2ban:

sudo fail2ban-client reload

List jails and show bans:

sudo fail2ban-client status
sudo fail2ban-client status sshd

Unban a specific IP:

sudo fail2ban-client set sshd unbanip 203.0.113.45
Code language: CSS (css)

Check nftables sets for banned IPs:

sudo nft list ruleset | grep -A3 'f2b'
Code language: PHP (php)

Troubleshooting

  • Filters available:
ls /etc/fail2ban/filter.d
  • Test a filter against a log:
sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
Code language: JavaScript (javascript)
  • Reverse proxy or CDN:
    Ensure your web server logs the real client IP, not the proxy, otherwise you will ban the proxy’s IP.
  • Dockerized services:
    Make sure containers write logs to files on the host or to journald so Fail2ban can read them.

Leave A Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.