Skip to main content

Fail2ban setup and configuration guide

TL;DR

Complete guide to installing and configuring fail2ban on Ubuntu and Debian covering SSH jails, nginx jails, custom filters, and operational management.

Key facts

Topology
Fail2ban on Ubuntu/Debian

TL;DR

fail2ban watches your log files for repeated authentication failures and automatically bans offending IP addresses using iptables or UFW. It is the simplest effective defence against brute-force attacks on SSH, web applications, and mail servers. This guide covers installation, jail configuration, custom filters, and day-to-day management.

Installation

sudo apt update && sudo apt install -y fail2ban

fail2ban starts automatically. Verify it is running:

sudo systemctl status fail2ban

Configuration structure

Never edit /etc/fail2ban/jail.conf directly — it gets overwritten on updates. Create a local override:

sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

All customisations go in jail.local or in individual files under /etc/fail2ban/jail.d/.

SSH jail customisation

The SSH jail is enabled by default. Tune it for your environment in /etc/fail2ban/jail.local:

[sshd]
enabled  = true
port     = ssh,2222
filter   = sshd
logpath  = /var/log/auth.log
maxretry = 5
bantime  = 3600
findtime = 600
banaction = ufw
  • maxretry: ban after 5 failed attempts
  • findtime: within a 10-minute window
  • bantime: ban for 1 hour (use -1 for permanent)
  • banaction: use ufw if UFW is your firewall, otherwise iptables-multiport

Restart after changes:

sudo systemctl restart fail2ban

Nginx jails

Protect your web server against common attack patterns.

nginx-http-auth — bans IPs that fail HTTP basic authentication:

[nginx-http-auth]
enabled  = true
port     = http,https
filter   = nginx-http-auth
logpath  = /var/log/nginx/error.log
maxretry = 3
bantime  = 3600

nginx-botsearch — bans bots probing for common vulnerability paths (wp-admin, phpmyadmin, etc.):

[nginx-botsearch]
enabled  = true
port     = http,https
filter   = nginx-botsearch
logpath  = /var/log/nginx/access.log
maxretry = 2
bantime  = 86400

Custom filters for application brute force

Create a custom filter for your application's login endpoint. First, define the filter in /etc/fail2ban/filter.d/app-login.conf:

[Definition]
failregex = ^<HOST> -.*"POST /login HTTP.*" 401
ignoreregex =

Then create the jail in /etc/fail2ban/jail.d/app-login.conf:

[app-login]
enabled  = true
port     = http,https
filter   = app-login
logpath  = /var/log/nginx/access.log
maxretry = 10
findtime = 300
bantime  = 1800

Test the filter against your log file before enabling:

sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/app-login.conf

Whitelisting IPs

Prevent your own office or monitoring IPs from being banned:

# /etc/fail2ban/jail.local — under [DEFAULT]
ignoreip = 127.0.0.1/8 ::1 203.0.113.10 198.51.100.0/24

Operational commands

# Check status of all jails
sudo fail2ban-client status

# Check a specific jail
sudo fail2ban-client status sshd

# Manually ban an IP
sudo fail2ban-client set sshd banip 192.0.2.50

# Unban an IP
sudo fail2ban-client set sshd unbanip 192.0.2.50

# Check which IPs are currently banned
sudo fail2ban-client get sshd banned

Email notifications

Configure fail2ban to send email alerts on bans. In /etc/fail2ban/jail.local:

[DEFAULT]
destemail = admin@example.com
sender    = fail2ban@example.com
mta       = sendmail
action    = %(action_mwl)s

The action_mwl action sends an email with the whois lookup and relevant log lines.

Log monitoring

Review fail2ban's own logs to verify it is working:

sudo tail -50 /var/log/fail2ban.log

Look for Ban and Unban entries to confirm jails are triggering as expected.

With Reflex

Reflex integrates with fail2ban to provide a centralised view of banned IPs across your entire fleet, alerts on unusually high ban rates that may indicate a coordinated attack, and tracks jail health so you know immediately if fail2ban stops running. See How it works.