fail2ban Rule Builder: Ban the Bots, Not Your Users

Pick what's being hammered, set how many tries count as an attack, and copy the filter and jail. Each comes with the command to test it against your own log before it bans anyone.

What to Protect

The defaults are what I use on client servers. Lower the limits if the attacks keep getting through.


    

    
Test it, then turn it on

    

fail2ban-regex should report matched lines for the attacks already in your log. If it shows 0 matched, the log path or format is wrong: fix that before reloading.

Where fail2ban Helps, and Where It Doesn't

It helps with noise and brute force on a server that faces the internet directly: password guessing on SSH, wp-login.php and xmlrpc.php floods, and scanners working through lists of admin paths.

It doesn't help behind Cloudflare or a load balancer unless the logs show the real client address, and even then a ban on the server can't stop traffic arriving through the proxy. Rate-limit at the proxy instead.

It isn't the lock. Key-only SSH, strong passwords with two-factor on WordPress, and plugins kept patched are what keep people out. fail2ban saves CPU and keeps the logs readable.

Watch for false bans. Your office behind one shared address, an uptime monitor, or an agency's whole team can trip a tight limit. Put them in the never-ban list.

Questions

How do I stop wp-login.php brute force attacks with fail2ban?

Pick "WordPress logins" above. The filter matches every POST to wp-login.php in the web server's access log, and the jail bans an address that tries more than a few times in ten minutes. A normal login is one POST, so real users are never caught; a password guesser makes hundreds.

Should I block xmlrpc.php?

If nothing uses it, yes: deny it in the web server and you don't need a jail. The Jetpack plugin and some mobile apps still need it, and then a fail2ban jail with a low limit stops the brute force and pingback abuse while leaving occasional use alone.

Where do I put the files?

The filter goes in /etc/fail2ban/filter.d/ and the jail in /etc/fail2ban/jail.d/, both under the names shown. Never edit jail.conf itself: package updates replace it. Test the filter against your log with fail2ban-regex, then systemctl reload fail2ban.

Why isn't fail2ban banning anything?

Usually one of four things: the log path is wrong, the log format doesn't match the filter (check with fail2ban-regex), the site sits behind Cloudflare or a load balancer so every request comes from the proxy's address, or the ban works on iptables while the server uses nftables or ufw. fail2ban-client status <jail> shows whether lines are being matched.

Does fail2ban work behind Cloudflare?

Not on its own. Behind a proxy the log shows the proxy's address unless you set the real client IP (nginx's real_ip module), and even then a firewall ban on the server can't block a visitor who reaches it through Cloudflare. Use Cloudflare's own rate limiting or WAF rules for the website, and keep fail2ban for SSH and anything not proxied.

What is bantime.increment?

It makes each repeat ban longer: an address banned for an hour, back again later, gets a longer ban each time it returns. Persistent bots end up banned for days while a user who mistyped a password a few times is let back in quickly.

Is fail2ban enough to protect SSH?

It cuts the noise, but the real protection is key-only logins (PasswordAuthentication no) with root login turned off. Then guessing passwords can't work at all, and fail2ban just keeps the logs readable. Restricting port 22 to known addresses in the firewall is better still.

Servers Under Constant Attack?

I harden the servers behind your sites: SSH, firewalls, fail2ban and the web server, with patching and monitoring after.