Releases: crowdsecurity/cs-haproxy-spoa-bouncer
v0.2.0
Breaking Changes
As outlined in the 0.1.0 release, every minor version before 1.0.0 may contain breaking changes.
Please review the sections below carefully before upgrading to avoid service interruptions.
TL;DR (Key Changes)
- Parent/worker model removed – the SPOA now runs as a single process.
workers,worker_user,worker_groupoptions removed – replaced bylisten_tcp/listen_unix.admin_socketremoved – the setting is now ignored and can be deleted.- Service now runs fully as
crowdsec-spoauser – config/log file permissions must allow this. - Docker image now runs as
crowdsec-spoa. - Default log directory moved to
/var/log/crowdsec-spoa/(config change required).
Inner Architecture
In short:
We removed the parent/worker architecture and now run a simpler, single-process model.
Background
Previously:
-
Multiple workers handled incoming SPOE messages from HAProxy.
-
Each worker communicated with a parent process over a Unix socket to fetch:
- State
- Decisions
- Host configuration (e.g. ban / captcha)
This design existed to support multiple SPOA listeners from a single process.
In practice, we found that users almost never configured more than one SPOA listener.
The added complexity:
- Slowed down feature development,
- Increased code debt,
- Made onboarding new contributors harder.
As a result, we have simplified the architecture to a single process that directly handles SPOE messages.
Configuration Changes
We have removed the following YAML options:
workersworker_userworker_group
These are replaced with:
listen_tcp: 127.0.0.1:9090
listen_unix: /path/to/unix.sockRecommendation:
Add these keys to your configuration before upgrading to avoid startup failures.
Admin Socket
Because we no longer support multiple SPOA listeners, the admin socket no longer provides value.
- The following option has been removed and is now ignored:
admin_socket: /path/to/admin.sockYou can safely remove this key from your configuration.
We know users still need a way to reload the SPOA without dropping in-flight messages from HAProxy.
In a future release, we plan to add a proper systemctl reload hook to handle this cleanly.
Process Owner (systemd Unit)
With the removal of the parent/worker model and the admin socket, the systemd unit now runs entirely as the crowdsec-spoa user.
This improves separation between service accounts and root, but it also means:
- All files needed by the SPOA must be readable by the
crowdsec-spoagroup.
For example:
chown root:crowdsec-spoa /etc/crowdsec/bouncers/crowdsec-spoa-bouncer.yaml
chmod 640 /etc/crowdsec/bouncers/crowdsec-spoa-bouncer.yamlIf you have created .local variants of these configuration files, please run equivalent commands for those files as well.
Note:
The DEB/RPM packages are patched to adjust these permissions on upgrade.
If you encounter issues, manually validate permissions/ownership and open an issue on this repository if problems persist.
Dockerfile
The Docker image has also been updated to run as the crowdsec-spoa user.
If you are building the container locally and mounting configuration files, ensure that:
- The mounted configuration is readable by
crowdsec-spoa.
Log Files
Since the systemd unit now runs as crowdsec-spoa, it can no longer write to the root-owned default /var/log directly.
The unit is configured to create a dedicated directory:
/var/log/crowdsec-spoaPlease update your YAML configuration accordingly:
log_dir: /var/log/crowdsec-spoa/Note:
The DEB/RPM packages may not clean up old log files in previous locations.
After the upgrade, you may want to manually remove any obsolete log files or directories.
v0.2.0-rc5
Breaking Changes
As outlined in the 0.1.0 release, every minor version before 1.0.0 may contain breaking changes.
Please review the sections below carefully before upgrading to avoid service interruptions.
TL;DR (Key Changes)
- Parent/worker model removed – the SPOA now runs as a single process.
workers,worker_user,worker_groupoptions removed – replaced bylisten_tcp/listen_unix.admin_socketremoved – the setting is now ignored and can be deleted.- Service now runs fully as
crowdsec-spoauser – config/log file permissions must allow this. - Docker image now runs as
crowdsec-spoa. - Default log directory moved to
/var/log/crowdsec-spoa/(config change required).
Inner Architecture
In short:
We removed the parent/worker architecture and now run a simpler, single-process model.
Background
Previously:
-
Multiple workers handled incoming SPOE messages from HAProxy.
-
Each worker communicated with a parent process over a Unix socket to fetch:
- State
- Decisions
- Host configuration (e.g. ban / captcha)
This design existed to support multiple SPOA listeners from a single process.
In practice, we found that users almost never configured more than one SPOA listener.
The added complexity:
- Slowed down feature development,
- Increased code debt,
- Made onboarding new contributors harder.
As a result, we have simplified the architecture to a single process that directly handles SPOE messages.
Configuration Changes
We have removed the following YAML options:
workersworker_userworker_group
These are replaced with:
listen_tcp: 127.0.0.1:9090
listen_unix: /path/to/unix.sockRecommendation:
Add these keys to your configuration before upgrading to avoid startup failures.
Admin Socket
Because we no longer support multiple SPOA listeners, the admin socket no longer provides value.
- The following option has been removed and is now ignored:
admin_socket: /path/to/admin.sockYou can safely remove this key from your configuration.
We know users still need a way to reload the SPOA without dropping in-flight messages from HAProxy.
In a future release, we plan to add a proper systemctl reload hook to handle this cleanly.
Process Owner (systemd Unit)
With the removal of the parent/worker model and the admin socket, the systemd unit now runs entirely as the crowdsec-spoa user.
This improves separation between service accounts and root, but it also means:
- All files needed by the SPOA must be readable by the
crowdsec-spoagroup.
For example:
chown root:crowdsec-spoa /etc/crowdsec/bouncers/crowdsec-spoa-bouncer.yaml
chmod 640 /etc/crowdsec/bouncers/crowdsec-spoa-bouncer.yamlIf you have created .local variants of these configuration files, please run equivalent commands for those files as well.
Note:
The DEB/RPM packages are patched to adjust these permissions on upgrade.
If you encounter issues, manually validate permissions/ownership and open an issue on this repository if problems persist.
Dockerfile
The Docker image has also been updated to run as the crowdsec-spoa user.
If you are building the container locally and mounting configuration files, ensure that:
- The mounted configuration is readable by
crowdsec-spoa.
Log Files
Since the systemd unit now runs as crowdsec-spoa, it can no longer write to the root-owned default /var/log directly.
The unit is configured to create a dedicated directory:
/var/log/crowdsec-spoaPlease update your YAML configuration accordingly:
log_dir: /var/log/crowdsec-spoa/Note:
The DEB/RPM packages may not clean up old log files in previous locations.
After the upgrade, you may want to manually remove any obsolete log files or directories.
v0.2.0-rc4
Breaking Changes
As outlined in the 0.1.0 release, every minor version before 1.0.0 may contain breaking changes.
Please review the sections below carefully before upgrading to avoid service interruptions.
TL;DR (Key Changes)
- Parent/worker model removed – the SPOA now runs as a single process.
workers,worker_user,worker_groupoptions removed – replaced bylisten_tcp/listen_unix.admin_socketremoved – the setting is now ignored and can be deleted.- Service now runs fully as
crowdsec-spoauser – config/log file permissions must allow this. - Docker image now runs as
crowdsec-spoa. - Default log directory moved to
/var/log/crowdsec-spoa/(config change required).
Inner Architecture
In short:
We removed the parent/worker architecture and now run a simpler, single-process model.
Background
Previously:
-
Multiple workers handled incoming SPOE messages from HAProxy.
-
Each worker communicated with a parent process over a Unix socket to fetch:
- State
- Decisions
- Host configuration (e.g. ban / captcha)
This design existed to support multiple SPOA listeners from a single process.
In practice, we found that users almost never configured more than one SPOA listener.
The added complexity:
- Slowed down feature development,
- Increased code debt,
- Made onboarding new contributors harder.
As a result, we have simplified the architecture to a single process that directly handles SPOE messages.
Configuration Changes
We have removed the following YAML options:
workersworker_userworker_group
These are replaced with:
listen_tcp: 127.0.0.1:9090
listen_unix: /path/to/unix.sockRecommendation:
Add these keys to your configuration before upgrading to avoid startup failures.
Admin Socket
Because we no longer support multiple SPOA listeners, the admin socket no longer provides value.
- The following option has been removed and is now ignored:
admin_socket: /path/to/admin.sockYou can safely remove this key from your configuration.
We know users still need a way to reload the SPOA without dropping in-flight messages from HAProxy.
In a future release, we plan to add a proper systemctl reload hook to handle this cleanly.
Process Owner (systemd Unit)
With the removal of the parent/worker model and the admin socket, the systemd unit now runs entirely as the crowdsec-spoa user.
This improves separation between service accounts and root, but it also means:
- All files needed by the SPOA must be readable by the
crowdsec-spoagroup.
For example:
chown root:crowdsec-spoa /etc/crowdsec/bouncers/crowdsec-spoa-bouncer.yaml
chmod 640 /etc/crowdsec/bouncers/crowdsec-spoa-bouncer.yamlIf you have created .local variants of these configuration files, please run equivalent commands for those files as well.
Note:
The DEB/RPM packages are patched to adjust these permissions on upgrade.
If you encounter issues, manually validate permissions/ownership and open an issue on this repository if problems persist.
Dockerfile
The Docker image has also been updated to run as the crowdsec-spoa user.
If you are building the container locally and mounting configuration files, ensure that:
- The mounted configuration is readable by
crowdsec-spoa.
Log Files
Since the systemd unit now runs as crowdsec-spoa, it can no longer write to the root-owned default /var/log directly.
The unit is configured to create a dedicated directory:
/var/log/crowdsec-spoaPlease update your YAML configuration accordingly:
log_dir: /var/log/crowdsec-spoa/Note:
The DEB/RPM packages may not clean up old log files in previous locations.
After the upgrade, you may want to manually remove any obsolete log files or directories.
v0.2.0-rc3
Breaking Changes
As outlined in the 0.1.0 release, every minor version before 1.0.0 may contain breaking changes.
Please review the sections below carefully before upgrading to avoid service interruptions.
TL;DR (Key Changes)
- Parent/worker model removed – the SPOA now runs as a single process.
workers,worker_user,worker_groupoptions removed – replaced bylisten_tcp/listen_unix.admin_socketremoved – the setting is now ignored and can be deleted.- Service now runs fully as
crowdsec-spoauser – config/log file permissions must allow this. - Docker image now runs as
crowdsec-spoa. - Default log directory moved to
/var/log/crowdsec-spoa/(config change required).
Inner Architecture
In short:
We removed the parent/worker architecture and now run a simpler, single-process model.
Background
Previously:
-
Multiple workers handled incoming SPOE messages from HAProxy.
-
Each worker communicated with a parent process over a Unix socket to fetch:
- State
- Decisions
- Host configuration (e.g. ban / captcha)
This design existed to support multiple SPOA listeners from a single process.
In practice, we found that users almost never configured more than one SPOA listener.
The added complexity:
- Slowed down feature development,
- Increased code debt,
- Made onboarding new contributors harder.
As a result, we have simplified the architecture to a single process that directly handles SPOE messages.
Configuration Changes
We have removed the following YAML options:
workersworker_userworker_group
These are replaced with:
listen_tcp: 127.0.0.1:9090
listen_unix: /path/to/unix.sockRecommendation:
Add these keys to your configuration before upgrading to avoid startup failures.
Admin Socket
Because we no longer support multiple SPOA listeners, the admin socket no longer provides value.
- The following option has been removed and is now ignored:
admin_socket: /path/to/admin.sockYou can safely remove this key from your configuration.
We know users still need a way to reload the SPOA without dropping in-flight messages from HAProxy.
In a future release, we plan to add a proper systemctl reload hook to handle this cleanly.
Process Owner (systemd Unit)
With the removal of the parent/worker model and the admin socket, the systemd unit now runs entirely as the crowdsec-spoa user.
This improves separation between service accounts and root, but it also means:
- All files needed by the SPOA must be readable by the
crowdsec-spoagroup.
For example:
chown root:crowdsec-spoa /etc/crowdsec/bouncers/crowdsec-spoa-bouncer.yaml
chmod 640 /etc/crowdsec/bouncers/crowdsec-spoa-bouncer.yamlIf you have created .local variants of these configuration files, please run equivalent commands for those files as well.
Note:
The DEB/RPM packages are patched to adjust these permissions on upgrade.
If you encounter issues, manually validate permissions/ownership and open an issue on this repository if problems persist.
Dockerfile
The Docker image has also been updated to run as the crowdsec-spoa user.
If you are building the container locally and mounting configuration files, ensure that:
- The mounted configuration is readable by
crowdsec-spoa.
Log Files
Since the systemd unit now runs as crowdsec-spoa, it can no longer write to the root-owned default /var/log directly.
The unit is configured to create a dedicated directory:
/var/log/crowdsec-spoaPlease update your YAML configuration accordingly:
log_dir: /var/log/crowdsec-spoa/Note:
The DEB/RPM packages may not clean up old log files in previous locations.
After the upgrade, you may want to manually remove any obsolete log files or directories.
v0.2.0-rc2
Breaking Changes
As outlined in the 0.1.0 release, every minor version before 1.0.0 may contain breaking changes.
Please review the sections below carefully before upgrading to avoid service interruptions.
TL;DR (Key Changes)
- Parent/worker model removed – the SPOA now runs as a single process.
workers,worker_user,worker_groupoptions removed – replaced bylisten_tcp/listen_unix.admin_socketremoved – the setting is now ignored and can be deleted.- Service now runs fully as
crowdsec-spoauser – config/log file permissions must allow this. - Docker image now runs as
crowdsec-spoa. - Default log directory moved to
/var/log/crowdsec-spoa/(config change required).
Inner Architecture
In short:
We removed the parent/worker architecture and now run a simpler, single-process model.
Background
Previously:
-
Multiple workers handled incoming SPOE messages from HAProxy.
-
Each worker communicated with a parent process over a Unix socket to fetch:
- State
- Decisions
- Host configuration (e.g. ban / captcha)
This design existed to support multiple SPOA listeners from a single process.
In practice, we found that users almost never configured more than one SPOA listener.
The added complexity:
- Slowed down feature development,
- Increased code debt,
- Made onboarding new contributors harder.
As a result, we have simplified the architecture to a single process that directly handles SPOE messages.
Configuration Changes
We have removed the following YAML options:
workersworker_userworker_group
These are replaced with:
listen_tcp: 127.0.0.1:9090
listen_unix: /path/to/unix.sockRecommendation:
Add these keys to your configuration before upgrading to avoid startup failures.
Admin Socket
Because we no longer support multiple SPOA listeners, the admin socket no longer provides value.
- The following option has been removed and is now ignored:
admin_socket: /path/to/admin.sockYou can safely remove this key from your configuration.
We know users still need a way to reload the SPOA without dropping in-flight messages from HAProxy.
In a future release, we plan to add a proper systemctl reload hook to handle this cleanly.
Process Owner (systemd Unit)
With the removal of the parent/worker model and the admin socket, the systemd unit now runs entirely as the crowdsec-spoa user.
This improves separation between service accounts and root, but it also means:
- All files needed by the SPOA must be readable by the
crowdsec-spoagroup.
For example:
chown root:crowdsec-spoa /etc/crowdsec/bouncers/crowdsec-haproxy-spoa.yaml
chmod 640 /etc/crowdsec/bouncers/crowdsec-haproxy-spoa.yamlIf you have created .local variants of these configuration files, please run equivalent commands for those files as well.
Note:
The DEB/RPM packages are patched to adjust these permissions on upgrade.
If you encounter issues, manually validate permissions/ownership and open an issue on this repository if problems persist.
Dockerfile
The Docker image has also been updated to run as the crowdsec-spoa user.
If you are building the container locally and mounting configuration files, ensure that:
- The mounted configuration is readable by
crowdsec-spoa.
Log Files
Since the systemd unit now runs as crowdsec-spoa, it can no longer write to the root-owned default /var/log directly.
The unit is configured to create a dedicated directory:
/var/log/crowdsec-spoaPlease update your YAML configuration accordingly:
log_dir: /var/log/crowdsec-spoa/Note:
The DEB/RPM packages may not clean up old log files in previous locations.
After the upgrade, you may want to manually remove any obsolete log files or directories.
v0.2.0-rc1
Breaking Changes
As outlined in the 0.1.0 release, every minor version before 1.0.0 may contain breaking changes.
Please review the sections below carefully before upgrading to avoid service interruptions.
TL;DR (Key Changes)
- Parent/worker model removed – the SPOA now runs as a single process.
workers,worker_user,worker_groupoptions removed – replaced bylisten_tcp/listen_unix.admin_socketremoved – the setting is now ignored and can be deleted.- Service now runs fully as
crowdsec-spoauser – config/log file permissions must allow this. - Docker image now runs as
crowdsec-spoa. - Default log directory moved to
/var/log/crowdsec-spoa/(config change required).
Inner Architecture
In short:
We removed the parent/worker architecture and now run a simpler, single-process model.
Background
Previously:
-
Multiple workers handled incoming SPOE messages from HAProxy.
-
Each worker communicated with a parent process over a Unix socket to fetch:
- State
- Decisions
- Host configuration (e.g. ban / captcha)
This design existed to support multiple SPOA listeners from a single process.
In practice, we found that users almost never configured more than one SPOA listener.
The added complexity:
- Slowed down feature development,
- Increased code debt,
- Made onboarding new contributors harder.
As a result, we have simplified the architecture to a single process that directly handles SPOE messages.
Configuration Changes
We have removed the following YAML options:
workersworker_userworker_group
These are replaced with:
listen_tcp: 127.0.0.1:9090
listen_unix: /path/to/unix.sockRecommendation:
Add these keys to your configuration before upgrading to avoid startup failures.
Admin Socket
Because we no longer support multiple SPOA listeners, the admin socket no longer provides value.
- The following option has been removed and is now ignored:
admin_socket: /path/to/admin.sockYou can safely remove this key from your configuration.
We know users still need a way to reload the SPOA without dropping in-flight messages from HAProxy.
In a future release, we plan to add a proper systemctl reload hook to handle this cleanly.
Process Owner (systemd Unit)
With the removal of the parent/worker model and the admin socket, the systemd unit now runs entirely as the crowdsec-spoa user.
This improves separation between service accounts and root, but it also means:
- All files needed by the SPOA must be readable by the
crowdsec-spoagroup.
For example:
chown root:crowdsec-spoa /etc/crowdsec/bouncers/crowdsec-haproxy-spoa.yaml
chmod 640 /etc/crowdsec/bouncers/crowdsec-haproxy-spoa.yamlIf you have created .local variants of these configuration files, please run equivalent commands for those files as well.
Note:
The DEB/RPM packages are patched to adjust these permissions on upgrade.
If you encounter issues, manually validate permissions/ownership and open an issue on this repository if problems persist.
Dockerfile
The Docker image has also been updated to run as the crowdsec-spoa user.
If you are building the container locally and mounting configuration files, ensure that:
- The mounted configuration is readable by
crowdsec-spoa.
Log Files
Since the systemd unit now runs as crowdsec-spoa, it can no longer write to the root-owned default /var/log directly.
The unit is configured to create a dedicated directory:
/var/log/crowdsec-spoaPlease update your YAML configuration accordingly:
log_dir: /var/log/crowdsec-spoa/Note:
The DEB/RPM packages may not clean up old log files in previous locations.
After the upgrade, you may want to manually remove any obsolete log files or directories.
v0.1.2
🚀 Highlights
- Upstream proxy/CDN support (single-message SPOE) — Evaluate the true client IP (e.g., from
X-Real-IP/X-Forwarded-For) when HAProxy sits behind a CDN/L7 proxy. - Smart fallback — If HAProxy didn’t precompute a
remediationvariable, the bouncer now falls back to IP-based remediation. - Maintenance & CI — Cleaner packaging scripts, pinned actions, refreshed CrowdSec deps, and linter rules.
Why this matters
When HAProxy is behind a CDN or another L7 proxy, the socket’s src is not the real client. This release lets the bouncer evaluate the true client IP (from a header like X-Real-IP) and still apply decisions correctly—even if HAProxy didn’t precompute a remediation variable.
Recommended SPOE config (single message)
Use only the crowdsec-http message. It extracts the real IP and includes all arguments the bouncer needs.
Adjust the header (x-real-ip) to match your proxy/CDN setup (e.g., x-forwarded-for).
# /etc/haproxy/spoe/crowdsec.cfg
# SPOE section
# - Uses a single message: crowdsec-http
# - Extracts real client IP from X-Real-IP (change if needed)
# - Falls back to IP remediation if 'remediation' var is not set
[crowdsec]
spoe-agent crowdsec-agent
messages 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 extracts the real IP via X-Real-IP and includes all arguments.
# IMPORTANT: req.hdr_ip() returns an IP type (required by SPOE protocol).
# If 'remediation' isn't provided by HAProxy, the bouncer will check IP remediation.
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 \
src-ip=req.hdr_ip(x-real-ip) src-port=src_port
event on-frontend-http-request
# Tip: If your upstream sets X-Forwarded-For, you can use:
# src-ip=req.hdr_ip(x-forwarded-for)Migration notes
- If you don’t use an upstream proxy/CDN in front of HAProxy, keep using
crowdsec-ipandcrowdsec-httptogether as before. - If you do have an upstream proxy/CDN, see the examples in #85 and adapt the header (
X-Real-IPvsX-Forwarded-For) to your environment.
What’s Changed
- Add example configuration for HAProxy behind upstream proxy by @LaurenceJJones in #85
- Add IP remediation fallback when remediation variable not set by @LaurenceJJones in #86
- Rename bouncer in postrm script by @LaurenceJJones in #93
- avoid "install /dev/stdin" by @mmetc in #94
- update crowdsec dependencies and linter rules by @mmetc in #95
- update and pin action dependencies by @mmetc in #96
Full Changelog: v0.1.0...v0.1.2
v0.1.1-rc2
✨ Highlights
- Packaging & CI polish (RC2) — Safer post-remove script, cleaner installs (no
install /dev/stdin), updated CrowdSec deps, pinned CI actions. - Config recap (from RC1, still valid) — Support for upstream proxy/CDN with a single
crowdsec-httpSPOE message using a real-IP header; automatic fallback to IP remediation ifremediationisn’t set.
What’s Changed
- Rename bouncer in postrm script by @LaurenceJJones in #93
- avoid "install /dev/stdin" by @mmetc in #94
- update crowdsec dependencies and linter rules by @mmetc in #95
- update and pin action dependencies by @mmetc in #96
Full Changelog: v0.1.1-rc1...v0.1.1-rc2
Config notes (from RC1)
- Behind a proxy/CDN? Use only
crowdsec-httpand set the real client IP header (e.g.,x-real-iporx-forwarded-for). - Not behind a proxy? Keep using
crowdsec-ippluscrowdsec-httptogether. - If
remediationisn’t set by HAProxy, the bouncer falls back to IP-based remediation.
v0.1.1-rc1
✨ Highlights
- Upstream proxy/CDN support — You can now run HAProxy behind an upstream proxy (e.g., a CDN) and use a single SPOE message (
crowdsec-http) that supports getting the real client IP from an HTTP header. - Safer defaults — If the
remediationvariable isn’t set bycrowdsec-ip, the SPOA bouncer now falls back to IP-based remediation automatically.
What’s Changed
- Add example configuration for HAProxy behind upstream proxy by @LaurenceJJones in #85
- Add IP remediation fallback when remediation variable not set by @LaurenceJJones in #86
Full Changelog: v0.1.0...v0.1.1-rc1
Why this matters
When HAProxy is behind a CDN or another L7 proxy, the socket’s src is not the real client. This release lets the bouncer evaluate the true client IP (from a header like X-Real-IP) and still apply decisions correctly—even if HAProxy didn’t precompute a remediation variable.
Recommended SPOE config (single message)
Use only the crowdsec-http message. It extracts the real IP and includes all args the bouncer needs.
Adjust the header (x-real-ip) to match your proxy/CDN setup (e.g., x-forwarded-for).
# /etc/haproxy/spoe/crowdsec.cfg
# SPOE section
# - Uses a single message: crowdsec-http
# - Extracts real client IP from X-Real-IP (change if needed)
# - Falls back to IP remediation if 'remediation' var is not set
[crowdsec]
spoe-agent crowdsec-agent
messages 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 extracts the real IP via X-Real-IP and includes all arguments.
# IMPORTANT: req.hdr_ip() returns an IP type (required by SPOE protocol).
# If 'remediation' isn't provided by HAProxy, the bouncer will check IP remediation.
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 \
src-ip=req.hdr_ip(x-real-ip) src-port=src_port
event on-frontend-http-requestTip: If your upstream sets
X-Forwarded-For, you can use:
src-ip=req.hdr_ip(x-forwarded-for)
Migration notes
If you do not use an upstream proxy like Cloudflare for example then these do not apply and still use the crowdsec-ip and crowdsec-http in unison
- if you are using a upstream proxy infront of HAproxy then check #85 the examples files and alter to your setup.
v0.1.0
⚠️ Breaking Changes
Minor releases in this project can include breaking changes until 1.0.0. A migration path is provided below.
1) Reduce Lua invocations in HAProxy (applies to everyone)
Only call the Lua handler when a decision actually requires it.
Before
http-request lua.crowdsec_handle if { var(txn.crowdsec.remediation) -m found }After
http-request lua.crowdsec_handle if { var(txn.crowdsec.remediation) -m str "captcha" }
http-request lua.crowdsec_handle if { var(txn.crowdsec.remediation) -m str "ban" }2) Captcha flow moved from Lua to native HAProxy rules (only if you use Captcha)
- Lua no longer sets or clears the captcha cookie.
- Cookie management is now handled with
http-after-response. - On successful captcha, redirects are now native HAProxy redirects (not Lua).
Add these to the frontend that uses Captcha:
Set/clear Captcha cookie
# Set captcha cookie when SPOA provides a status (pending or valid)
http-after-response set-header Set-Cookie %[var(txn.crowdsec.captcha_cookie)] \
if { var(txn.crowdsec.captcha_status) -m found } { var(txn.crowdsec.captcha_cookie) -m found }
# Clear captcha cookie when cookie exists but no captcha_status (Allow decision)
http-after-response set-header Set-Cookie %[var(txn.crowdsec.captcha_cookie)] \
if { var(txn.crowdsec.captcha_cookie) -m found } !{ var(txn.crowdsec.captcha_status) -m found }Redirect after successful validation
# IMPORTANT: place this BEFORE the lua.crowdsec_handle lines
http-request redirect code 302 location %[var(txn.crowdsec.redirect)] \
if { var(txn.crowdsec.remediation) -m str "allow" } { var(txn.crowdsec.redirect) -m found }
# Lua now only for captcha/ban
http-request lua.crowdsec_handle if { var(txn.crowdsec.remediation) -m str "captcha" }
http-request lua.crowdsec_handle if { var(txn.crowdsec.remediation) -m str "ban" }Note: There is no “original” user config to revert from for the Lua cookie logic—this change replaces internal Lua behavior with HAProxy-native rules.
✅ Migration Checklist
-
Update
http-request lua.crowdsec_handleto trigger only forcaptchaandban. -
If using Captcha:
- Add the two
http-after-response set-header Set-Cookierules to your Captcha frontend. - Add the native
http-request redirectrule before the Lua lines.
- Add the two
-
Reload HAProxy.
What’s Changed
Features & Enhancements
- feat: HAProxy-native redirects replace Lua-based redirects. (@LaurenceJJones, #62)
- feat: Captcha cookie handling moved to HAProxy with remediation expiry support. (@LaurenceJJones, #60)
- enhance: Host manager logging and logger inheritance. (@LaurenceJJones, #55)
- enhance: API/client handling & logging. (@LaurenceJJones, #51)
- enhance: Captcha validation and error handling. (@LaurenceJJones, #53)
- enhance: Configurable Captcha timeouts. (@LaurenceJJones, #50)
- enhance: Add debug logging when no host matches in
MatchFirstHost. (@LaurenceJJones, #83) - enhance: Improve post-installation messages with accurate setup steps. (@LaurenceJJones, #82)
- enhance: Implement
--versionflag. (@LaurenceJJones, #78) - optimize: Dataset performance, fewer allocations, reduced debug logs. (@LaurenceJJones, #52)
- optimize:
MatchFirstHostearly return when no hosts configured. (@LaurenceJJones, #84)
Fixes
- fix: remove stale unix socket files before creating listeners. (@LaurenceJJones, #72)
- fix: remove unnecessary pointer indirection for
net.Listenerslice. (@LaurenceJJones, #71) - fix: make Server lifecycle context-aware with proper errgroup management. (@LaurenceJJones)
- fix: Admin socket handling for 2/3-part commands. (@LaurenceJJones, #58)
- fix: Worker-to-API decode error handling. (@LaurenceJJones, #59)
- fix: Docker configuration and paths. (@LaurenceJJones, #54)
- fix: Turnstile key name. (@LaurenceJJones, #48)
- fix: Resolve
maintidxCI issue via API constructor refactor. (@LaurenceJJones, #56) - fix: packaging improvements. (@sabban, #90)
- chore: add
restart unless-stoppeddefault in sample service files. (@WhyAydan, @LaurenceJJones, #21)
CI / Release
Full Changelog
Since last stable: v0.0.4...v0.1.0
TL;DR
- Call Lua only for
captchaandban. - Move Captcha cookie + redirect handling to native HAProxy.
- Add the provided
http-after-responseandhttp-request redirectrules to your Captcha frontend and place the redirect before Lua. - Includes many quality-of-life improvements (version flag, clearer post-install, better logs) and stability fixes (lifecycle, sockets, packaging).