Crowdsec with Traefik and Nginx Bouncers

CrowdSec is a collaborative, open-source intrusion prevention system that analyzes logs to detect attacks and shares threat intelligence across its community network. By integrating CrowdSec bouncers with Traefik and Nginx, you can automatically block attackers at the reverse proxy layer before requests reach your applications.

Prerequisites

  • Ubuntu/Debian or CentOS/Rocky Linux
  • Nginx or Traefik as your reverse proxy
  • Root or sudo access
  • Open port 8080 (local CrowdSec API)

Installing CrowdSec

# Ubuntu/Debian
curl -s https://install.crowdsec.net | sudo bash
sudo apt-get install -y crowdsec

# CentOS/Rocky
curl -s https://install.crowdsec.net | sudo bash
sudo dnf install -y crowdsec

# Verify installation and check status
sudo systemctl status crowdsec
cscli version

# Enroll your instance with the CrowdSec console (optional but recommended)
# Get the enrollment key from https://app.crowdsec.net
sudo cscli console enroll YOUR-ENROLLMENT-KEY
sudo systemctl restart crowdsec

Install Default Collections

Collections bundle parsers and scenarios for common services:

# Install core collections
sudo cscli collections install crowdsecurity/linux
sudo cscli collections install crowdsecurity/nginx
sudo cscli collections install crowdsecurity/traefik

# Install additional collections for your stack
sudo cscli collections install crowdsecurity/wordpress
sudo cscli collections install crowdsecurity/mysql
sudo cscli collections install crowdsecurity/ssh-bf  # SSH brute force

# List installed collections
sudo cscli collections list

# Update all collections
sudo cscli hub update
sudo cscli hub upgrade

Nginx Bouncer Installation

The Nginx bouncer blocks IPs at the HTTP layer by consulting the CrowdSec LAPI:

# Install the Nginx bouncer
sudo apt-get install -y crowdsec-nginx-bouncer  # Debian/Ubuntu

# Or install manually
curl -s https://packagecloud.io/crowdsec/crowdsec/gpgkey | sudo apt-key add -
# Then install crowdsec-nginx-bouncer package

# Generate an API key for the bouncer
sudo cscli bouncers add nginx-bouncer
# Save the returned API key!

# Configure the bouncer
sudo nano /etc/crowdsec/bouncers/crowdsec-nginx-bouncer.conf

Configure the bouncer:

# /etc/crowdsec/bouncers/crowdsec-nginx-bouncer.conf
API_KEY=your-api-key-from-cscli-bouncers-add
API_URL=http://127.0.0.1:8080
# Mode: stream (check IPs via nginx_data) or live (check each request)
MODE=stream
# Path to lua module for live mode
CROWDSEC_NGINX_BOUNCER=/usr/lib/crowdsec/lua/nginx/crowdsec_nginx_bouncer.lua
# Ban template path
BAN_TEMPLATE_PATH=/etc/crowdsec/bouncers/ban.html
CAPTCHA_TEMPLATE_PATH=/etc/crowdsec/bouncers/captcha.html

Configure Nginx to Use the Bouncer

# /etc/nginx/conf.d/crowdsec.conf

lua_package_path '/usr/lib/crowdsec/lua/lib/?.lua;;';

init_by_lua_block {
    cs = require "crowdsec_nginx_bouncer"
    cs.init("/etc/crowdsec/bouncers/crowdsec-nginx-bouncer.conf")
}

access_by_lua_block {
    cs.allow()
}

For Nginx sites:

