First, check the jail is not silently broken
A large share of people looking for a fail2ban replacement have a fail2ban that is not running the way they think. The most common cause on a current distribution is that sshd logs to the systemd journal and nothing writes /var/log/auth.log any more, while the stock jail still points at that file. The jail reports as active, the failure count stays at zero, and the attacks continue.
Run "fail2ban-client status sshd" before you do anything else. If failures are zero while your server is clearly under attack, fail2ban is not reading your logs and no alternative is needed, only a backend setting. If failures climb but bans stay at zero, the ban action is failing, usually because banaction does not match the firewall you actually run.
It is worth ruling this out first, because switching tools to fix a configuration problem means you carry the same misunderstanding into the new tool.
CrowdSec: the closest thing to a direct upgrade
CrowdSec parses logs and applies decisions much as fail2ban does, with one structural difference: it participates in a shared reputation network. Addresses seen attacking other participants can be blocked on your server before they have attacked you.
That directly addresses fail2ban's biggest structural weakness. fail2ban only knows about your server, so it can only react after an address has already failed enough times against you. Community intelligence lets you act on the first packet.
The trade-offs are real. It is a heavier stack, with an agent plus bouncers to enforce decisions, more moving parts to keep running, and a dependency on a third-party service for the intelligence that makes it worthwhile. For a single hobby VPS that is a lot of machinery; across a fleet it usually pays for itself.
SSHGuard: less, on purpose
SSHGuard does one thing: it watches authentication logs and blocks sources that fail repeatedly, with a small C daemon and very little configuration. It reads the journal natively, so the failure mode that catches fail2ban users on modern distributions does not apply.
Choose it when SSH is the only service you need protected and you want the smallest possible thing that works. Do not choose it expecting fail2ban's breadth: the ecosystem of filters for web servers, mail and application logs is where fail2ban is genuinely strong, and SSHGuard is not trying to compete there.
DenyHosts: mostly of historical interest
DenyHosts predates fail2ban's dominance and works through TCP wrappers and /etc/hosts.deny rather than the firewall. It is still packaged, and you will still find it recommended in old threads.
Two things make it hard to recommend today. Many modern services are not built against libwrap, so hosts.deny does not stop them, and its development has been far quieter than the alternatives. If you are choosing today rather than maintaining an existing install, choose something else.
nftables or iptables rate limiting: no daemon at all
You can rate-limit new connections directly in the firewall. An nftables rule with a limit expression, or the iptables recent module, drops sources exceeding a connection rate without any log parsing, any Python process, or anything to keep alive.
This is genuinely underrated for the specific case of SSH brute force from single sources. It is fast, it fails closed, and it survives a broken log pipeline because it never touches logs.
The limits are equally clear. It counts connections, not authentication failures, so it cannot distinguish a legitimate user with a flaky network from an attacker, and it gives you no record of who was blocked and why. It is protection without evidence, which is fine until you need to explain an incident.
Cloudflare and edge services: a different layer
An edge service filters HTTP traffic before it reaches you, which is valuable and worth having. It is not a fail2ban alternative, because fail2ban protects services on the host, most importantly SSH, which does not pass through an HTTP edge at all.
There is also a trap worth naming. Once traffic arrives via a proxy, every connection appears to come from the proxy's addresses, so a host-level tool counting failures per source address sees one very busy client instead of many attackers. If you put an edge in front of an existing setup, check that anything doing per-IP blocking reads the real client address from the forwarded header rather than the connection.
Host security agents: detecting behaviour instead of counting failures
All of the above share an assumption: an attacker is an address that fails a threshold number of times. That assumption is what a distributed attack defeats. If each attempt comes from a different address in a large pool, no address ever reaches maxretry, nothing is ever banned, every jail is healthy, and your logs fill with failures.
No combination of findtime and maxretry fixes this, because the model is per address and the attack is not. The response has to be based on the pattern of behaviour rather than on repeated failures from one source.
This is the category SecAI sits in. It watches behaviour across your servers, blocks sources within seconds of a pattern emerging rather than after a per-address threshold, and applies what one server learns to the rest of the fleet. It also monitors what fail2ban never looked at: file integrity, privilege changes, webshells, package vulnerabilities and outbound connections. The honest trade is that it is a paid subscription and it is more than a blocking tool, so if all you want is to stop SSH brute force on one box, fail2ban configured correctly is the cheaper answer.
How to choose
Keep fail2ban if it is working, one server, and you want zero cost and zero new dependencies. Confirm the jail actually reads your logs first.
Choose SSHGuard if SSH is all you protect and you want something smaller than fail2ban.
Choose nftables rate limiting if you want no daemon at all and can accept having no record of what was blocked.
Choose CrowdSec if you want to block known-bad sources before they reach you and can carry the extra operational surface.
Choose a host agent if the attacks are distributed, if you run several servers and want one to teach the others, or if per-host log parsing is no longer the biggest gap in what you can see.