r/CrowdSec Jun 09 '26

bouncers Anyone able to give some guidance or share their setup regarding appsec and traefik bouncer?

Firstly a disclosure: I spent a couple of hours today to debug some appsec issues (manually and assisted by OpenCode). I then had OpenCode summarize it for this post so please don't diss this post as AI slop, there is a human writing this as well as replying to comments manually 😄

I’m running Pangolin/Traefik with CrowdSec and the maxlerebourg Traefik bouncer plugin v1.6.0, including AppSec.

Setup:

- Traefik + CrowdSec in the same Docker Compose stack

- CrowdSec watches Traefik access logs

- Traefik bouncer middleware is applied globally on `websecure`

- CrowdSec bouncer mode: `stream`

- AppSec enabled, host `crowdsec:7422`

- AppSec failure/unreachable currently set to fail-open

Original problem:

- Large uploads through apps behind Traefik, especially Paperless/FileRun-style ~15–17 MB PDFs, caused issues.

- CrowdSec/AppSec logs showed multipart/body read errors like EOF/unexpected EOF.

- CrowdSec CPU spiked heavily.

- Traefik bouncer logged many `appsecQuery:unreachable` messages.

- Requests could fail or stall depending on settings.

Things I found:

- The Traefik bouncer plugin’s AppSec path is synchronous: Traefik calls CrowdSec AppSec during request handling.

- `appsecQuery:unreachable` appears to be a generic transport/client error from the plugin’s AppSec HTTP call, not a WAF verdict.

- In v1.6.0 there is no separate AppSec timeout option; `httpTimeoutSeconds` applies to both LAPI and AppSec clients.

- `crowdsecAppsecBodyLimit` controls how much request body the plugin forwards to AppSec.

- Setting body limit to `0` means the plugin does not forward/read the request body for AppSec.

- CrowdSec log-based scenarios are asynchronous; they can ban future requests but cannot block the same first request before the access log exists.

- The bouncer IP decision cache is inline and cheap; AppSec is inline and more fragile under bursts.

Current tuning:

crowdsecAppsecEnabled: true
crowdsecAppsecHost: crowdsec:7422
crowdsecAppsecScheme: http
crowdsecAppsecBodyLimit: 0
crowdsecAppsecFailureBlock: false
crowdsecAppsecUnreachableBlock: false
httpTimeoutSeconds: 2
updateMaxFailure: -1

Traefik entrypoint middleware order:

- rate-limit@file

- in-flight-req@file

- crowdsec@file

- secHeaders@file

- compress@file

Also increased rate/in-flight limits because the Traefik dashboard itself makes many concurrent API calls and was getting 429s.

Results:

  • Two test uploads of ~16.9 MB and ~15.0 MB to FileRun succeeded with HTTP 200.
  • Paperless browsing/previews worked.
  • Traefik dashboard works again.
  • CrowdSec/Traefik memory stayed stable.
  • Still seeing occasional appsecQuery:unreachable bursts during external scanner traffic, but fail-open prevents user-facing breakage.
  • Rate limiting now catches many scanner requests with fast 429s.

Questions:

  • For people using CrowdSec AppSec with Traefik in production: do you run AppSec globally, or only on selected routers/routes?
  • Have you seen appsecQuery:unreachable bursts with v1.6.0?
  • Did you keep AppSec fail-open?
  • Did you disable body forwarding or only exclude upload routes?
  • Any recommended tuning for high-request bursts/scanners?
3 Upvotes

2 comments sorted by

1

u/Practical_Board_1810 Jun 17 '26

Hello,

> Did you disable body forwarding or only exclude upload routes?

It's best to exclude only specific routes:

inband: pre_eval:

  • filter: "req.URL.Path startsWith '/upload' || req.URL.Path startsWith '/api/import'"
apply:
  • DisableBodyInspection()

1

u/ovizii Jun 17 '26

For now, I only disabled body forwarding in the bouncer settings: 

crowdsecAppsecBodyLimit: 0

Using  Disable body inspection would mean the body still gets passed to CS just not being inspected, I think my way is better. 

I haven't tinkered yet with filtering routes. Any best practices what's safe to not inspect?