Skip to main content

How to Self-Host CrowdSec: Collaborative Intrusion Prevention 2026

·OSSAlt Team
crowdsecsecurityidsipsself-hostingdockerfail2ban2026

TL;DR

CrowdSec (MIT, ~10K GitHub stars, Go) is a collaborative intrusion detection and prevention system. Like fail2ban, it detects attacks by reading logs — but then shares threat intelligence with the entire CrowdSec network, so everyone benefits. It automatically blocks known bad IPs using community-contributed blocklists. Cloudflare WAF costs $20/month for basic protection. CrowdSec gives you crowd-sourced threat intelligence for free.

Key Takeaways

  • CrowdSec: MIT, ~10K stars, Go — modern collaborative IDS/IPS
  • Crowd-sourced blocklists: Block IPs that are attacking other CrowdSec users worldwide
  • Bouncers: Enforcement components for Caddy, Nginx, iptables, Cloudflare, and more
  • Scenarios: Detect brute force, credential stuffing, port scanning, L7 DDoS
  • Console: Free web dashboard at app.crowdsec.net for monitoring
  • vs fail2ban: CrowdSec adds shared threat intelligence and a richer scenario system

How CrowdSec Works

Logs (Nginx, SSH, etc.)  →  CrowdSec Agent  →  Decisions (ban, captcha)
                              ↑ ↓                    ↓
                         CrowdSec API        Bouncers (enforce)
                              ↑ ↓
                       Community Intel
                    (crowd-sourced blocklists)
  1. Agent reads logs and detects attack patterns (scenarios)
  2. Decisions are created: ban IP, show captcha, throttle
  3. Bouncers enforce decisions at the reverse proxy, firewall, or CDN level
  4. Community: your detections contribute to the global blocklist; you receive others' detections

CrowdSec vs fail2ban

FeatureCrowdSecfail2ban
Shared threat intelYes (crowd-sourced)No (local only)
IP reputation listsYes (community)No
LanguageGoPython
PerformanceFastSlow with many rules
ActionsBan, captcha, throttleBan only
Web consoleYes (free)No
APIREST APICLI only
Bouncer ecosystemRich (Caddy, Nginx, CF)iptables only
ConfigurationYAML scenariosRegex filters

Part 1: Docker Setup

# docker-compose.yml
services:
  crowdsec:
    image: crowdsecurity/crowdsec:latest
    container_name: crowdsec
    restart: unless-stopped
    ports:
      - "8080:8080"    # API (local only — don't expose publicly)
      - "6060:6060"    # Prometheus metrics (optional)
    volumes:
      # CrowdSec config and data:
      - crowdsec_config:/etc/crowdsec
      - crowdsec_data:/var/lib/crowdsec/data

      # Log sources (mount the logs you want CrowdSec to watch):
      - /var/log:/var/log:ro
      - caddy_logs:/var/log/caddy:ro           # Caddy access logs
      # - nginx_logs:/var/log/nginx:ro          # Nginx logs
      # - /var/log/auth.log:/var/log/auth.log:ro  # SSH logs

    environment:
      # Collections to install on first run:
      COLLECTIONS: >-
        crowdsecurity/linux
        crowdsecurity/caddy
        crowdsecurity/http-cve
        crowdsecurity/whitelist-good-actors
      # crowdsecurity/nginx            # If using Nginx
      # crowdsecurity/sshd             # If SSH is exposed

      # Enroll in CrowdSec Console (optional):
      # ENROLL_KEY: "your-enrollment-key"
      # ENROLL_INSTANCE_NAME: "my-server"

volumes:
  crowdsec_config:
  crowdsec_data:
  caddy_logs:        # Your Caddy log volume
docker compose up -d

# Check it's running:
docker exec crowdsec cscli version
docker exec crowdsec cscli metrics

Part 2: Configure Log Sources

Caddy

Make sure Caddy logs to a file that CrowdSec can read:

{
    log {
        output file /var/log/caddy/access.log
        format json
    }
}

CrowdSec acquirer config:

# /etc/crowdsec/acquis.yaml (or acquis.d/caddy.yaml)
source: file
filenames:
  - /var/log/caddy/access.log
labels:
  type: caddy

Nginx

source: file
filenames:
  - /var/log/nginx/access.log
  - /var/log/nginx/error.log
labels:
  type: nginx

SSH

source: file
filenames:
  - /var/log/auth.log
labels:
  type: syslog

Docker container logs

source: docker
container_name:
  - my-webapp
labels:
  type: nginx

Part 3: Install Bouncers

Bouncers enforce CrowdSec's decisions (bans, captchas, etc.).

Caddy Bouncer

# Generate an API key for the bouncer:
docker exec crowdsec cscli bouncers add caddy-bouncer
# Outputs: API key = abc123...
# Add to docker-compose.yml:
  caddy:
    image: caddy:latest
    # Use the CrowdSec Caddy module:
    # Build a custom Caddy with: xcaddy build --with github.com/hslatman/caddy-crowdsec-bouncer
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
{
    crowdsec {
        api_url http://crowdsec:8080
        api_key abc123...
        ticker_interval 15s
    }
}

yourdomain.com {
    crowdsec
    reverse_proxy localhost:3000
}

Nginx Bouncer

# Generate bouncer API key:
docker exec crowdsec cscli bouncers add nginx-bouncer
# docker-compose.yml:
  nginx-bouncer:
    image: crowdsecurity/cs-openresty-bouncer:latest
    container_name: nginx-bouncer
    restart: unless-stopped
    environment:
      CROWDSEC_BOUNCER_API_KEY: "abc123..."
      CROWDSEC_AGENT_HOST: "crowdsec:8080"
    depends_on:
      - crowdsec

