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
maxretryfailures withinfindtime→ banned forbantime.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
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_ipmodule 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:
- SSH keys only, password login off — then SSH brute force can't succeed at all. (SSH hardening)
- Firewall with only needed ports open. (UFW basics)
- Rate limiting in your app. (Implementing rate limiting)
- Updates. (How to secure a new VPS)
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
What Is Tailscale? A Private Network for Your Devices and Servers
Tailscale builds a private, encrypted network (a tailnet) between your laptops, phones and servers using WireGuard, with no ports to open. How it works, common uses — private SSH, reaching databases and admin tools, home labs — MagicDNS, ACLs, Funnel and Serve, and alternatives like Headscale and plain WireGuard.
Writing a systemd Service File for Your App (With Hardening)
A production-ready systemd unit for a Node.js or Python app, explained: Type, User, WorkingDirectory, EnvironmentFile, Restart and backoff, graceful stop, resource limits, logging, and the sandboxing options (ProtectSystem, NoNewPrivileges, PrivateTmp) that limit damage if the app is compromised.