What happened?
I have configured the crowdsec-openresty-bouncer in Stream mode with mTLS authentication. The stream synchronization works perfectly (the bouncer successfully fetches the stream via /v1/decisions/stream using the client certificates).
However, every 15 minutes, when our Prometheus server scrapes the Nginx metrics endpoint (port 9145, GET /metrics), the bouncer generates a 403 error in the Nginx error log.
The log shows that the bouncer is attempting to query the Live API (/v1/decisions?ip=...), and this specific Live LAPI request is rejected with an HTTP 403 error.
Error log:
[error] 229659#229659: *665493 [lua] crowdsec.lua:689: Allow(): [Crowdsec] bouncer error: Http error 403 while talking to LAPI (https://crowdsec-lapi.numberly.dev/v1/decisions?ip=10.6.31.28), client: 10.X.X.X, server: , request: "GET /metrics HTTP/1.1", host: "cdn1-node1.dv.par5.numberly.net:9145"
It seems that the bouncer is unexpectedly falling back to the Live API for this specific server block/port, and failing to pass the mTLS certificates for this specific call (or the LAPI rejects it).
What did you expect to happen?
If falling back to the Live API is the intended behavior in this case, I expect the bouncer to successfully use the configured mTLS certificates (TLS_CERT_PATH, TLS_KEY_PATH) just as it does for the stream sync, returning a 200 OK rather than a 403 Forbidden.
How can we reproduce it (as minimally and precisely as possible)?
Here is the steps we followed (but it might come from how we coded the whole thing) :
Set up a CrowdSec LAPI requiring mTLS authentication (no API key).
Install crowdsec-openresty-bouncer on an Nginx node.
Configure the bouncer with MODE=stream and provide valid TLS_CERT_PATH / TLS_KEY_PATH.
Ensure the Nginx worker (www-data) has the correct Linux permissions to read the private key.
Expose a Prometheus metrics endpoint on a different port (e.g., 9145) with CrowdSec access logic enabled.
Perform periodic GET /metrics requests to that port.
Anything else we need to know?
No response
Crowdsec version
Details
$ cscli version
version: v1.7.4-debian-pragmatic-amd64-469b374e
Codename: alphaga
BuildDate: 2025-12-04_15:31:39
GoVersion: 1.25.3
Platform: linux
libre2: C++
User-Agent: crowdsec/v1.7.4-debian-pragmatic-amd64-469b374e-linux
Constraint_parser: >= 1.0, <= 3.0
Constraint_scenario: >= 1.0, <= 3.0
Constraint_api: v1
Constraint_acquis: >= 1.0, < 2.0
Built-in optional components: cscli_setup, datasource_appsec, datasource_cloudwatch, datasource_docker, datasource_file, datasource_http, datasource_journalctl, datasource_k8s-audit, datasource_kafka, datasource_kinesis, datasource_loki, datasource_s3, datasource_syslog, datasource_victorialogs, datasource_wineventlog, db_mysql, db_postgres, db_sqlite
OS version
Details
# On Linux:
$ cat /etc/os-release
PRETTY_NAME="Ubuntu 24.04.2 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION="24.04.2 LTS (Noble Numbat)"
VERSION_CODENAME=noble
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=noble
LOGO=ubuntu-logo
$ uname -a
Linux crowdsec1-node1.dv.par5.numberly.net 6.8.0-90-generic crowdsecurity/crowdsec#91-Ubuntu SMP PREEMPT_DYNAMIC Tue Nov 18 14:14:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
# On Windows:
C:\> wmic os get Caption, Version, BuildNumber, OSArchitecture
# paste output here
Enabled collections and parsers
Details
$ cscli hub list -o raw
# paste output here
Acquisition config
Details
# On Linux:
$ cat /etc/crowdsec/acquis.yaml /etc/crowdsec/acquis.d/*
# paste output here
# On Windows:
C:\> Get-Content C:\ProgramData\CrowdSec\config\acquis.yaml
# paste output here
Config show
Details
$ cscli config show
Global:
- Configuration Folder : /etc/crowdsec
- Data Folder : /var/lib/crowdsec/data
- Hub Folder : /etc/crowdsec/hub
- Notification Folder : /etc/crowdsec/notifications
- Simulation File : /etc/crowdsec/simulation.yaml
- Log Folder : /var/log
- Log level : info
- Log Media : file
Crowdsec:
- Acquisition File : /etc/crowdsec/acquis.yaml
- Parsers routines : 16
- Acquisition Folder : /etc/crowdsec/acquis.d
cscli:
- Output : human
- Hub Branch :
API Client:
- URL : https://crowdsec-lapi.numberly.dev/
- Login :
- Credentials File : /etc/crowdsec/local_api_credentials.yaml
Local API Server:
- Listen URL : 0.0.0.0:443
- Listen Socket :
- Profile File : /etc/crowdsec/profiles.yaml
- Cert File : /etc/ssl/certs/host-full_chain.cert
- Key File : /etc/ssl/private/host-certificate.key
- CA Cert : /etc/ssl/certs/host-ca_chain.cert
- Allowed Agents OU : IT servers
- Allowed Agents OU : team-infrastructure
- Allowed Bouncers OU : IT servers
- Allowed Bouncers OU : team-infrastructure
- Trusted IPs:
- X.X.X.X
- Database:
- Type : postgres
- Host : rw-pgsql3-dv.numberly.in
- Port : 5433
- User : crowdsec_dv
- DB Name : crowdsec_dv
- Max Open Conns : 100
- Flush age : 168h0m0s
- Flush size : 5000
Prometheus metrics
Details
$ cscli metrics
# paste output here
Related custom configs versions (if applicable) : notification plugins, custom scenarios, parsers etc.
Details
What happened?
I have configured the crowdsec-openresty-bouncer in Stream mode with mTLS authentication. The stream synchronization works perfectly (the bouncer successfully fetches the stream via /v1/decisions/stream using the client certificates).
However, every 15 minutes, when our Prometheus server scrapes the Nginx metrics endpoint (port 9145, GET /metrics), the bouncer generates a 403 error in the Nginx error log.
The log shows that the bouncer is attempting to query the Live API (/v1/decisions?ip=...), and this specific Live LAPI request is rejected with an HTTP 403 error.
Error log:
[error] 229659#229659: *665493 [lua] crowdsec.lua:689: Allow(): [Crowdsec] bouncer error: Http error 403 while talking to LAPI (https://crowdsec-lapi.numberly.dev/v1/decisions?ip=10.6.31.28), client: 10.X.X.X, server: , request: "GET /metrics HTTP/1.1", host: "cdn1-node1.dv.par5.numberly.net:9145"
It seems that the bouncer is unexpectedly falling back to the Live API for this specific server block/port, and failing to pass the mTLS certificates for this specific call (or the LAPI rejects it).
What did you expect to happen?
If falling back to the Live API is the intended behavior in this case, I expect the bouncer to successfully use the configured mTLS certificates (TLS_CERT_PATH, TLS_KEY_PATH) just as it does for the stream sync, returning a 200 OK rather than a 403 Forbidden.
How can we reproduce it (as minimally and precisely as possible)?
Here is the steps we followed (but it might come from how we coded the whole thing) :
Set up a CrowdSec LAPI requiring mTLS authentication (no API key).
Install crowdsec-openresty-bouncer on an Nginx node.
Configure the bouncer with MODE=stream and provide valid TLS_CERT_PATH / TLS_KEY_PATH.
Ensure the Nginx worker (www-data) has the correct Linux permissions to read the private key.
Expose a Prometheus metrics endpoint on a different port (e.g., 9145) with CrowdSec access logic enabled.
Perform periodic GET /metrics requests to that port.
Anything else we need to know?
No response
Crowdsec version
Details
OS version
Details
Enabled collections and parsers
Details
Acquisition config
Details
Config show
Details
Prometheus metrics
Details
Related custom configs versions (if applicable) : notification plugins, custom scenarios, parsers etc.
Details