Firewall Bouncer (iptables/nftables)

# Install directly on the host:
curl -s https://install.crowdsec.net | sudo bash
sudo apt install crowdsec-firewall-bouncer-iptables

# Or nftables:
sudo apt install crowdsec-firewall-bouncer-nftables

# Configure:
sudo vim /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml
# api_url: http://localhost:8080
# api_key: abc123...

Cloudflare Bouncer

docker exec crowdsec cscli bouncers add cloudflare-bouncer
# docker-compose.yml:
  cloudflare-bouncer:
    image: crowdsecurity/cs-cloudflare-bouncer:latest
    restart: unless-stopped
    environment:
      CROWDSEC_BOUNCER_API_KEY: "abc123..."
      CROWDSEC_AGENT_HOST: "crowdsec:8080"
      CLOUDFLARE_API_TOKEN: "${CF_API_TOKEN}"
      CLOUDFLARE_ACCOUNT_ID: "${CF_ACCOUNT_ID}"

Part 4: Scenarios and Collections

List installed scenarios

docker exec crowdsec cscli scenarios list
docker exec crowdsec cscli collections list

Install additional collections

# WordPress protection:
docker exec crowdsec cscli collections install crowdsecurity/wordpress

# Traefik:
docker exec crowdsec cscli collections install crowdsecurity/traefik

# HTTP generic attacks:
docker exec crowdsec cscli collections install crowdsecurity/http-cve

# Whitelist known good bots (Google, Bing, etc.):
docker exec crowdsec cscli collections install crowdsecurity/whitelist-good-actors

What scenarios detect

ScenarioDetects
crowdsecurity/http-bfHTTP brute force (login pages)
crowdsecurity/ssh-bfSSH brute force
crowdsecurity/http-crawl-non_staticsAggressive crawlers
crowdsecurity/http-bad-user-agentKnown malicious user agents
crowdsecurity/http-path-traversalPath traversal attempts
crowdsecurity/http-sqliSQL injection attempts
crowdsecurity/http-xssCross-site scripting attempts
crowdsecurity/http-cve-*Known CVE exploits

Part 5: Managing Decisions

# View active decisions (bans):
docker exec crowdsec cscli decisions list

# Ban an IP manually:
docker exec crowdsec cscli decisions add -i 1.2.3.4 -d 24h -t ban -r "manual block"

# Ban a range:
docker exec crowdsec cscli decisions add -r 1.2.3.0/24 -d 48h -t ban -r "abusive range"

# Remove a ban:
docker exec crowdsec cscli decisions delete -i 1.2.3.4

# Whitelist your own IP:
cat >> /etc/crowdsec/parsers/s02-enrich/whitelist.yaml << 'EOF'
name: my-whitelist
description: "Whitelist my IPs"
whitelist:
  reason: "My trusted IPs"
  ip:
    - "203.0.113.10"    # Your home IP
    - "10.0.0.0/8"      # Internal network
EOF
docker exec crowdsec cscli hub update
docker compose restart crowdsec

Part 6: CrowdSec Console

The free cloud console at app.crowdsec.net provides:

  • Real-time alert visualization
  • Attack statistics and trends
  • Community blocklist status
  • Multi-instance management

Enroll your instance

# Get enrollment key from app.crowdsec.net:
docker exec crowdsec cscli console enroll YOUR_ENROLLMENT_KEY \
  --name "my-server" \
  --tags "production,web"

Part 7: Alerts and Notifications

Send alerts to ntfy

# /etc/crowdsec/notifications/ntfy.yaml
type: http
name: ntfy
log_level: info
format: |
  {{ range . -}}
  {{ .Alert.Scenario }} triggered by {{ .Alert.Source.IP }}
  {{ end -}}

url: "https://ntfy.yourdomain.com/crowdsec-alerts"
method: POST
headers:
  Title: "CrowdSec Alert"
  Priority: "high"
  Tags: "shield"
# /etc/crowdsec/profiles.yaml (add notification):
name: default_ip_remediation
filters:
  - Alert.Remediation == true && Alert.GetScope() == "Ip"
decisions:
  - type: ban
    duration: 4h
notifications:
  - ntfy
on_success: break

Part 8: Metrics and Monitoring

# View metrics:
docker exec crowdsec cscli metrics

# Sample output:
# Acquisition:
#   /var/log/caddy/access.log: 15423 lines read, 12 events parsed
# Parsers:
#   crowdsecurity/caddy-logs: 12 parsed
# Scenarios:
#   crowdsecurity/http-bf: 3 triggered

# View alert history:
docker exec crowdsec cscli alerts list

# View specific alert:
docker exec crowdsec cscli alerts inspect 42

# Prometheus metrics (if port 6060 exposed):
curl localhost:6060/metrics

Maintenance

# Update:
docker compose pull
docker compose up -d

# Update hub (scenarios, parsers, collections):
docker exec crowdsec cscli hub update
docker exec crowdsec cscli hub upgrade

# Backup config:
tar -czf crowdsec-config-$(date +%Y%m%d).tar.gz \
  $(docker volume inspect crowdsec_crowdsec_config --format '{{.Mountpoint}}')

# Check bouncer connectivity:
docker exec crowdsec cscli bouncers list

# Logs:
docker compose logs -f crowdsec

See all open source security tools at OSSAlt.com/categories/security.

Comments