
CrowdSec: Crowdsourced Intrusion Prevention for Everyone Else's Servers Too
Any server that gets a public IP address starts taking hits within minutes of coming online: SSH login attempts cycling through the same twenty usernames, requests probing for /wp-login.php and .env files that were never there, path traversal payloads, half-finished TLS handshakes from mass scanners running on rented botnets. None of it is personal, it’s the internet’s background radiation, and it never stops. For years the standard defense was fail2ban: tail a log file, count the failures, ban the offending IP for a while, repeat forever. It works, and plenty of people still run it happily, but it has a blind spot that gets more obvious every year: every server fights the exact same botnets in total isolation. Your box learns nothing from the fact that the IP hammering your SSH port hit a hundred other servers last week, and the moment a ban expires, all memory of the attacker is gone.
CrowdSec (source on GitHub at https://github.com/crowdsecurity/crowdsec , project site at https://crowdsec.net , MIT licensed) is what you get when you take the fail2ban idea and add the one ingredient it always lacked: a crowd. It’s a free, open-source intrusion prevention system written in Go that parses your logs, runs behavior-based scenarios against them to spot bruteforce attempts, scanning, and known exploitation patterns, and then, if you opt in, shares what it learns with every other CrowdSec instance on the internet. We run CrowdSec in front of our own services here at DreamServer, paired with Traefik as the reverse proxy and its CrowdSec bouncer, to block malicious IPs at the edge before they reach our applications. It’s the kind of component that quietly does its job in the background, exactly what you want from anything sitting in the security path.
What CrowdSec actually is
Structurally, CrowdSec splits the job into pieces that talk to each other over a small local API. The crowdsec agent does the log parsing: it tails whatever files you point it at (Nginx access logs, Traefik logs, auth.log for SSH, application logs, anything with a timestamp and an IP in it), normalizes each line through a parser, and feeds the result into detection “scenarios.” A scenario is a small, declarative rule describing a pattern of bad behavior over time: ten failed SSH logins from one IP in two minutes, a burst of 404s that looks like directory bruteforcing, a request matching a known CVE payload signature. When a scenario fires, it produces a “decision,” which is really just a statement: ban, or captcha, this IP, for this long, for this reason.
The important detail: CrowdSec itself never blocks anything. The LAPI stores decisions in a database (SQLite by default), and separate “bouncers” enforce them: a firewall bouncer driving iptables or nftables, an Nginx bouncer, a Traefik bouncer/plugin, a Cloudflare bouncer pushing bans into Cloudflare’s rules, and others for different chokepoints. The separation is deliberate: detection and enforcement are different concerns, so you can run detection on a box that has no business touching the firewall, or enforce the same decision at multiple layers at once.
Why crowdsourced detection beats fighting alone
What actually makes CrowdSec more than “fail2ban with better YAML” is the community blocklist. Every participating instance can, if you opt in, report the IPs it confirms as attackers back to a central service, and in return receive a stream of IPs other instances have already flagged. In practice, an address that started hammering someone else’s SSH port in Germany this morning can already be blocked on your server in Bucharest before it ever sends you a single packet. That’s a fundamentally different posture than fail2ban’s local-only model: instead of every server independently rediscovering the same handful of scanning botnets, the discovery happens once, somewhere, and the mitigation propagates. It doesn’t replace local detection, your own scenarios still catch things specific to your traffic, but it turns thousands of otherwise-isolated servers into something closer to a shared sensor network, a genuinely different security model, not just a marketing angle on an old idea.
What you get out of the box
The core install gives you a fairly complete toolkit without much extra work:
- A log parsing and detection engine (the
crowdsecagent) watching multiple log sources at once. - A curated catalog of parsers, scenarios, and “collections” at the Hub, hub.crowdsec.net, contributed by CrowdSec and the community, covering common stacks like Linux, SSH, Nginx, Traefik, and WordPress.
- The Local API (LAPI), the source of truth for decisions and what bouncers query.
- An ecosystem of bouncers for different enforcement points: host firewalls via iptables/nftables, Nginx, Traefik, Cloudflare, and more.
- The opt-in community blocklist, really the whole point of the project’s name.
cscli, the command-line tool for installing collections, inspecting decisions, and managing bouncers without hand-editing YAML for every change.
There’s also an optional cloud Console for visibility across a fleet, but nothing about the engine or the bouncers requires it. It’s entirely usable fully self-hosted and offline, which matters if “send our security telemetry to a third party” is a line you don’t want to cross.
Installing CrowdSec on a VPS
A minimal Docker setup looks roughly like this: the CrowdSec container reads your logs and runs its own LAPI, and a bouncer container queries that LAPI to know what to block.
# Run the CrowdSec engine, mounting the logs it should watch
docker run -d \
--name crowdsec \
--restart unless-stopped \
-v /var/log:/var/log:ro \
-v /etc/crowdsec:/etc/crowdsec \
-v crowdsec-db:/var/lib/crowdsec/data \
-p 8080:8080 \
crowdsecurity/crowdsec
# Install collections matching your stack (SSH + generic Linux)
docker exec -it crowdsec cscli collections install crowdsecurity/sshd
docker exec -it crowdsec cscli collections install crowdsecurity/linux
# Register a bouncer, then start the firewall bouncer with its key
docker exec -it crowdsec cscli bouncers add firewall-bouncer
docker run -d \
--name crowdsec-firewall-bouncer \
--restart unless-stopped \
--network host \
--cap-add=NET_ADMIN \
-e BOUNCER_KEY_FILE=/etc/crowdsec/bouncer.key \
-v /etc/crowdsec/bouncer.key:/etc/crowdsec/bouncer.key:ro \
crowdsecurity/cs-firewall-bouncer
If you’re fronting web traffic with Traefik instead of, or alongside, the host firewall, the Traefik CrowdSec bouncer plugin talks to the same LAPI and rejects requests at the reverse proxy layer, exactly the combination we run in front of our own services.
On the host firewall side, keep it simple: CrowdSec’s own bouncer handles IP-level blocking dynamically, so your static rules just need to stay out of the way for legitimate traffic:
# ufw note: keep the baseline permissive for the ports you actually serve,
# and let the CrowdSec bouncer handle dynamic IP blocking on top of it
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
If you’re setting this up on a fresh box, our VPS plans give you full root access, so nothing here needs any workarounds; you configure CrowdSec exactly like on any Linux server you own.
Configuration patterns worth knowing
Choosing collections for your actual stack
Don’t install everything the Hub offers just because it’s there. Pull the collections matching what’s actually running: crowdsecurity/sshd and crowdsecurity/linux for basically any server, crowdsecurity/nginx or crowdsecurity/traefik for your reverse proxy, crowdsecurity/wordpress if you host WordPress. Extra collections just run extra parsers against logs they’ll never match, adding noise and slowing troubleshooting later.
Whitelisting your own traffic before it bites you
The single most common CrowdSec support request is “I locked myself out.” Scenarios don’t know the difference between an attacker bruteforcing SSH and a developer who fat-fingered their password four times in a row. Before you go live, add your office and home IPs, your CI runners, and any monitoring service hitting your endpoints on a schedule, to a whitelist parser. It takes two minutes and saves an awkward out-of-band recovery later.
Wiring a bouncer that actually enforces decisions
This is the step people skip, and it’s the one that matters. A decision that nothing enforces is a log entry, not a defense. Whether you use the firewall bouncer, the Nginx bouncer, or the Traefik plugin, verify with cscli decisions list that bans are being created, then verify separately that the bouncer is actually querying the LAPI and dropping traffic. Detection without enforcement is a security theater prop.
Deciding on the community blocklist and the Console
Opting into the shared blocklist is where CrowdSec earns its name, and for most people it’s a clear win: you get ahead of IPs before they hit you. It does mean your instance reports confirmed attacker IPs upstream, so if that data-sharing model doesn’t fit your compliance posture, run CrowdSec entirely locally and skip it, you just lose the network effect. The Console is a separate, genuinely optional layer for multi-machine visibility; the engine works identically with or without it.
Where CrowdSec is not the right answer
It’s worth being honest about the edges. CrowdSec is not a SIEM: no long-term log retention, no correlation across event types, no compliance reporting, it’s a detection-and-decision engine focused on network-level bad behavior. It’s not a WAF replacement either; deep application-layer inspection, like recognizing a SQL injection attempt inside a specific POST body, is a different problem than “this IP is scanning.” It depends entirely on bouncers being deployed, an instance with no bouncer attached is just an expensive log reader. It also depends on decent parsers existing for your exact log format; an unusual application log with no matching Hub parser gets nothing out of the box until you write one. And none of this substitutes for patching: it can slow down a scanner probing a known CVE, but an unpatched vulnerability still exposes you to a patient attacker who never trips the bruteforce or scanning scenarios at all.
Alternatives we considered
fail2ban is the obvious comparison, and still a perfectly reasonable choice for a single box where you don’t need shared threat intelligence: simpler, no LAPI, no bouncer concept, just log-watching and local bans. What it doesn’t give you is CrowdSec’s network effect or its Hub ecosystem of maintained scenarios.
Wazuh sits at a completely different weight class: a full XDR/SIEM platform with file integrity monitoring, vulnerability detection, compliance reporting, and centralized log management across a fleet. If you need SIEM-grade visibility and the operational budget to run it, Wazuh is a serious tool; for a handful of VPS instances it’s usually more infrastructure than the problem calls for.
ModSecurity operates at a different layer entirely: an application-layer WAF inspecting HTTP request and response bodies against rule sets like OWASP CRS, catching SQL injection and XSS payloads inside the request itself. CrowdSec is behavior-based and network-focused; ModSecurity is content-based and application-focused. Complementary rather than competing, running both isn’t redundant.
So, should you run it?
If your current defense is either nothing or a lonely fail2ban jail rediscovering the same botnets since 2019, CrowdSec is a straightforward upgrade: free, open source, and genuinely useful the moment you install a couple of collections and wire up one bouncer. The catch is that it only does anything if you finish the job: pick the right collections, whitelist your own traffic, and deploy a bouncer that actually enforces what it decides. Start with a VPS you control end-to-end (our VPS plans give you root access to set this up exactly as described above), and if you’d rather someone else own the hardening, patching, and monitoring entirely, that’s what our server administration service is for.