TL;DR — Quick Summary
CrowdSec complete guide: install, configure bouncers, custom scenarios, community blocklists, multi-server setup, and Nginx+SSH production protection on Linux.
Every internet-connected server is probed constantly — SSH scanners, web vulnerability crawlers, credential-stuffing bots, and API abusers generate millions of malicious requests every hour. CrowdSec is a modern, open-source intrusion prevention system that goes beyond single-server log watching: it parses your logs locally, detects attack patterns using behavioral scenarios, and shares anonymized attacker IPs with a global community to build crowd-sourced blocklists. This guide covers the complete CrowdSec setup: architecture, installation on Debian/Ubuntu and RHEL/Rocky, collections, bouncers, custom scenarios, whitelists, multi-server deployment, and a production hardening walkthrough protecting Nginx and SSH.
Prerequisites
Before you begin, ensure you have:
- A Linux server running Ubuntu 20.04/22.04/24.04, Debian 11/12, or RHEL/Rocky/AlmaLinux 8/9
- Root or sudo access
- systemd as the init system
- iptables, nftables, or firewalld available for the firewall bouncer
- Basic familiarity with YAML configuration files
How CrowdSec Works
CrowdSec separates threat detection from threat enforcement across three layers:
1. Agent (detection)
The CrowdSec agent reads logs from files, journald, Docker, Kafka, or syslog. Logs pass through a multi-stage parsing pipeline: S00-raw normalizes the raw text, S01-parse extracts structured fields (IP, timestamp, HTTP method, path), and S02-enrich adds GeoIP and CTI data. Parsed events feed into scenarios — YAML state machines that implement leaky-bucket, trigger, or counter logic to identify attack patterns.
2. Local API (coordination) The Local API (LAPI) receives decisions from the agent, stores them in a SQLite or PostgreSQL database, and serves them to bouncers. In a multi-machine setup, one server runs the LAPI while all other agents and bouncers connect to it over HTTPS.
3. Central API (community intelligence)
When you enroll your instance, the Central API at api.crowdsec.net pushes community blocklists to your LAPI and receives anonymized IP reports from you. This turns every CrowdSec deployment into a sensor feeding the global threat network.
4. Bouncers (enforcement) Bouncers poll the LAPI for active decisions and enforce them: the firewall bouncer adds iptables/nftables rules, the Nginx bouncer issues HTTP 403 responses or CAPTCHA challenges, and the Cloudflare bouncer creates edge firewall rules via the Cloudflare API.
Installation
Ubuntu / Debian
curl -s https://install.crowdsec.net | sudo bash
sudo apt install crowdsec -y
sudo systemctl enable --now crowdsec
sudo systemctl status crowdsec
RHEL / Rocky / AlmaLinux
curl -s https://install.crowdsec.net | sudo bash
sudo dnf install crowdsec -y
sudo systemctl enable --now crowdsec
Docker
services:
crowdsec:
image: crowdsecurity/crowdsec:latest
restart: unless-stopped
environment:
COLLECTIONS: "crowdsecurity/linux crowdsecurity/nginx crowdsecurity/sshd"
volumes:
- /var/log:/var/log:ro
- crowdsec_data:/var/lib/crowdsec/data
- crowdsec_config:/etc/crowdsec
ports:
- "8080:8080"
volumes:
crowdsec_data:
crowdsec_config:
Kubernetes (Helm)
helm repo add crowdsec https://crowdsecurity.github.io/helm-charts
helm repo update
helm install crowdsec crowdsec/crowdsec \
--set agent.acquisition[0].namespace=default \
--set agent.acquisition[0].podName="*" \
--set agent.acquisition[0].program=nginx
Installing Collections
Collections bundle parsers and scenarios for a specific service. Install them with cscli:
# Core Linux collection (auth, syslog)
sudo cscli collections install crowdsecurity/linux
# SSH brute-force detection
sudo cscli collections install crowdsecurity/sshd
# Nginx attack detection (auth failures, path scanning, bad bots)
sudo cscli collections install crowdsecurity/nginx
# Apache
sudo cscli collections install crowdsecurity/apache2
# WordPress
sudo cscli collections install crowdsecurity/wordpress
# Reload after installing new collections
sudo systemctl reload crowdsec
List installed hub content:
sudo cscli hub list
sudo cscli collections list
sudo cscli scenarios list
sudo cscli parsers list
Log Acquisition
CrowdSec discovers log sources via /etc/crowdsec/acquis.yaml. Multiple acquisition methods are supported:
File source
filenames:
- /var/log/nginx/access.log
- /var/log/nginx/error.log
labels:
type: nginx
# --- (next source)
filenames:
- /var/log/auth.log
labels:
type: syslog
journald / systemd
source: journalctl
journalctl_filter:
- "_SYSTEMD_UNIT=sshd.service"
labels:
type: syslog
Docker containers
source: docker
container_name:
- nginx
- myapp
labels:
type: nginx
Syslog (UDP/TCP)
source: syslog
listen_addr: 0.0.0.0
listen_port: 514
labels:
type: syslog
After editing acquis.yaml, restart the agent:
sudo systemctl restart crowdsec
Scenarios and Parsers
Parser pipeline stages
Parsers transform raw log lines into structured events:
s00-raw— decode timestamps, split fieldss01-parse— apply grok patterns per log type (nginx, sshd, postfix…)s02-enrich— add GeoIP, AS number, CrowdSec CTI tags
A parser is a YAML file with a filter expression and statics that populate event fields. The crowdsecurity/sshd-logs parser, for example, extracts evt.Meta.source_ip from OpenSSH log lines.
Scenario types
| Type | Description | Use case |
|---|---|---|
leakybucket | Count events in a sliding window; overflow triggers decision | Brute-force (N failures in T seconds) |
trigger | Single event fires immediately | One-shot critical events |
counter | Count distinct values (e.g., distinct URLs scanned) | Scanners, enumerators |
Example custom scenario
Create /etc/crowdsec/scenarios/myapp-bruteforce.yaml:
type: leakybucket
name: myapp/bruteforce
description: "Detect brute-force on myapp login endpoint"
filter: "evt.Meta.service == 'myapp' && evt.Meta.log_type == 'auth_failed'"
groupby: "evt.Meta.source_ip"
distinct: "evt.Meta.username"
capacity: 5
leakspeed: "10s"
blackhole: "5m"
labels:
service: myapp
type: bruteforce
remediation: true
Key fields:
| Field | Meaning |
|---|---|
capacity | Max bucket fill before overflow |
leakspeed | Rate at which bucket drains (one event per interval) |
blackhole | Minimum time between repeated overflows for the same IP |
groupby | What to group events by (usually source IP) |
distinct | Count distinct values (prevents one IP testing many usernames from evading a single-credential count) |
remediation: true | Overflow results in a ban decision |
Installing and Configuring Bouncers
Firewall bouncer (iptables/nftables)
# iptables backend
sudo apt install crowdsec-firewall-bouncer-iptables -y
# nftables backend
sudo apt install crowdsec-firewall-bouncer-nftables -y
sudo systemctl enable --now crowdsec-firewall-bouncer
The bouncer auto-registers with the local LAPI. Verify:
sudo cscli bouncers list
Nginx bouncer
The Nginx bouncer embeds as a Lua module, intercepting requests before they reach your application:
sudo apt install crowdsec-nginx-bouncer -y
Configuration at /etc/crowdsec/bouncers/crowdsec-nginx-bouncer.conf:
API_KEY=<auto-generated>
API_URL=http://localhost:8080
MODE=ban # ban | captcha | throttle
BAN_TEMPLATE_PATH=/etc/crowdsec/bouncers/ban.html
CAPTCHA_SITE_KEY=<recaptcha-v2-site-key>
CAPTCHA_SECRET_KEY=<recaptcha-v2-secret>
CAPTCHA_GRACE_TIME=1800
Reload Nginx after installation:
sudo nginx -t && sudo systemctl reload nginx
Cloudflare bouncer
sudo apt install crowdsec-cloudflare-bouncer -y
sudo crowdsec-cloudflare-bouncer -g <CF_API_TOKEN> -o /etc/crowdsec/bouncers/crowdsec-cloudflare-bouncer.yaml
sudo systemctl enable --now crowdsec-cloudflare-bouncer
The Cloudflare bouncer creates IP list rules in your zone’s WAF, blocking attackers at the CDN edge before traffic reaches your origin.
Custom HTTP bouncer
Any application can query the LAPI directly using the REST API:
curl -s -H "X-Api-Key: <bouncer-key>" \
"http://localhost:8080/v1/decisions?ip=203.0.113.42"
A 200 response with an array of decisions means the IP is banned; an empty [] means it is clean.
cscli Reference
# Decisions
sudo cscli decisions list # All active bans
sudo cscli decisions add -i 203.0.113.42 # Manual ban
sudo cscli decisions add -r 10.0.0.0/8 -t ban -d 1h # Ban entire CIDR
sudo cscli decisions delete -i 203.0.113.42 # Remove ban
# Alerts
sudo cscli alerts list # Recent triggered scenarios
sudo cscli alerts inspect <id> # Full alert context
# Hub management
sudo cscli hub list # All installed content
sudo cscli hub update # Refresh hub index
sudo cscli collections upgrade crowdsecurity/nginx # Upgrade a collection
# Machine management (multi-server)
sudo cscli machines list # Registered agents
sudo cscli machines add agent-web-02 --auto # Register new agent
# Bouncer management
sudo cscli bouncers list # Registered bouncers
sudo cscli bouncers add my-bouncer # Create bouncer API key
# Metrics
sudo cscli metrics # Full parser/scenario stats
Community Blocklists and Central API
Enrolling with the Central API unlocks community-sourced blocklists:
# Get your enrollment token from app.crowdsec.net
sudo cscli console enroll <your-enrollment-token>
sudo systemctl restart crowdsec
After enrollment, the LAPI receives blocklist updates every 30 minutes. Community lists include:
- CrowdSec IP reputation list — IPs seen attacking CrowdSec deployments worldwide
- Firehol Level 1 — known malicious IPs
- Tor exit nodes — optional, for blocking anonymous traffic
- Proxy/VPN lists — cloud provider exit IPs used by bots
Each decision from the Central API carries a type: ban (hard block), captcha (CAPTCHA challenge), or throttle (rate limit). The Nginx and custom bouncers can act on all three types; the firewall bouncer only applies ban decisions.
Monitor your CTI dashboard at app.crowdsec.net to see your instance’s contribution to the network and the global threat landscape.
Whitelists
Whitelists prevent trusted IPs from being banned. CrowdSec supports two whitelist types:
Parser whitelist (pre-scenario)
Create /etc/crowdsec/parsers/s02-enrich/mywhitelist.yaml:
name: mycompany/whitelists
description: "Whitelist office and monitoring IPs"
whitelist:
reason: "Internal and trusted IPs"
ip:
- "192.168.1.0/24"
- "10.0.0.0/8"
- "203.0.113.10"
cidr:
- "172.16.0.0/12"
Parser whitelists drop events entirely before they reach scenarios.
Postoverflow whitelist (post-scenario)
If you need to whitelist after a scenario overflows (e.g., allow your own monitoring tool even if it triggers a scenario), use a postoverflow whitelist:
name: mycompany/postoverflow-whitelist
description: "Allow synthetic monitoring from known IPs"
whitelist:
reason: "Uptime monitoring"
expression:
- "evt.Overflow.Alert.Source.IP in ['203.0.113.100', '203.0.113.101']"
Place this in /etc/crowdsec/postoverflows/s01-whitelist/.
Multi-Server Setup
In a fleet deployment, one machine runs the LAPI and all others register as agents:
LAPI server
The LAPI is already running if you installed CrowdSec normally. Ensure it listens on a network interface:
# /etc/crowdsec/config.yaml
api:
server:
listen_uri: 0.0.0.0:8080
tls:
cert_file: /etc/crowdsec/ssl/cert.pem
key_file: /etc/crowdsec/ssl/key.pem
Agent registration
On each additional server:
# Install CrowdSec agent only (no LAPI)
sudo apt install crowdsec -y
# Register with the remote LAPI
sudo cscli lapi register -u https://lapi-server:8080
# On the LAPI server, validate:
sudo cscli machines validate <machine-id>
Bouncer connection to remote LAPI
Edit the bouncer config to point at the LAPI server instead of localhost:
# /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml
api_url: https://lapi-server:8080
api_key: <bouncer-key-from-lapi-server>
All agents report events to the LAPI, all bouncers receive decisions from it, and the LAPI handles Central API sync centrally.
Monitoring: Prometheus and Grafana
CrowdSec exposes Prometheus metrics at http://localhost:6060/metrics. Add a scrape job:
# prometheus.yml
scrape_configs:
- job_name: crowdsec
static_configs:
- targets: ["localhost:6060"]
Import the official CrowdSec Grafana dashboard (ID 14584) for a visual overview of:
- Decisions issued per hour
- Top attacked services
- Parser hit rates and error counts
- Scenario overflow frequency
- Blocked IP counts by country
Quick CLI metrics check:
sudo cscli metrics
This shows events read, parsed, unparsed (config gaps to investigate), and decisions per scenario.
CrowdSec vs Alternatives
| Tool | Mechanism | Language | Multi-server | Community Intelligence | Bouncers |
|---|---|---|---|---|---|
| CrowdSec | Behavioral scenarios | Go | Native LAPI | Yes (Central API) | Firewall, Nginx, CF, custom |
| Fail2Ban | Log regex | Python | Manual sync | No | iptables, nftables, firewalld |
| Suricata | Network IDS/IPS | C | Cluster mode | Ruleset subscriptions | NFQueue |
| OSSEC/Wazuh | HIDS + log analysis | C | Manager-agent | Wazuh cloud rules | Active response |
| ModSecurity | WAF (HTTP layer) | C | Reverse proxy | OWASP CRS | Nginx/Apache module |
| Cloudflare WAF | Edge firewall | N/A | Global CDN | CF threat intel | CF edge only |
Choose CrowdSec when you run multiple Linux servers, want community threat intelligence, and need flexible bouncer enforcement at firewall, application, or CDN layers.
Choose Fail2Ban for a simple, single-server setup where regex-based log matching is sufficient.
Choose Suricata when you need network-layer packet inspection rather than log analysis.
Choose ModSecurity/Cloudflare WAF for HTTP-specific protection at the application or CDN edge.
Production Deployment: Nginx + SSH Protection
Here is a complete production hardening scenario for a server running Nginx and SSH:
Step 1 — Install CrowdSec and collections:
curl -s https://install.crowdsec.net | sudo bash
sudo apt install crowdsec -y
sudo cscli collections install crowdsecurity/linux \
crowdsecurity/sshd \
crowdsecurity/nginx
Step 2 — Configure log acquisition at /etc/crowdsec/acquis.yaml:
filenames:
- /var/log/nginx/access.log
- /var/log/nginx/error.log
labels:
type: nginx
# --- (next source)
source: journalctl
journalctl_filter:
- "_SYSTEMD_UNIT=sshd.service"
labels:
type: syslog
Step 3 — Install firewall bouncer:
sudo apt install crowdsec-firewall-bouncer-nftables -y
sudo systemctl enable --now crowdsec-firewall-bouncer
Step 4 — Whitelist trusted IPs:
# /etc/crowdsec/parsers/s02-enrich/whitelist.yaml
name: myserver/whitelist
description: "Trusted IPs"
whitelist:
reason: "Office and VPN"
ip:
- "192.168.1.0/24"
Step 5 — Enroll with Central API:
sudo cscli console enroll <token-from-app.crowdsec.net>
sudo systemctl restart crowdsec
Step 6 — Verify protection is active:
sudo cscli decisions list
sudo cscli metrics
sudo cscli bouncers list
Within minutes of starting CrowdSec on an SSH-exposed server, the crowdsecurity/sshd-bf scenario will begin triggering on brute-force attempts. The firewall bouncer immediately drops all traffic from banned IPs at the nftables level before any connection reaches sshd.
Gotchas and Edge Cases
- False positives from load balancers: If all traffic arrives through a reverse proxy, CrowdSec sees only the proxy IP. Configure
X-Forwarded-Forparsing or add the proxy IP to the whitelist and ensure the real client IP is extracted. - Docker log acquisition: Docker logs require the
source: dockeracquisition type. Bind-mounting/var/logdoes not work for containers writing to stdout/stderr. - Parser coverage gaps: Check
sudo cscli metricsfor highunparsedcounts — these indicate log lines that no installed parser matches, meaning attacks could go undetected. - Bouncer API key expiry: Bouncer API keys do not expire by default, but if you regenerate them (e.g., after a LAPI reinstall), update every bouncer’s config file and restart the bouncer service.
- LAPI TLS in multi-server mode: Always use TLS for the LAPI when agents connect over the network. Use a self-signed cert or Let’s Encrypt — the
csclitool accepts a--insecureflag only for initial setup. - Community blocklists and false positives: Cloud providers, CDNs, and shared hosting IPs may appear in community lists. Review
cscli decisions list --origin listsand add legitimate IPs to your whitelist.
Summary
CrowdSec delivers a layered, community-powered intrusion prevention system that scales from a single VPS to a multi-datacenter fleet:
- The agent parses logs through a staged pipeline and evaluates events against YAML scenarios using leaky-bucket, trigger, and counter logic
- The Local API coordinates decisions and connects bouncers to agents in multi-server deployments
- Bouncers enforce decisions at the firewall (iptables/nftables), application (Nginx), or CDN (Cloudflare) layer
csclimanages collections, decisions, alerts, machines, bouncers, and metrics from the command line- Community blocklists via the Central API add global threat intelligence with zero configuration overhead
- Custom scenarios and whitelists let you tune protection precisely for your environment
- Prometheus metrics and Grafana dashboards provide full operational visibility