CrowdSec Security Engine: AppSec, Multi-Machine Deployment, and Advanced Configuration
If you have already deployed CrowdSec for basic log-based intrusion prevention, you are using maybe thirty percent of what it can do. CrowdSec's Security Engine includes an application security component that acts as a web application firewall, supports centralized multi-machine deployments through its Local API architecture, and provides a scenario development framework for writing custom detection logic. This guide covers the advanced features that turn CrowdSec from a Fail2ban replacement into a real security platform.
Photo by selcuk sarikoz on Unsplash

The AppSec Component: CrowdSec as a WAF
CrowdSec's AppSec (Application Security) component is a web application firewall that inspects HTTP requests before they reach your application. Unlike the log-based detection engine that reacts after an attack is logged, AppSec operates inline -- it evaluates every incoming request and can block malicious traffic in real-time.
How AppSec Differs From Log-Based Detection
Traditional CrowdSec workflow: Attack happens, gets logged, CrowdSec reads the log, creates a ban decision, bouncer enforces it on the next request. The first attack always succeeds.
AppSec workflow: Request arrives at the reverse proxy, the bouncer sends it to CrowdSec's AppSec engine for inspection, malicious requests are blocked immediately. The first attack is caught.
Enabling AppSec
AppSec works through a supported bouncer (the Traefik, Nginx, or HAProxy bouncer). The bouncer sends request details to CrowdSec for inspection rather than just checking IP-based decisions.
Install the AppSec rules:
sudo cscli collections install crowdsecurity/appsec-virtual-patching
sudo cscli collections install crowdsecurity/appsec-generic-rules
Configure the AppSec component in your CrowdSec acquisition config:
# /etc/crowdsec/acquis.d/appsec.yaml
listen_addr: 0.0.0.0:7422
appsec_config: crowdsecurity/appsec-default
name: myAppSec
source: appsec
labels:
type: appsec
Then configure your bouncer to forward requests to the AppSec endpoint. For the Nginx bouncer:
# In nginx config
crowdsec_appsec_url http://localhost:7422;
crowdsec_appsec_action ban; # or captcha, or log
What AppSec Catches
The default rule sets cover:
- SQL injection attempts in query parameters, headers, and body
- Cross-site scripting (XSS) payloads
- Path traversal (directory traversal) attacks
- Remote code execution patterns
- Log4Shell and known CVE exploits via virtual patching rules
- Scanner fingerprinting (common security scanner signatures)
You can write custom AppSec rules to match your application's specific attack surface.
Multi-Machine LAPI Deployment
For anything beyond a single server, CrowdSec supports a centralized deployment model using its Local API (LAPI) architecture.
The Architecture
Instead of running a full CrowdSec instance on every machine, you designate one machine as the LAPI server and run lightweight agents on everything else:
- LAPI Server: Runs the full CrowdSec engine, stores decisions, connects to the CrowdSec Central API for community blocklists
- Agents: Run on each machine, parse logs, send alerts to the central LAPI
- Bouncers: Can run anywhere, poll the central LAPI for decisions
This means a ban decision on any machine is immediately enforced across all machines.
Docker Compose: Centralized LAPI
# On the LAPI server
services:
crowdsec-lapi:
image: crowdsecurity/crowdsec:latest
environment:
COLLECTIONS: >-
crowdsecurity/linux
crowdsecurity/nginx
crowdsecurity/traefik
crowdsecurity/http-cve
crowdsecurity/appsec-virtual-patching
DISABLE_AGENT: "false"
volumes:
- crowdsec_config:/etc/crowdsec
- crowdsec_data:/var/lib/crowdsec/data
- /var/log:/var/log:ro
ports:
- "8080:8080" # LAPI port
- "7422:7422" # AppSec port
- "6060:6060" # Prometheus metrics
restart: unless-stopped
volumes:
crowdsec_config:
crowdsec_data:
Registering Remote Agents
On the LAPI server, generate a registration token:
docker exec crowdsec-lapi cscli machines add worker-01 --auto
# Note the password output
On the remote machine, configure the agent to point to the central LAPI:
# /etc/crowdsec/config.yaml.local on the remote agent
api:
client:
credentials_path: /etc/crowdsec/local_api_credentials.yaml
# /etc/crowdsec/local_api_credentials.yaml
url: http://lapi-server:8080
login: worker-01
password: "the-generated-password"
Registering Remote Bouncers
Similarly, bouncers on any machine can connect to the central LAPI:
# On the LAPI server
docker exec crowdsec-lapi cscli bouncers add nginx-bouncer-web01
# Use the generated API key in the bouncer's configuration
Writing Custom Parsers
When your logs do not match any existing parser from the Hub, you need to write your own. Parsers use Grok patterns (similar to Logstash) to extract structured data from log lines.
Parser Structure
# /etc/crowdsec/parsers/s01-parse/my-app.yaml
name: my-company/my-app-logs
description: "Parse my custom application logs"
filter: "evt.Parsed.program == 'my-app'"
onsuccess: next_stage
nodes:
- grok:
pattern: '%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} \[%{DATA:module}\] %{IP:source_ip} - %{GREEDYDATA:message}'
apply_on: message
statics:
- meta: log_type
value: my-app
- meta: source_ip
expression: evt.Parsed.source_ip
Test your parser without deploying it:
echo '2026-02-14T10:30:00Z ERROR [auth] 192.168.1.100 - Failed login for user admin' | \
sudo cscli explain --type my-app --log -
The cscli explain command shows you exactly how CrowdSec processes a log line through each parser stage, which is invaluable for debugging.
Like what you're reading? Subscribe to Self-Hosted Weekly — free weekly guides in your inbox.
Writing Custom Scenarios
Once your parser extracts structured data, scenarios define what constitutes an attack.
# /etc/crowdsec/scenarios/my-app-bruteforce.yaml
type: leaky
name: my-company/my-app-bruteforce
description: "Detect brute force login attempts on my app"
filter: "evt.Meta.log_type == 'my-app' && evt.Meta.level == 'ERROR' && evt.Parsed.message contains 'Failed login'"
groupby: evt.Meta.source_ip
capacity: 10
leakspeed: 1m
blackhole: 10m
reprocess: true
labels:
service: my-app
type: bruteforce
remediation: true
This scenario uses the "leaky bucket" model: it tolerates up to 10 failed logins per minute from a single IP. The bucket leaks at one event per minute, so sustained low-rate attacks are also caught. The blackhole period prevents re-triggering for 10 minutes after a ban.
Scenario Types
- leaky: Leaky bucket -- classic rate limiting, good for brute force
- trigger: Fires immediately on a single matching event, good for known-bad patterns
- conditional: Fires when a condition is met across multiple event types
Allowlisting and Tuning
False positives are the enemy of any IPS. CrowdSec provides several allowlisting mechanisms.
IP Allowlists
# /etc/crowdsec/parsers/s02-enrich/my-whitelist.yaml
name: my-company/my-whitelist
description: "Whitelist internal and VPN IPs"
whitelist:
reason: "Internal network and VPN"
ip:
- "10.0.0.0/8"
- "172.16.0.0/12"
- "192.168.0.0/16"
- "203.0.113.50" # Office static IP
cidr:
- "100.64.0.0/10" # Tailscale
Expression-Based Allowlists
For more granular control, use expression-based whitelists that evaluate parsed event data:
whitelist:
reason: "Monitoring system health checks"
expression:
- "evt.Meta.http_user_agent contains 'UptimeKuma'"
- "evt.Meta.http_path == '/health' && evt.Meta.source_ip in ['10.0.0.5']"
Prometheus Metrics
CrowdSec exposes Prometheus metrics on port 6060 by default, giving you visibility into:
- Parsed lines per source
- Active decisions by type and origin
- Bucket overflows (scenario triggers)
- LAPI request latency
- Parser performance
Add CrowdSec to your Prometheus scrape config:
- job_name: 'crowdsec'
static_configs:
- targets: ['crowdsec:6060']
Build a Grafana dashboard to track attack trends, bouncer activity, and parser health across your entire infrastructure.
Production Hardening
Secure the LAPI
In multi-machine deployments, the LAPI port should only be accessible to trusted agents and bouncers. Use firewall rules or a VPN (WireGuard/Tailscale) to restrict access. Never expose port 8080 to the public internet.
Enable TLS for Agent-LAPI Communication
For deployments across untrusted networks, configure TLS on the LAPI:
# config.yaml.local
api:
server:
tls:
cert_file: /etc/crowdsec/ssl/cert.pem
key_file: /etc/crowdsec/ssl/key.pem
Monitor Decision Counts
An unusually high number of decisions can indicate either a real attack surge or a parser misconfiguration causing false positives. Set up alerts for decision count spikes.
Regular Hub Updates
sudo cscli hub update && sudo cscli hub upgrade
New vulnerability signatures and parser improvements ship through the Hub regularly. Automate updates with a weekly cron job, but review changelogs for breaking changes.
The Bottom Line
CrowdSec's Security Engine is more than a log-based IPS. The AppSec component provides real-time request inspection, the LAPI architecture scales to any number of machines with centralized decision-making, and the parser/scenario framework lets you build detection for any application. If you are running CrowdSec only for SSH brute force protection, you are leaving most of its capability on the table. Deploy AppSec behind your reverse proxy, centralize your LAPI, and write custom scenarios for your applications. The security posture improvement is significant and the operational overhead is minimal.
