A well-configured load balancer receives traffic and redistributes it to backends. However, it doesn't distinguish between a real visitor and a bot scanning your URLs for vulnerabilities.
As soon as a web frontend is exposed to the Internet, it is under constant attack, starting from the very first hour: port scans, brute-force attacks on login forms, SQL injections, cross-site scripting, and exploitation of newly published CVEs, most often by automated bots.
HAProxy does its job as a load balancer very well: it routes, balances, and handles SSL termination. But it has no way of knowing what is legitimate or malicious in a request. You could write a few filtering ACLs by hand, but no one is going to maintain lists of malicious IPs or a rule for every new attack technique. It lacks a layer of protection.
That is the role of CrowdSec: an open-source behavioral detection engine that analyzes traffic, identifies malicious behavior, and applies remediation (blocking, challenge pages, captchas). Its unique feature is that it is community-driven. When an IP is banned for aggressive behavior by thousands of users, it feeds into a shared reputation list.
In front of HAProxy, everything goes through the SPOE (Stream Processing Offload Engine) protocol: HAProxy offloads the analysis of each request to CrowdSec. For every connection, it transmits the source IP, method, path, headers, and request body, and CrowdSec responds in near real-time—allow or block—with tight latency to ensure legitimate visitors aren't penalized.
Key strength: the HAProxy SPOA bouncer is the only one to include AppSec, meaning a true WAF (Web Application Firewall). CrowdSec doesn't just ban IPs; it inspects application content to block injections and performs virtual patching, neutralizing the exploitation of known vulnerabilities before you have even patched the application itself. You can also add the OWASP Core Rule Set, the industry-standard rule set.
The concrete result: scans and known hostile IPs are filtered out upstream, web exploitation attempts are blocked at the application level, and legitimate traffic reaches your applications as normal.
The logic is simple. You first made your frontend available—that was the subject of our article on HAProxy high availability. The next step is to make it secure. A highly available but unprotected frontend is like a reinforced door left wide open.
The benefit of CrowdSec is that it provides enterprise-grade protection (behavioral IPS, WAF, global reputation) without expensive licenses or dedicated appliances. It runs on the same machine hosting HAProxy, updates itself automatically via its hub, and is part of a continuous security approach rather than a one-off audit.
For a production deployment, we placed CrowdSec in front of an existing HAProxy cluster. Installing the engine and updating the hub is quick:
apt install crowdsec -y
curl -s https://install.crowdsec.net | sh
cscli hub update && cscli hub upgrade
systemctl restart crowdsec
Next, install the HAProxy collection, a package that includes tailored detection scenarios:
cscli collections install crowdsecurity/haproxy
Then, declare the SPOE agent on the HAProxy side (file /etc/haproxy/crowdsec.cfg), which defines the messages sent to CrowdSec and points to the crowdsec-spoa backend. This backend is declared in HAProxy as follows:
backend crowdsec-spoa
mode tcp
server crowdsec-spoa 127.0.0.1:9000 check
Now, enable the bouncer, the component that enforces the decision—whether to allow or block the traffic:
systemctl enable --now crowdsec-spoa-bouncer
Verify that crowdsec-spoa and crowdsec are listening on their respective ports:
ss -lntp | grep -E '9000|7422'
The final and most interesting step: enable the WAF (AppSec). Install the AppSec collections, then configure the engine (it listens locally on 127.0.0.1:7422):
cscli collections install crowdsecurity/appsec-generic-rules
cscli collections install crowdsecurity/appsec-virtual-patching
Next, edit the file /etc/crowdsec/acquis.d/appsec.yaml :
appsec_configs:
- crowdsecurity/appsec-generic-rules
- crowdsecurity/appsec-virtual-patching
labels:
type: appsec
listen_addr: 127.0.0.1:7422
After installing each collection, reload the service:
systemctl reload crowdsec
Monitor WAF activity in real time:
cscli metrics show appsec
View the details of active rules from the applied collections:
cscli appsec-rules list | grep enabled
Logs (detections, blocking decisions, WAF alerts) are available here:
/var/log/crowdsec-spoa/crowdsec-spoa-bouncer.log
We forward these to Graylog for a centralized view and to trigger alerts as soon as a detection occurs.
Enable AppSec and IP banning in stages. Many stop at IP reputation, but that is only one part of CrowdSec: the application WAF and virtual patching are what truly protect against CVE exploitation the day a vulnerability is released.
Proceed gradually: use your staging environment as soon as possible and only enable CrowdSec on specific backends using an ACL like this:
http-request send-spoe-group crowdsec crowdsec-http-no-body if ACL_votresite
http-request deny status 403 if ACL_votresite { var(txn.crowdsec.remediation) -m str ban }
use_backend back_votresite if ACL_votresite
Watch out for false positives at startup: an overly strict WAF can block legitimate requests. Start in observation mode, then gradually tighten security by adjusting active rules rather than blocking everything right away. Finally, centralize your logs from day one: a block you cannot see is a block you cannot understand or fix.
Making a frontend available is the first half of the job. Making it capable of refusing malicious requests is the second. CrowdSec adds this intelligence in front of HAProxy, for free, backed by the power of a global network.