Blog
3 min read

fail2ban: Automatically Ban IPs That Attack Your Server

fail2ban watches your logs for repeated failed logins and other abuse, then bans the offending IPs with the firewall. Install and configure jail.local, protect SSH and Nginx, check and unban IPs, write a simple custom filter, and know what fail2ban does and doesn't protect against.

Put a server on the internet and within minutes bots start trying passwords on SSH, probing for /wp-login.php, and hammering login forms. fail2ban reads your log files, spots IPs that keep failing, and bans them at the firewall for a while. (Brute force attacks)

Install

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

Configure: jail.local

Never edit jail.conf (it's overwritten on upgrade). Create /etc/fail2ban/jail.local:

[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5
bantime.increment = true
ignoreip = 127.0.0.1/8 ::1 203.0.113.50
backend = systemd

[sshd]
enabled = true
port    = ssh
  • maxretry failures within findtime → banned for bantime.
  • bantime.increment — repeat offenders get longer bans.
  • ignoreip — your own static IP, so you can't lock yourself out.
  • backend = systemd — read from the journal, which modern Ubuntu/Debian use for SSH logs.
sudo systemctl restart fail2ban

Protect web endpoints too

fail2ban ships filters for many services. For Nginx:

[nginx-http-auth]
enabled = true

[nginx-botsearch]
enabled  = true
logpath  = /var/log/nginx/access.log
maxretry = 2

nginx-botsearch catches scanners requesting paths that don't exist on your site (admin panels, .env files). (What is Nginx?)

A custom filter: your app's login

If your app logs failed logins like:

2026-10-02T10:15:00Z WARN login_failed ip=198.51.100.7 email=...

create /etc/fail2ban/filter.d/myapp-login.conf:

[Definition]
failregex = login_failed ip=<HOST>

and a jail:

[myapp-login]
enabled  = true
filter   = myapp-login
logpath  = /var/log/myapp/app.log
maxretry = 10
findtime = 5m

Test the regex against your log before relying on it:

fail2ban-regex /var/log/myapp/app.log /etc/fail2ban/filter.d/myapp-login.conf

(Structured logging)

Check status and unban

sudo fail2ban-client status
sudo fail2ban-client status sshd
sudo fail2ban-client set sshd unbanip 198.51.100.7

Behind a proxy or Cloudflare

If your site is behind Cloudflare or a load balancer, Nginx sees their IP addresses, not visitors'. fail2ban would then ban Cloudflare — taking your site down for everyone (Cloudflare 521). Either:

  • configure Nginx's real_ip module so logs contain the real client IP, and ban using Cloudflare's API or rules instead of the local firewall, or
  • leave web-facing banning to Cloudflare's own WAF and rate limiting, and use fail2ban for SSH.

What fail2ban does and doesn't do

Does: cut log noise, slow down brute-force attempts, block lazy scanners.

Doesn't:

  • stop attacks from huge botnets spread across thousands of IPs (each stays under the threshold),
  • protect against vulnerabilities in your app,
  • replace proper authentication.

It's one layer. The fundamentals matter more:


EasySpawn servers come with the firewall, OS patching and SSL handled, and databases never exposed to the internet — the fundamentals fail2ban is meant to sit on top of. See how it works or join the waitlist.

Related: SSH Hardening · How to Secure a New VPS · UFW Firewall Basics · Brute Force Attacks

Keep reading