TL;DR: CrowdSec is like a community-driven immune system for your homelab. Combined with Traefik, it automatically blocks brute-force attacks, scanners, and known malicious IPs β all with a few lines of Docker Compose. Here's how to set up CrowdSec, configure the Traefik Bouncer, and actively defend your network.
π€ Why Traefik alone isn't enough
Traefik is an amazing reverse proxy. It handles SSL certificates, routing, and load balancing like a champ. But there's one thing it can't do out of the box: detect and block malicious requests.
Sure, you can set up IP whitelists or enable rate limiting. But what about brute-force attacks against your services? What about bots scanning for known vulnerabilities? What about IPs that are globally known to be malicious?
That's where CrowdSec comes in. And yes β it's free and open source. π


π‘οΈ What is CrowdSec?
CrowdSec is a collaborative Intrusion Prevention System (IPS). Think of it as Fail2ban on steroids, powered by a global community. The concept is simple:
- Detection: CrowdSec reads your log files (e.g., Traefik access logs) and identifies suspicious behavior.
- Decision: Based on defined scenarios (e.g., "more than 10 failed logins in 30 seconds"), CrowdSec makes a decision.
- Enforcement: A so-called Bouncer enforces the decision β for example, by blocking the IP.
- Community: Detected attackers are (anonymously) shared with the community. You benefit from the knowledge of all other CrowdSec users.
π CrowdSec vs. Fail2ban β What's the difference?
Sounds a lot like Fail2ban, right? But there are some crucial differences:
| Feature | Fail2ban | CrowdSec |
|---|---|---|
| Architecture | Monolithic | Agent + Bouncer (decoupled) |
| Language | Python | Go (significantly faster) |
| Community Blocklists | β | β (centralized threat intelligence) |
| Dashboard | β (CLI only) | β (Web console) |
| Docker Support | Cumbersome | First-class |
| Scenarios | Regex-based | YAML-based scenarios with buckets |
| Performance | Moderate with many logs | Excellent thanks to Go |
In short: CrowdSec is more modern, more scalable, and significantly more effective thanks to community blocklists.
βοΈ The Architecture: Agent + Bouncer
Before we dive into the configuration, let's understand the architecture. CrowdSec consists of two main components:
1. CrowdSec Agent (Security Engine)
The agent reads your log files, analyzes them using parsers and scenarios, and makes decisions. It's the "brain" of the system.
2. Bouncer
The bouncer is the "doorman." It queries the agent for current decisions and enforces them. For Traefik, there's a dedicated Traefik Bouncer Plugin that hooks directly into Traefik as middleware.
The beauty of this architecture: agent and bouncer are decoupled. You can run one agent on your server and deploy multiple bouncers at different points.

