π Documentation π Hub π¬ Discourse
A Remediation Component for haproxy.
What it does ?β
The cs-haproxy-spoa-bouncer
allows CrowdSec to enforce blocking, CAPTCHA, or
allow actions directly within HAProxy using the SPOE
protocol.
This remediation component is meant to obsolete the old lua-based haproxy bouncer.
It supports IP-based decisions, CAPTCHA challenges, GeoIP-based headers, and integrates cleanly with CrowdSecβs LAPI using the stream bouncer protocol.
Supported features:
- Stream mode (pull the local API for new/old decisions every X seconds)
- Ban remediation (can ban an IP address by redirecting or returning a custom HTML page)
- Captcha remediation (can return a captcha)
- Works with IPv4/IPv6
- Support IP ranges (can apply a remediation on an IP range)
- We are working on supporting AppSec
Installationβ
We strongly encourage the use of our packages.
Using packagesβ
You will have to setup crowdsec repositories first setup crowdsec repositories.
- Debian/Ubuntu
- RHEL/Centos/Fedora
sudo apt install crowdsec-haproxy-spoa-bouncer
sudo dnf install crowdsec-haproxy-spoa-bouncer
Bouncer configurationβ
If you are using packages, and have a lapi on the same server the following
configuration file /etc/crowdsec/bouncer/crowdsec-spoa-bouncer.yaml
should
already be in a working state, and can skip this section and begin with HAProxy
Configuration.
You can always edit the configuration file at /etc/crowdsec/bouncer/crowdsec-spoa-bouncer.yaml
:
/etc/crowdsec/bouncer/crowdsec-spoa-bouncer.yaml
log_mode: file
log_dir: /var/log/
log_level: info
log_compression: true
log_max_size: 100
log_max_backups: 3
log_max_age: 30
update_frequency: 10s
api_url: http://127.0.0.1:8080/
api_key: ${API_KEY}
insecure_skip_verify: false
workers:
- name: spoa1
listen_addr: 0.0.0.0:9000
listen_socket: /run/crowdsec-spoa/spoa-1.sock
worker_user: crowdsec-spoa
worker_group: crowdsec-spoa
asn_database_path: /var/lib/crowdsec/data/GeoLite2-ASN.mmdb
city_database_path: /var/lib/crowdsec/data/GeoLite2-City.mmdb
admin_socket: /run/crowdsec-spoa-admin.sock
prometheus:
enabled: true
listen_addr: 127.0.0.1
listen_port: 60601
You can get a workable configuration by using the yaml above and getting and api key by:
sudo cscli bouncers add mybouncer
API key for 'bouncertest':
JdVa7DKBM35gPDAR014pH/55l38fxLGt02NPPnZgLQI
Please keep this key since you will not be able to retrieve it!
You can check that the bouncer is correctly installed with cscli:
β― sudo cscli bouncers list
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Name IP Address Valid Last API pull Type
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
cs-spoa-bouncer-1752052534 127.0.0.1 βοΈ crowdsec-spoa-bouncer
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β― sudo cscli bouncers inspect cs-spoa-bouncer-1752052534
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Bouncer: cs-spoa-bouncer-1752052534
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Created At 2025-07-09 09:15:34.685444393 +0000 UTC
Last Update 2025-07-09 12:42:18.92023029 +0000 UTC
Revoked? false
IP Address 127.0.0.1
Type crowdsec-spoa-bouncer
Version v0.0.3-beta29-rpm-pragmatic-arm64-db7065289a0f5ce1c92f34807c9a98b23c07dc90
Last Pull
Auth type api-key
OS ?
Auto Created false
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
HAProxy Configurationβ
HAProxy requires two configuration files for integration with the bouncer. The
primary file is /etc/haproxy/haproxy.cfg, which must be modified to enable
communication with the SPOE engineβour documentation will guide you through
this. The second file is /etc/haproxy/crowdsec.cfg, which contains the SPOE
agent configuration. This file is automatically installed along with the bouncer
package on the condition that /etc/haproxy
exists.
If you are using packages, you will find the haproxy configuration
snippets in /usr/share/doc/crowdsec-haproxy-spoa-bouncer/examples
.
SPOE Filterβ
Add a SPOE agent configuration to /etc/haproxy/crowdsec.cfg:
/etc/haproxy/crowdsec.cfg
[crowdsec]
spoe-agent crowdsec-agent
messages crowdsec-ip crowdsec-http
option var-prefix crowdsec
option set-on-error error
timeout hello 100ms
timeout idle 30s
timeout processing 500ms
use-backend crowdsec-spoa
log global
## This message is used to customise the remediation from crowdsec-ip based on the host header
spoe-message crowdsec-http
args remediation=var(txn.crowdsec.remediation) crowdsec_captcha_cookie=req.cook(crowdsec_captcha_cookie) id=unique-id host=hdr(Host) method=method path=path query=query version=req.ver headers=req.hdrs body=req.body url=url ssl=ssl_fc
event on-frontend-http-request
## This message should be the first to trigger in the chain
spoe-message crowdsec-ip
args id=unique-id src-ip=src src-port=src_port
event on-client-session
If you installed the haproxy spoe bouncer through package, you will find this
configuration file in /usr/share/docs/crowdsec-haproxy-spoa-bouncer/examples
This crowdsec spoe agent configuration is then referenced in the main haproxy
configuration file /etc/haproxy/haproxy.cfg
and may be added at the bottom of
the haproxy configuration file.
/etc/haproxy/haproxy.cfg
[...]
frontend http-in
bind *:80
filter spoe engine crowdsec config /etc/haproxy/crowdsec.cfg
http-request set-header X-CrowdSec-Remediation %[var(txn.crowdsec.remediation)]
http-request lua.crowdsec_handle if { var(txn.crowdsec.remediation) -m found }
use_backend <whatever>
backend crowdsec-spoa
mode tcp
server s1 127.0.0.1:9000
In the global
section of your haproxy.cfg
, lua path configuration is also mandatory:
global
[...]
lua-load /usr/lib/crowdsec-haproxy-spoa-bouncer/lua/crowdsec.lua
An example that includes this snippet can also be found in
/usr/share/docs/crowdsec-haproxy-spoa-bouncer/examples/haproxy.cfg
.
Specific featuresβ
To enable CAPTCHA for a domain:β
hosts:
- host: "example.com"
captcha:
site_key: "<your-site-key>"
secret_key: "<your-secret-key>"
provider: "hcaptcha"
The following captcha providers are supported:
hcaptcha
recaptcha
turnstile
Prometheus Metricsβ
Enable and expose metrics:
prometheus:
enabled: true
listen_addr: 127.0.0.1
listen_port: 60601
Access them at http://127.0.0.1:60601/metrics.
Admin Socketβ
You can query the bouncer runtime state using the admin socket:
socat - UNIX-CONNECT:/run/crowdsec-spoa-admin.sock
Commands:
get hosts
get host <host> session <uuid> <key>
set host <host> session <uuid> <key> <value>
get ip <ip>
val host <host> cookie <cookie>
val host <host> captcha <response>
Manual installation and advanced configurationβ
We strongly encourage the use of our packages.
Compile the Binaryβ
This requires a whole working golang installation.
git clone https://github.com/crowdsecurity/crowdsec-spoa-bouncer.git
cd crowdsec-spoa-bouncer
make build
Configure the Bouncerβ
sudo mkdir -p /etc/crowdsec/bouncers/
sudo cp config/crowdsec-spoa-bouncer.yaml /etc/crowdsec/bouncers/
Edit /etc/crowdsec/bouncers/crowdsec-spoa-bouncer.yaml
:
-
Set your LAPI URL to point to your CrowdSec LAPI instance:
api_url: http://127.0.0.1:8080/
-
Generate an API key on the server where CrowdSec is intalled:
cscli bouncers add haproxy-spoa
-
Paste the key into:
api_key: your-generated-key
Create runtime socket directory and crowdsec-spoa user:
sudo
sudo mkdir -p /run/crowdsec-spoa
sudo chown crowdsec-spoa:crowdsec-spoa /run/crowdsec-spoa
Configure HAProxyβ
Lua Integration & Environment Variablesβ
In the global
section of your haproxy.cfg
, configure Lua paths and template environment:
global
lua-prepend-path /usr/lib/crowdsec-haproxy-spoa-bouncer/lua/?.lua
lua-load /usr/lib/crowdsec-haproxy-spoa-bouncer/lua/crowdsec.lua
setenv CROWDSEC_BAN_TEMPLATE_PATH /var/lib/crowdsec/lua/haproxy/templates/ban.html
setenv CROWDSEC_CAPTCHA_TEMPLATE_PATH /var/lib/crowdsec/lua/haproxy/templates/captcha.html
These variables are used by the Lua module to render proper HTML responses for banned or captcha-validated users.
Add SPOE Filter in frontend
β
frontend test
mode http
bind *:9090
filter spoe engine crowdsec config /etc/haproxy/crowdsec.cfg
http-request set-header X-CrowdSec-Remediation %[var(txn.crowdsec.remediation)] if { var(txn.crowdsec.remediation) -m found }
http-request set-header X-CrowdSec-IsoCode %[var(txn.crowdsec.isocode)] if { var(txn.crowdsec.isocode) -m found }
http-request lua.crowdsec_handle if { var(txn.crowdsec.remediation) -m found }
use_backend test_backend
Create SPOE Configβ
Create /etc/haproxy/crowdsec.cfg
:
/etc/haproxy/crowdsec.cfg
spoe-agent crowdsec-agent
messages crowdsec-ip crowdsec-http
option var-prefix crowdsec
option set-on-error error
timeout hello 100ms
timeout idle 30s
timeout processing 500ms
use-backend crowdsec-spoa
spoe-message crowdsec-ip
args id=unique-id src-ip=src src-port=src_port
event on-client-session
spoe-message crowdsec-http
args remediation=var(txn.crowdsec.remediation) crowdsec_captcha_cookie=req.cook(crowdsec_captcha_cookie) id=unique-id host=hdr(Host) method=method path=path query=query version=req.ver headers=req.hdrs body=re
q.body url=url ssl=ssl_fc
event on-frontend-http-request
Add SPOE Backendβ
backend crowdsec-spoa
mode tcp
balance roundrobin
server s1 127.0.0.1:9000
Modify HAProxy systemd Unit (Optional)β
Edit /etc/systemd/system/haproxy.service
and add:
[Service]
Environment=CROWDSEC_BAN_TEMPLATE_PATH=/var/lib/crowdsec/lua/haproxy/templates/ban.html
Environment=CROWDSEC_CAPTCHA_TEMPLATE_PATH=/var/lib/crowdsec/lua/haproxy/templates/captcha.html
Then reload systemd:
sudo systemctl daemon-reexec
sudo systemctl daemon-reload
Start the Bouncerβ
Run Directly
sudo ./crowdsec-spoa-bouncer -c /etc/crowdsec/bouncers/crowdsec-spoa-bouncer.yaml
Or Run as a Systemd Service
sudo cp config/crowdsec-spoa-bouncer.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now crowdsec-spoa-bouncer