# /etc/nginx/sites-available/myapp
server {
    server_name myapp.yourdomain.com;
    listen 443 ssl;

    # CrowdSec check runs via the global access_by_lua_block
    # No additional config needed per-site

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
sudo nginx -t && sudo systemctl reload nginx
sudo systemctl enable --now crowdsec-nginx-bouncer

Traefik Bouncer Configuration

Use the Traefik bouncer as a middleware:

# Generate API key for Traefik bouncer
sudo cscli bouncers add traefik-bouncer

Docker Compose with Traefik

# docker-compose.yml
version: '3'

services:
  traefik:
    image: traefik:v3.0
    command:
      - --api.insecure=true
      - --providers.docker=true
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik/traefik.yml:/traefik.yml:ro
      - ./traefik/dynamic.yml:/dynamic.yml:ro

  # CrowdSec Traefik bouncer (as a forwardAuth middleware)
  crowdsec-bouncer:
    image: fbonalair/traefik-crowdsec-bouncer:latest
    environment:
      CROWDSEC_BOUNCER_API_KEY: your-traefik-bouncer-api-key
      CROWDSEC_AGENT_HOST: host.docker.internal:8080
      # host.docker.internal resolves to host IP in Docker
    extra_hosts:
      - "host.docker.internal:host-gateway"
    restart: unless-stopped

  myapp:
    image: myapp:latest
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.myapp.rule=Host(`myapp.yourdomain.com`)"
      - "traefik.http.routers.myapp.middlewares=crowdsec@file"

Create the Traefik dynamic configuration:

# traefik/dynamic.yml
http:
  middlewares:
    crowdsec:
      forwardAuth:
        address: http://crowdsec-bouncer:8080/api/v1/forwardAuth
        trustForwardHeader: true

Traefik Plugin (Alternative)

# traefik.yml static configuration
experimental:
  plugins:
    bouncer:
      moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin
      version: v1.3.3
# dynamic.yml with plugin
http:
  middlewares:
    crowdsec-bouncer:
      plugin:
        bouncer:
          crowdsecLapiKey: your-api-key
          crowdsecLapiHost: http://crowdsec:8080
          crowdsecMode: live
          forwardedHeadersTrustedIPs:
            - 10.0.0.0/8

Custom Scenarios and Parsers

CrowdSec scenarios define detection rules:

# Create a custom scenario for your application
sudo mkdir -p /etc/crowdsec/scenarios
cat > /etc/crowdsec/scenarios/custom-api-abuse.yaml << 'EOF'
type: leaky
name: my-company/custom-api-abuse
description: "Detect API abuse - too many 429 responses"
filter: "evt.Meta.service == 'nginx' && evt.Meta.http_status == '429'"
groupby: "evt.Meta.source_ip"
capacity: 20
leakspeed: "10s"
blackhole: 5m
labels:
  service: http
  type: api-abuse
  remediation: true
EOF

# Reload CrowdSec to pick up new scenario
sudo systemctl reload crowdsec

# List active scenarios
sudo cscli scenarios list

Custom Parser

# /etc/crowdsec/parsers/s01-parse/custom-app-logs.yaml
filter: "evt.Line.Labels.type == 'custom-app'"
name: my-company/custom-app-logs
description: "Parse custom application logs"
nodes:
  - grok:
      pattern: '%{IP:source_ip} - %{USER:http_user} \[%{HTTPDATE:date}\] "%{WORD:verb} %{NOTSPACE:request}" %{INT:http_status} %{INT:bytes_read}'
      apply_on: evt.Line.Raw
statics:
  - meta: log_type
    value: http_access-log
  - meta: http_path
    expression: evt.Parsed.request
  - meta: source_ip
    expression: evt.Parsed.source_ip

Dashboard Monitoring

# View real-time alerts
sudo cscli alerts list

# View active bans/decisions
sudo cscli decisions list

# Check metrics
sudo cscli metrics

# View parser/scenario hit rates
sudo cscli metrics --url http://127.0.0.1:6060

# List bouncers and their status
sudo cscli bouncers list

# View simulation mode (test without actually banning)
sudo cscli simulation enable crowdsecurity/http-probing
sudo cscli simulation list

CrowdSec Console

The CrowdSec Console at https://app.crowdsec.net provides a hosted dashboard:

# Enroll your instance (if not done during install)
sudo cscli console enroll YOUR_KEY_FROM_APP_CROWDSEC_NET

# Enable metrics sharing
sudo cscli console enable context

# Restart to apply
sudo systemctl restart crowdsec

Managing Decisions

# Manually ban an IP
sudo cscli decisions add --ip 1.2.3.4 --duration 24h --reason "manual block"

# Ban a CIDR range
sudo cscli decisions add --range 1.2.3.0/24 --duration 48h --reason "attacking subnet"

# Remove a decision (unban)
sudo cscli decisions delete --ip 1.2.3.4

# Remove all decisions
sudo cscli decisions delete --all

# Whitelist your office IP / monitoring service
cat > /etc/crowdsec/parsers/s02-enrich/my-whitelists.yaml << 'EOF'
name: my-company/whitelists
description: "Whitelist trusted IPs"
whitelist:
  reason: "trusted monitoring and office IPs"
  ip:
    - "203.0.113.5"   # Uptime monitoring
    - "10.0.0.0/8"    # Internal network
  expression:
    - "evt.Meta.source_ip == '198.51.100.1'"
EOF

sudo systemctl reload crowdsec

Troubleshooting

Bouncer not blocking IPs:

# Check bouncer is connected to LAPI
sudo cscli bouncers list  # Should show "valid" status

# Test API key
curl -H "X-Api-Key: your-api-key" http://localhost:8080/v1/decisions

# Check decisions exist
sudo cscli decisions list

Parser not matching log lines:

# Test parser with a log line
sudo cscli explain --log '/var/log/nginx/access.log' --type nginx

# Or test a specific line
sudo cscli explain --log '1.2.3.4 - - [01/Jan/2024:00:00:00 +0000] "GET /admin HTTP/1.1" 404 100' --type nginx

High CPU usage:

# Reduce log tailing frequency or limit monitored log files
# Check /etc/crowdsec/acquis.yaml
cat /etc/crowdsec/acquis.yaml

# Disable unused parsers
sudo cscli parsers remove <unused-parser>

Conclusion

Integrating CrowdSec with Traefik or Nginx creates an automated, community-powered firewall that improves with every detected attack. Unlike IP-based blocklists, CrowdSec analyzes behavior patterns and shares threat intelligence across its entire user community — meaning attacks seen elsewhere are blocked on your server automatically. The bouncer architecture ensures minimal latency impact while providing effective protection at the reverse proxy layer.