RousselTMLEARNING

Article · CrowdSec: From Discovery to Expertise

Nginx, Apache and HAProxy bouncers

1. Nginx and OpenResty #

A Lua bouncer.

Install #

The Nginx bouncer relies on the Lua module. On Ubuntu 22.xx, this module may be missing: move to a newer version or use OpenResty, which includes it.

sudo apt install nginx lua5.1 libnginx-mod-http-lua luarocks gettext-base lua-cjson
sudo apt install crowdsec-nginx-bouncer
sudo nginx -t && sudo systemctl reload nginx

Configure #

The /etc/crowdsec/bouncers/crowdsec-nginx-bouncer.conf file can be overridden with a .conf.local file.

API_URL=http://127.0.0.1:8080
API_KEY=YOUR_KEY
MODE=stream
UPDATE_FREQUENCY=10
BOUNCING_ON_TYPE=all
FALLBACK_REMEDIATION=ban
RET_CODE=403
APPSEC_URL=http://127.0.0.1:7422
OptionRole
MODElive by default, or stream
BOUNCING_ON_TYPEall, ban, captcha
FALLBACK_REMEDIATIONRemediation if the received type is unknown
BAN_TEMPLATE_PATHHTML page shown to banned IPs
REDIRECT_LOCATIONRedirects instead of showing the page
APPSEC_URLEnables the WAF

Captcha #

Captcha gives a legitimate user a chance, for example behind a shared IP. Three providers: recaptcha, hcaptcha, turnstile. Nginx must be able to reach them: configure resolver and lua_ssl_trusted_certificate.

CAPTCHA_PROVIDER=turnstile
SITE_KEY=YOUR_SITE_KEY
SECRET_KEY=YOUR_SECRET_KEY
CAPTCHA_EXPIRATION=3600
sudo cscli decisions add --ip 192.0.2.6 --duration 1h --type captcha

Apache #

An Apache bouncer also exists, with WAF, virtual patching and bot detection through AppSec. Its logic is identical: API key, LAPI URL, then server reload. See the dedicated documentation.

2. HAProxy with SPOA #

Offloading the check outside HAProxy.

The principle #

HAProxy talks to the SPOA bouncer with the SPOE protocol; the bouncer relies on the Local API and AppSec

Old bouncer deprecated. The old Lua HAProxy bouncer, still cited by many tutorials, is deprecated. Use the SPOA bouncer, the only one supporting AppSec.

Install and configure #

sudo apt install crowdsec-haproxy-spoa-bouncer
sudo cscli bouncers add haproxy-spoa
sudo cp /usr/share/doc/crowdsec-haproxy-spoa-bouncer/examples/crowdsec.cfg /etc/haproxy/crowdsec.cfg

In /etc/crowdsec/bouncers/crowdsec-spoa-bouncer.yaml, set api_url, api_key and listen_tcp: 127.0.0.1:9000. Then, in haproxy.cfg:

frontend http-in
    bind *:80
    option http-buffer-request
    unique-id-format %[uuid()]
    unique-id-header X-Unique-ID
    filter spoe engine crowdsec config /etc/haproxy/crowdsec.cfg

    acl body_within_limit req.body_size -m int le 51200
    http-request send-spoe-group crowdsec crowdsec-http-body if body_within_limit || !{ req.body_size -m found }
    http-request send-spoe-group crowdsec crowdsec-http-no-body if !body_within_limit { req.body_size -m found }

    # Ban and captcha pages are in examples/haproxy.cfg
    default_backend app

backend crowdsec-spoa
    mode tcp
    timeout connect 2s
    timeout server 60s
    server spoa 127.0.0.1:9000
sudo crowdsec-spoa-bouncer -c /etc/crowdsec/bouncers/crowdsec-spoa-bouncer.yaml -t
sudo haproxy -c -f /etc/haproxy/haproxy.cfg
sudo systemctl restart crowdsec-spoa-bouncer haproxy

Two traps #

  • Real IP. Behind a CDN, use set-src before the send-spoe-group lines, and only allow the trusted proxy on your ports.
  • 50 KB limit. A request body beyond this size is not inspected by the WAF. An attacker can use this to bypass it: reject these requests, except on your upload paths.

Sources #

Configurations from the official documentation consulted in November 2026: these bouncers were not run for this article.

📄 CrowdSec bouncers for Nginx, Apache and HAProxy →

My progress

  • ⏱ Estimated time : ≈ 7 min

Sign in to track your progress and take notes. Sign in

💬 Ask a question

Recommended Articles

CrowdSec bouncers: principles and firewall bouncer

Understanding CrowdSec bouncers: where to block, live and stream modes, API keys, decisions API, ...

CrowdSec bouncers: Cloudflare, network devices, Kubernetes and custom bouncer

Block at the CDN with Cloudflare Workers, feed pfSense or MikroTik with Blocklist Mirror, protect...

Decisions, profiles, allowlists and AppSec in CrowdSec

Manage decisions with cscli, adapt block duration and type with profiles, avoid false positives w...

Protecting Traefik with CrowdSec: the bouncer plugin

Setting up the CrowdSec bouncer in Traefik: plugin, middleware, stream and live modes, real IP be...

CrowdSec: understanding the collaborative firewall

What CrowdSec is, how it detects and blocks attacks: Security Engine, parsers, scenarios, Local A...

CrowdSec observability: banned IPs, blocked attacks, Prometheus and Grafana

Monitoring CrowdSec: cscli metrics, banned IPs, detected attacks, volume blocked by bouncers, Pro...

Gestion des certificats SSL/TLS avec Let's Encrypt et ACME

Apprenez à automatiser la génération et le renouvellement de vos certificats SSL/TLS avec Let's E...

Protocole ACME : serveur ACME, challenges http-01 et dns-01, automatisation TLS

Comprendre le protocole ACME : rôle du serveur ACME (Let's Encrypt, ZeroSSL, step-ca), challenges...

HAProxy dans Kubernetes : L'Ingress Controller Haute Performance

Découvrez en profondeur l'intégration de HAProxy dans Kubernetes. Architecture Direct-to-Pod, opt...

Support us

♥ SUPPORT US

Support RousselTM Learning

Courses, articles, labs and certificates stay free with no intrusive ads. A voluntary contribution, of any amount you choose, pays for hosting, lab environments and new content.

Contribute with PayPal Any amount · card or PayPal accountLearn more
QR code PayPal
Or scan this QR code with your phone

Thank you, every contribution counts!