CrowdSec isn't detecting attacks
Detection works as a pipeline: CrowdSec reads log lines, parses them, feeds them to scenarios, and turns overflows into alerts unless a whitelist discards them. Start with the detection checks of the Stack Health-Check: they trigger test scenarios and check that your logs are read and parsed. Then find the first stage that doesn't work:
| Symptom | Go to |
|---|---|
| No logs read at all | No logs read |
| Logs read but none parsed | No logs parsed |
| Logs parsed but no alerts | Security Engine no alerts |
| A collection is installed but its logs aren't read | Mismatching collections |
| The WAF (AppSec) doesn't block a request | AppSec troubleshooting |
How do I know if my setup is working correctly? Are some unparsed logs normal?
Yes, some unparsed lines are normal. Parsers only parse the lines that scenarios use, and ignore the rest.
cscli metrics shows, for each log source, how many lines were read, parsed and unparsed. See what the metrics mean. For an end-to-end test, run the Stack Health-Check.
Why are some logs not parsed in cscli metrics?
Use cscli explain on a line that should be parsed. It shows which parser accepted or rejected it at each stage, and which scenarios received it:
# cscli explain --log "May 16 07:50:30 sd-126005 sshd[10041]: Invalid user git from 78.142.18.204 port 47738" --type syslog
line: May 16 07:50:30 sd-126005 sshd[10041]: Invalid user git from 78.142.18.204 port 47738
├ s00-raw
| └ 🟢 crowdsecurity/syslog-logs (first_parser)
├ s01-parse
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/mysql-logs
| ├ 🔴 crowdsecurity/nginx-logs
| └ 🟢 crowdsecurity/sshd-logs (+6 ~1)
├ s02-enrich
| ├ 🟢 crowdsecurity/dateparse-enrich (+2 ~1)
| ├ 🟢 crowdsecurity/geoip-enrich (+13)
| ├ 🔴 crowdsecurity/http-logs
| └ 🟢 crowdsecurity/whitelists (unchanged)
├-------- parser success 🟢
├ Scenarios
├ 🟢 crowdsecurity/ssh-bf
├ 🟢 crowdsecurity/ssh-bf_user-enum
├ 🟢 crowdsecurity/ssh-slow-bf
└ 🟢 crowdsecurity/ssh-slow-bf_user-enum
If every s01-parse parser is red, the line's format doesn't match what the collection expects, or the type label in your acquisition is wrong.
Do not run cscli explain on big log files: it buffers a lot of information in memory. To test CrowdSec on big log files, use replay mode.
I installed a collection: how do I add its log files and check that it works?
Installing a collection only installs parsers and scenarios. CrowdSec also needs to read the service's logs:
- Install the collection, for example
sudo cscli collections install crowdsecurity/nginx. - Add an acquisition for the service's log files, with the
typelabel the collection's hub page gives. See Adding a new acquisition. - Restart CrowdSec.
- Check
cscli metrics: the new log source should appear with lines read and parsed.
My service is behind a CDN and I get no alerts
If a CDN or reverse proxy terminates the connection in front of your service, your web server logs the CDN's address instead of the visitor's. Every event is then attributed to a few CDN addresses:
- Cloudflare: the
crowdsecurity/cdn-whitelistpostoverflow discards alerts from Cloudflare's ranges. It is part of thecrowdsecurity/whitelist-good-actorscollection, which the operating system collections (crowdsecurity/linux,crowdsecurity/windows,crowdsecurity/freebsd…) install. You see the requests in your access logs,cscli metricsshows them parsed, but nothing reachescscli alerts list. - Other CDNs: nothing discards the alerts, so they target the CDN's own addresses. Blocking them would cut off every legitimate visitor coming through that edge server, and never the attacker.
The whitelist is deliberate: without it, one misbehaving visitor would get Cloudflare banned, along with all your legitimate traffic. In both cases the fix is to log the real client IP, not to remove the whitelist.
To confirm this is your issue:
- Check the client address field of your access log. If the same few addresses appear on every line, the visitor IP is not reaching you.
- Run the HTTP detection check from a device with a public IP, and see whether the alert shows your IP or the CDN's.
- Run
cscli explainon an access log line that triggers a scenario on its own, such as a path traversal attempt. When a postoverflow whitelist discards the alert, the output ends withparser success, ignored by whitelist (CDN provider).cscli explainshows postoverflows since CrowdSec 1.6.0. - Search the CrowdSec log for discarded alerts:
sudo grep whitelisted /var/log/crowdsec.log. Each line names the IP and the reason.
To fix it, have your CDN forward the visitor address in a header. Then configure your web server to put it in the client address field before logging: use nginx's ngx_http_realip_module, Apache's mod_remoteip, or your proxy's trusted-proxy setting. CrowdSec parsers read the client address field (remote_addr, %h), never the header itself.
| Provider | Header | Documentation |
|---|---|---|
| Cloudflare | CF-Connecting-IP | Restoring original visitor IPs |
| Fastly | Fastly-Client-IP | Fastly-Client-IP |
| Akamai | True-Client-IP | Origin Server behavior |
| Amazon CloudFront | CloudFront-Viewer-Address | Add CloudFront request headers |
| Other CDNs and reverse proxies | usually X-Forwarded-For or X-Real-IP | refer to your provider's documentation |
Only trust proxies you actually control, and keep the trusted ranges up to date from your provider's published list (Cloudflare, Fastly, AWS CloudFront). If you trust arbitrary sources, a client can spoof its own address through the header, either to evade detection or to get an innocent IP banned.
If the Local API itself is behind a proxy, also set use_forwarded_for_headers and trusted_proxies in config.yaml. See Local API behind a reverse proxy.
Is scenario X working on my logs?
- Replay mode processes existing log files and shows which scenarios trigger.
cscli explainshows how one or a few log lines go through parsers and scenarios.
My scenario triggers with fewer log lines than its capacity
The same log file is probably read more than once, for example because it appears both in acquis.yaml and in a file under acquis.d/. CrowdSec then processes each line once per acquisition, and buckets fill up faster.
To confirm it, look for the file twice in the CrowdSec log at startup (sudo grep "Starting tail" /var/log/crowdsec.log), or compare cscli metrics show acquisition with the real line count: "Lines read" is a multiple of it. Then remove the duplicate entries and restart CrowdSec.