CrowdSec for anything internet-facing behind your reverse proxy; Fail2ban for a lone SSH port you want to protect once and never think about again. The structural difference decides it: Fail2ban can only ban an IP after it attacks you, while CrowdSec ships a community blocklist — tens of thousands of currently-active malicious IPs — that drops known attackers before their first request reaches your login page. For an exposed homelab in 2026, pre-emptive beats reactive.

How each one works

Fail2ban (Python, around since 2004) tails log files, matches failure lines against regex filters, and after N matches within a window bans the source IP via iptables or nftables on the same host. Entirely local, entirely self-contained.

CrowdSec (Go, launched 2020) starts from the same log-parsing idea but splits detection from enforcement. The agent parses logs against "scenarios" pulled from a hub; enforcement happens in "bouncers" that can live anywhere — the host firewall, Traefik, Caddy, nginx, even Cloudflare. When your agent confirms an attack, the IP and scenario (nothing else) are shared with the network, and in exchange you receive the community blocklist. You can opt out of sharing, at the cost of the list.

Head to head

Fail2banCrowdSec
DetectionYour logs onlyYour logs + community blocklist
Enforcementiptables/nftables, same hostBouncers: firewall, proxy, CDN
ConfigINI jails + regex filtersYAML scenarios from a hub
Typical RAM~30–60MB~120–180MB agent + bouncers (est.)
Multi-hostDIY scriptsNative: agents report to one LAPI
IPv6Yes (since 0.10)Yes
Data sharingNoneAttack signals out, blocklist in

The RAM difference is real but irrelevant on anything bigger than a Pi Zero. The multi-host difference matters more than it looks: one CrowdSec LAPI can take signals from your VPS, your home server, and your proxy, and ban an IP everywhere at once.

Setting up CrowdSec behind a reverse proxy

The highest-value placement is on the reverse proxy, where every exposed service's traffic already flows. With Traefik (the same shape works for Caddy and nginx — pick yours via the reverse proxy comparison):

services:
  crowdsec:
    image: crowdsecurity/crowdsec:v1.6
    environment:
      COLLECTIONS: "crowdsecurity/traefik crowdsecurity/http-cve crowdsecurity/base-http-scenarios"
    volumes:
      - ./crowdsec/config:/etc/crowdsec
      - ./crowdsec/data:/var/lib/crowdsec/data
      - traefik-logs:/var/log/traefik:ro
    restart: unless-stopped

Then register a bouncer key with docker exec crowdsec cscli bouncers add traefik-bouncer, install the Traefik CrowdSec plugin as a middleware, and point it at the agent's LAPI on port 8080. Verify it's alive with cscli metrics (are log lines being parsed?) and cscli decisions list (who's banned right now?). The http-cve collection is the quiet win — it bans IPs probing for known exploits, which is most of what hits a homelab, not password guessing. Full component docs live at docs.crowdsec.net.

Fail2ban still earns its place

For a VPS or bastion exposing only SSH, Fail2ban remains the ten-minute, zero-thought answer:

# /etc/fail2ban/jail.local
[sshd]
enabled  = true
maxretry = 3
findtime = 10m
bantime  = 1h
bantime.increment = true

bantime.increment doubles the ban on repeat offenders, which quietly ages out the persistent botnets. Honesty note: if you've disabled password authentication and use keys only — you should — the sshd jail is log hygiene rather than security. The attempts it bans were never going to succeed; it just makes journalctl readable again.

Whitelist yourself before you enable anything

The classic self-inflicted wound is banning your own phone because an app retried a stale password fifty times. Before turning on remediation, whitelist your LAN and VPN ranges: ignoreip = 192.168.0.0/16 100.64.0.0/10 in Fail2ban, or a whitelist parser in CrowdSec (/etc/crowdsec/parsers/s02-enrich/mywhitelists.yaml with your CIDRs). Also decide ban lengths like an adult: four hours stops brute force just as well as four weeks and halves the blast radius of a false positive.

Prove it works before you trust it

Both tools fail silent — a wrong log path or a stale regex parses nothing and bans nobody, while you feel protected. Test from an outside connection (a VPS, or a phone off Wi-Fi): hit a login endpoint with bad credentials six times, then confirm the ban landed. For CrowdSec, cscli alerts list should show the detection within seconds and cscli decisions list the resulting ban; for Fail2ban, fail2ban-client status sshd shows the banned IP. Then unban yourself (cscli decisions delete --ip x.x.x.x or fail2ban-client set sshd unbanip x.x.x.x) and put a quarterly calendar note on repeating the drill — log formats change with app updates, and a parser that broke in March protects nothing in July.

What difference the community list actually makes

After moving my exposed services from Fail2ban to CrowdSec with the firewall bouncer, 401s and exploit-probe 404s in the proxy access log dropped by roughly a third in the first week (my logs, not a benchmark) — those requests were being dropped at the firewall before generating a log line to react to. That's the pre-emptive advantage in practice: less noise, earlier blocks, and scenarios maintained by someone else when the next mass-exploited CVE lands.

What I'd do

Nothing exposed to the internet: neither tool — a VPN via remote access done right removes the problem instead of managing it. One exposed SSH port: Fail2ban, keys only, incremental bans, done. A reverse proxy with two or more exposed services: CrowdSec agent on the proxy host, firewall bouncer plus proxy middleware, the traefik/nginx and http-cve collections, and your own ranges whitelisted on day one. Reassess only if the LAPI's ~150MB ever matters, which on any real server it won't.