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 fields
  • s01-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

TypeDescriptionUse case
leakybucketCount events in a sliding window; overflow triggers decisionBrute-force (N failures in T seconds)
triggerSingle event fires immediatelyOne-shot critical events
counterCount 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:

FieldMeaning
capacityMax bucket fill before overflow
leakspeedRate at which bucket drains (one event per interval)
blackholeMinimum time between repeated overflows for the same IP
groupbyWhat to group events by (usually source IP)
distinctCount distinct values (prevents one IP testing many usernames from evading a single-credential count)
remediation: trueOverflow 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

ToolMechanismLanguageMulti-serverCommunity IntelligenceBouncers
CrowdSecBehavioral scenariosGoNative LAPIYes (Central API)Firewall, Nginx, CF, custom
Fail2BanLog regexPythonManual syncNoiptables, nftables, firewalld
SuricataNetwork IDS/IPSCCluster modeRuleset subscriptionsNFQueue
OSSEC/WazuhHIDS + log analysisCManager-agentWazuh cloud rulesActive response
ModSecurityWAF (HTTP layer)CReverse proxyOWASP CRSNginx/Apache module
Cloudflare WAFEdge firewallN/AGlobal CDNCF threat intelCF 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-For parsing or add the proxy IP to the whitelist and ensure the real client IP is extracted.
  • Docker log acquisition: Docker logs require the source: docker acquisition type. Bind-mounting /var/log does not work for containers writing to stdout/stderr.
  • Parser coverage gaps: Check sudo cscli metrics for high unparsed counts — 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 cscli tool accepts a --insecure flag 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 lists and 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
  • cscli manages 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