Updated 22 October 2026
CrowdSec is an open source IPS (Intrusion Prevention System) that watches your server logs for hostile behavior and bans the IPs behind it. The interesting part is what happens after the ban: your install reports the attack to the CrowdSec network, and in exchange you receive a curated blocklist built from what every other install saw. Attackers get blocked on your server before they've sent it a single request.
I moved my own boxes off fail2ban and onto CrowdSec in 2024, and this is the explainer I wish someone had handed me back then, written for people who already run servers and want the real picture instead of the pitch.
Everything below is checked against Security Engine 1.7.8, released in May 2026 and still the version LumaDock's template ships; the current release is 1.8.1 (September 2026), which adds bot detection. The engine is MIT licensed, written in Go and sits at 13.8k stars on the CrowdSec GitHub repository. The company behind it sells threat intelligence on top of the free engine, and that split matters, so I'll cover exactly where the paid line sits further down.
How the CrowdSec architecture works
The pipeline has four stages, and once you see them the whole product makes sense. The Security Engine (the docs now call the detection half a Log Processor, though everyone I know still says agent) tails your data sources: flat log files, journald, syslog, Docker container output. Parsers normalize each line into structured events. Scenarios then watch those events for patterns, and most of them are leaky buckets: ten failed SSH logins from the same IP inside a minute overflows the bucket and an alert fires.
An alert doesn't block anything by itself. It goes to the Local API (LAPI), which turns it into a decision, typically "ban this IP for four hours". Enforcement is a separate program called a Remediation Component, still universally known as a bouncer. The firewall bouncer writes iptables or nftables rules, the nginx bouncer rejects requests inside the web server, and there are bouncers for Traefik, Cloudflare, HAProxy, OPNsense and plenty more. On plain VPSes I run the firewall bouncer with iptables, because a banned IP then loses every port at once, SSH included.
Decisions don't have to be bans either. Profiles in /etc/crowdsec/profiles.yaml map alerts to remediation types and durations, so a web scanner can get a captcha challenge instead of a hard block while an SSH brute forcer gets the full four hours. The nginx and Cloudflare bouncers both handle captcha decisions, which matters on anything commercial: a false positive behind a captcha solves itself in five seconds, while a false positive behind a dropped connection becomes a support ticket. I keep bans for infrastructure ports and captchas for anything a paying human might legitimately touch.
Splitting detection from enforcement sounds academic until you run more than one machine. CrowdSec calls it "detect here, remedy there": several servers can stream alerts to a single LAPI, and every bouncer in the fleet enforces the merged decision list. One web node catches a credential stuffer and your mail server bans the same IP seconds later. State lives in a small local database, SQLite by default and PostgreSQL or MariaDB when a fleet shares one LAPI, and the trust boundary is clean: bouncers authenticate with API keys, machines with credentials, and the answer to "what does this component talk to" is always the LAPI. fail2ban has no answer to that, which is a large part of why I switched (the full argument is in my CrowdSec vs fail2ban comparison).
The community blocklist and signal curation
When a scenario fires, your engine sends a signal to the Central API (CAPI): the offending IP, the scenario name, a timestamp and nothing else. Your log lines never leave the box. CrowdSec's backend cross-checks signals from the whole network, weighs how many independent installs reported the same IP, filters out false positives and poisoning attempts and publishes the survivors as the community blocklist. Every enrolled engine pulls that list back down, and bouncers enforce it alongside your local decisions.
The curation is the whole point. A raw feed of "IPs somebody somewhere banned" would be dangerous to enforce; a home user misconfiguring their own NAS shouldn't get their IP blocked on ten thousand servers. An address only makes the list once the consensus engine trusts the reports, and in two years of enforcing it in blocking mode on production hosts I haven't traced a single customer complaint back to it. The practical effect shows up in cscli metrics: once the community list has arrived, most drops come from it rather than local detection, because the background noise that hammers every public IPv4 address is already known to the network. (The network got busy enough that CrowdSec added rate limiting to CAPI in December 2025, which is a nice problem to have.)
Give a freshly installed engine some time before you look. On the server this explainer was checked on, the Central API answered received 0 new entries for almost two hours, then 15,000 addresses arrived in one pull.
Once the community list arrives it dwarfs local detection: 9,925 and 5,060 CAPI bans against single digits.
Sharing is opt-out rather than mandatory. Disable it and the engine keeps working on local detection alone, though you stop receiving the community list, which removes the best part of the deal. The give-to-get design is explicit and I find it fair. It's the same trade Waze made for road traffic: the map is only as good as the drivers reporting into it, and a solo copy with reporting switched off is just a worse map.
Collections and scenarios on the hub
Detection logic isn't baked into the binary. It lives on the CrowdSec hub as small YAML files you install with cscli. A parser teaches the engine to read a log format. A scenario describes the behavior to catch. A collection bundles everything needed for one service, so a single command pulls the sshd parser together with its brute force and slow brute force scenarios:
sudo cscli collections install crowdsecurity/sshd
The install wizard detects the services on your box and picks collections for you, which is why a default install already understands sshd and whatever web server it found. Writing your own scenario is YAML plus grok patterns, and it's genuinely nicer than maintaining regex once you've done it twice. The first time has a learning curve, I won't pretend otherwise.
A scenario file is short enough to read over coffee. The sshd brute force one declares a leaky bucket keyed on source IP, a capacity, a leak rate and a blackhole period so one attacker doesn't generate fifty duplicate alerts. Because the format is declarative, cscli hub update and cscli hub upgrade refresh your detection rules the way apt refreshes packages, no engine release required. Compare that with hand-editing regex on every box you own, which is what improving detection used to mean, and the appeal of a shared hub is obvious.
The AppSec component and virtual patching
Since release 1.6 the engine also carries a WAF layer called the AppSec Component. Web bouncers forward incoming HTTP requests to it for inspection, which catches things that never produce an error log line: exploit payloads for fresh CVEs, path traversal probes, injection attempts, scanner fingerprints. CrowdSec ships virtual patching rules for actively exploited vulnerabilities, the component runs out-of-band by default so it observes before it blocks, and you can layer the OWASP Core Rule Set on top through the embedded Coraza engine. The nginx setup is a proper tutorial of its own, so I wrote the CrowdSec AppSec WAF guide for nginx separately. Do you still need a standalone WAF after that? For most VPS stacks, no. The AppSec component covers the virtual patching cases that matter and inherits all of CrowdSec's remediation machinery; I run it in blocking mode on two production nginx frontends and the overhead hasn't been worth measuring.
The same exploitation data feeds the public CVE Explorer, launched in August 2025, where you can look up which CVEs are actively being exploited in the wild. I check it before deciding if a patch can wait until Monday.