π Let's go: Docker Compose Setup
Now for the fun part! Here's the complete setup with Traefik and CrowdSec in Docker Compose. I'm assuming you already have Traefik running β if not, check out my article on migrating from Nginx Proxy Manager to Traefik.
Directory Structure
traefik/
βββ docker-compose.yml
βββ traefik/
β βββ traefik.yml # Static configuration
β βββ dynamic/
β β βββ middlewares.yml # Dynamic middleware config
β βββ logs/
β βββ access.log # Traefik access log (important!)
βββ crowdsec/
βββ config/
β βββ acquis.yaml # Log sources for CrowdSec
βββ data/ # CrowdSec database
Docker Compose
Here's the docker-compose.yml. Pay special attention to the volumes β CrowdSec needs access to the Traefik access logs:
services:
traefik:
image: traefik:v3.3
container_name: traefik
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik/traefik.yml:/etc/traefik/traefik.yml:ro
- ./traefik/dynamic:/etc/traefik/dynamic:ro
- ./traefik/logs:/var/log/traefik
- ./traefik/acme.json:/acme.json
networks:
- proxy
labels:
- "traefik.enable=true"
depends_on:
- crowdsec
crowdsec:
image: crowdsecurity/crowdsec:latest
container_name: crowdsec
restart: unless-stopped
environment:
- COLLECTIONS=crowdsecurity/traefik crowdsecurity/http-cve crowdsecurity/base-http-scenarios
- GID=${GID-1000}
- BOUNCER_KEY_traefik=${CROWDSEC_BOUNCER_KEY}
volumes:
# CrowdSec config and data
- ./crowdsec/config:/etc/crowdsec
- ./crowdsec/data:/var/lib/crowdsec/data
# Access to Traefik logs β this is the key!
- ./traefik/logs:/var/log/traefik:ro
networks:
- proxy
ports:
- "127.0.0.1:8080:8080" # API only locally accessible
networks:
proxy:
external: true
β οΈ Important: The CROWDSEC_BOUNCER_KEY environment variable needs to be defined in a .env file or generated on first start. More on that shortly.
π Preparing Traefik for CrowdSec
For CrowdSec to read Traefik's logs, you need to enable access logging. Here are the relevant parts of traefik.yml:
# traefik/traefik.yml
api:
dashboard: true
insecure: false
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
http:
tls:
certResolver: letsencrypt
middlewares:
- crowdsec@file # Enable CrowdSec middleware globally!
providers:
docker:
exposedByDefault: false
network: proxy
file:
directory: /etc/traefik/dynamic
watch: true
certificatesResolvers:
letsencrypt:
acme:
email: [email protected]
storage: /acme.json
httpChallenge:
entryPoint: web
# Access Log β MUST be enabled for CrowdSec!
accessLog:
filePath: "/var/log/traefik/access.log"
format: json
filters:
statusCodes:
- "200-599"
fields:
headers:
defaultMode: drop
names:
User-Agent: keep
X-Forwarded-For: keep
The key point here: the access log must be written in JSON format. CrowdSec has specialized parsers for Traefik JSON logs.
π§ CrowdSec Configuration
acquis.yaml β Where do the logs come from?
CrowdSec needs a configuration that tells it which logs to read. Create the file crowdsec/config/acquis.yaml:
# crowdsec/config/acquis.yaml
filenames:
- /var/log/traefik/access.log
labels:
type: traefik
That's it. CrowdSec now knows to read the Traefik logs and will automatically apply the matching parsers (which we installed via the COLLECTIONS environment variable).
Generating the Bouncer Key
On the first CrowdSec start, you need to generate an API key for the bouncer. If you set BOUNCER_KEY_traefik as an environment variable, the key is created automatically on first start. Alternatively:
# Start the container
docker compose up -d crowdsec
# Manually generate a bouncer key
docker exec crowdsec cscli bouncers add traefik-bouncer
# Output: API key for 'traefik-bouncer':
# abc123def456...
# Note this key!
π Configuring the Traefik Bouncer Plugin
Now for the crucial part: the Traefik Bouncer Plugin. There are two ways to connect CrowdSec with Traefik:
- Traefik Bouncer Plugin (recommended) β runs directly inside Traefik as middleware
- Standalone Bouncer β separate container using iptables
We're going with the plugin approach because it's more elegant and doesn't require extra network permissions.
Add the plugin to your traefik.yml (in the experimental block):
# Add to traefik.yml:
experimental:
plugins:
crowdsec:
moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin
version: v1.3.5
And the middleware configuration in traefik/dynamic/middlewares.yml:
# traefik/dynamic/middlewares.yml
http:
middlewares:
crowdsec:
plugin:
crowdsec:
enabled: true
crowdsecLapiScheme: http
crowdsecLapiHost: crowdsec:8080
crowdsecLapiKey: ${CROWDSEC_BOUNCER_KEY}
forwardedHeadersTrustedIPs:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
clientTrustedIPs:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
forwardedHeadersCustomName: X-Forwarded-For
crowdsecMode: live
updateIntervalSeconds: 15
defaultDecisionSeconds: 60
crowdsecLapiTLSInsecureVerify: false
The forwardedHeadersTrustedIPs and clientTrustedIPs are crucial so CrowdSec can read the real client IP from the proxy headers instead of always seeing the internal Docker IP.
π CrowdSec Console & Community Blocklists
One of CrowdSec's biggest advantages is the community. When you register your CrowdSec instance with the CrowdSec Console, two cool things happen:
- You share detected attacks (anonymized) with the community
- You receive community blocklists β IP addresses that other CrowdSec users worldwide have identified as malicious
# Enroll with the console
docker exec crowdsec cscli console enroll YOUR_ENROLLMENT_KEY
# Confirm enrollment at https://app.crowdsec.net
# Then restart CrowdSec
docker compose restart crowdsec
In the console, you'll see a dashboard with:
- Active decisions (blocked IPs)
- Detected scenarios
- Your installed collections and parsers
- Community blocklist status
The free tier already gives you a solid community blocklist. There are premium options for more comprehensive lists, but for a homelab, free is more than enough.
π§ͺ Testing: Does everything work?
Now for the fun part β let's make sure everything is working!
1. Check the status
# CrowdSec status
docker exec crowdsec cscli metrics
# Show installed collections
docker exec crowdsec cscli collections list
# Active decisions (blocked IPs)
docker exec crowdsec cscli decisions list
# Bouncer status
docker exec crowdsec cscli bouncers list
2. Manually ban an IP
# Ban a test IP (use one that doesn't belong to you!)
docker exec crowdsec cscli decisions add --ip 1.2.3.4 --reason "test ban" --duration 5m
# Check if it's blocked
docker exec crowdsec cscli decisions list
# Unban it
docker exec crowdsec cscli decisions delete --ip 1.2.3.4
3. Run a scanner
If you really want to see CrowdSec detect attacks, run a scanner from another device:
# From a DIFFERENT device on your network:
# WARNING: Only against your own infrastructure!
nikto -h https://your-domain.com
# Or just fire lots of rapid requests:
for i in $(seq 1 50); do curl -s -o /dev/null https://your-domain.com/wp-login.php; done
After a few seconds, you should see in the CrowdSec logs that the IP was detected and blocked:
# Watch CrowdSec logs
docker logs -f crowdsec
# Check for new decisions
docker exec crowdsec cscli decisions list
π― Real-World Scenarios: What CrowdSec Blocks
After running CrowdSec for several weeks, here are some things it has detected and blocked in my homelab:
- HTTP Brute Force: Bots attacking login pages with credential stuffing
- Path Traversal Attempts: Requests like
/../../etc/passwd - CVE Exploits: Scanners probing for known vulnerabilities like Log4Shell or Spring4Shell
- WordPress Scanners: Bots looking for
/wp-admin,/xmlrpc.php(even if you don't run WordPress!) - SSH Brute Force: Classic password attacks (if you configure CrowdSec for SSH too)
- Aggressive Crawlers: Bots hammering your site with hundreds of requests per second
The community blocklists also ensure that known attacker IPs are blocked before they even knock on your door. That's the real game changer.
β οΈ Troubleshooting & Tips
CrowdSec only sees internal Docker IPs
This is the most common issue. If CrowdSec sees 172.18.0.x instead of the real client IP, you need to:
- Make sure Traefik sets the
X-Forwarded-Forheader - Configure
forwardedHeadersTrustedIPscorrectly in the bouncer plugin - Optionally: configure Traefik's
proxyProtocolif you have an upstream proxy
# In traefik.yml - entryPoints configuration:
entryPoints:
websecure:
address: ":443"
forwardedHeaders:
trustedIPs:
- "10.0.0.0/8"
- "172.16.0.0/12"
- "192.168.0.0/16"
CrowdSec can't find the logs
Check if the volumes are mounted correctly:
# Are the logs visible inside the container?
docker exec crowdsec ls -la /var/log/traefik/
# Check parser status
docker exec crowdsec cscli parsers list
# Check acquisition config
docker exec crowdsec cat /etc/crowdsec/acquis.yaml
Bouncer can't connect to CrowdSec
Make sure that:
- Both containers are in the same Docker network
- The API key is correct
- CrowdSec starts before Traefik (hence
depends_onin the compose file)
π Bonus: Useful CrowdSec Collections
Beyond the standard collections, there are some particularly useful ones for a homelab:
# Install additional collections
docker exec crowdsec cscli collections install crowdsecurity/whitelist-good-actors
docker exec crowdsec cscli collections install crowdsecurity/appsec-virtual-patching
docker exec crowdsec cscli collections install crowdsecurity/appsec-generic-rules
# List all installed collections
docker exec crowdsec cscli collections list
whitelist-good-actors is particularly important β it prevents search engine bots like Googlebot or Bingbot from being accidentally blocked.

π‘ Conclusion
CrowdSec is an absolute game changer for any homelab. The combination of local log analysis and community-driven threat intelligence makes it a powerful tool that goes far beyond what Fail2ban can offer.
Here's a quick recap of the key points:
- β Easy setup with Docker Compose
- β Traefik plugin for seamless integration as middleware
- β Community blocklists for proactive protection
- β Free and open source
- β Much more modern than Fail2ban
- β Web console for an overview of what's happening
If you're already running Traefik as your reverse proxy, there's really no reason not to use CrowdSec. In less than 30 minutes, you'll have a solid security layer actively defending your homelab against attacks.
Got questions or running into issues? Drop me a comment below! π¬