WIUNIX ACADEMY
CrowdSec and Nginx: trustworthy logs, private LAPI and reversible IP bans
Page 4 of 5. Review the earlier steps and prerequisites before continuing.
YOUR SYSTEM. YOUR STEPS.
Where are you working?
Choose your OS and version. The prerequisites, commands and troubleshooting follow your environment.
USE YOUR OWN VALUES
Configure this tutorial
Set the example values for your environment; related explanations and copy panels update together. Never enter passwords, private keys or tokens. Values stay in this tab and are not sent to the server or share links. Check actual DNS, certificates and network policy before running commands.
Different IP addresses, domains or ports? Open the settings below, change the values and select “Apply to tutorial”, then copy the updated commands.
Set values for my environment7 editable values
LET’S BUILD
Inspect acquisition, parsing and bouncer authentication
Generate a request first, then inspect. Loopback events may be whitelisted by the collection; that is expected and is not a failed parser. explain evaluates parsing, not scenario overflow. A recent authenticated bouncer pull plus a real403 test is stronger evidence than a registered row alone.
Dedicated disposable VM · terminal
curl --noproxy '*' --interface '127.0.0.2' --fail http://127.0.0.1:18080/index.html
sleep 1
sudo '/srv/academy-crowdsec/crowdsec-v1.8.1/cmd/crowdsec-cli/cscli' -c '/srv/academy-crowdsec/config/engine.yaml' explain --crowdsec '/srv/academy-crowdsec/crowdsec-v1.8.1/cmd/crowdsec/crowdsec' --file '/srv/academy-crowdsec/logs/access.log' --type nginx
sudo '/srv/academy-crowdsec/crowdsec-v1.8.1/cmd/crowdsec-cli/cscli' -c '/srv/academy-crowdsec/config/engine.yaml' metrics --url 'http://127.0.0.1:18082/metrics' show acquisition
sudo '/srv/academy-crowdsec/crowdsec-v1.8.1/cmd/crowdsec-cli/cscli' -c '/srv/academy-crowdsec/config/engine.yaml' bouncers list
The source path appears in acquisition metrics, Nginx parsing is visible, and the bouncer has queried the local API.
LET’S BUILD
Ban only the controlled loopback source
Add a30-second manual decision, wait beyond the one-second live cache, then test. The other request deliberately forges both common client-IP headers; it must still be allowed because its TCP peer is management. Manual ban proves decision enforcement, not automatic scenario detection.
Dedicated disposable VM · terminal
sudo '/srv/academy-crowdsec/crowdsec-v1.8.1/cmd/crowdsec-cli/cscli' -c '/srv/academy-crowdsec/config/engine.yaml' decisions add --ip '127.0.0.2' --type ban --duration 30s --reason academy-test
sleep 2
curl --noproxy '*' --interface '127.0.0.2' --silent --output /dev/null --write-out '%{http_code}\n' http://127.0.0.1:18080/index.html
curl --noproxy '*' --interface 127.0.0.1 --fail -H 'X-Forwarded-For: 127.0.0.2' -H 'X-Real-IP: 127.0.0.2' http://127.0.0.1:18080/index.html
sudo '/srv/academy-crowdsec/crowdsec-v1.8.1/cmd/crowdsec-cli/cscli' -c '/srv/academy-crowdsec/config/engine.yaml' decisions list --ip '127.0.0.2'
First request403; spoofed-header management request academy-ok; decision identifies 127.0.0.2.
LET’S BUILD
Recover the exact source and verify expiry
Delete only this source’s test decisions, never all decisions. After the second short decision, verify that expiry also restores access after cache refresh. Keep independent console/SSH access for real deployments; allowlists are not a replacement for a recovery route.
Dedicated disposable VM · terminal
sudo '/srv/academy-crowdsec/crowdsec-v1.8.1/cmd/crowdsec-cli/cscli' -c '/srv/academy-crowdsec/config/engine.yaml' decisions delete --ip '127.0.0.2'
sleep 2
curl --noproxy '*' --interface '127.0.0.2' --fail http://127.0.0.1:18080/index.html
sudo '/srv/academy-crowdsec/crowdsec-v1.8.1/cmd/crowdsec-cli/cscli' -c '/srv/academy-crowdsec/config/engine.yaml' decisions add --ip '127.0.0.2' --duration 5s --reason academy-expiry
sleep 7
curl --noproxy '*' --interface '127.0.0.2' --fail http://127.0.0.1:18080/index.html
Both final requests return academy-ok; the5-second decision no longer blocks after7 seconds.
Understand the real API failure policy
This recipe chooses live mode with a one-second cache and500ms request timeout. In reviewed bouncer1.2.3, failed LAPI requests and non200 API responses allow uncached traffic; this is fail open, not a configurable universal fail-closed guarantee. A cached ban can survive until its cache TTL. A syntactically broken initialization can instead prevent Nginx starting. Stream mode has a different stale-state/timer model and is not tested by this recipe.
In terminalA stop only the foreground lab engine with Ctrl+C; after more than one second request the test file from terminalB. It should remain available while the dedicated error log records the failed API request. Restart terminalA with the same command and repeat ban/unban. Availability during an outage means reputation enforcement is degraded; monitor it. APPSEC_FAILURE_ACTION controls AppSec, not this LAPI failure policy. The initial missing CAPTCHA key/ban-template notices are expected for this ban-only403 configuration; they are not proof of a broken LAPI. Do not hide later API authentication/time-out errors among those notices.
Read bounded diagnostics without exposing keys
Use these panels for the outage test and non-secret logs. Never dump complete Nginx configuration or print the bouncer credential file as a support transcript: expanded configuration and private credentials do not belong in tickets. Restrict and rotate access/error logs; combined logs contain IPs, user agents, referrers and requested paths/query strings. Do not use real personal URLs in this lab.
curl --noproxy '*' --interface '127.0.0.2' --fail http://127.0.0.1:18080/index.html
sudo tail -n 20 '/srv/academy-crowdsec/logs/nginx-error.log'
sudo '/srv/academy-crowdsec/crowdsec-v1.8.1/cmd/crowdsec-cli/cscli' -c '/srv/academy-crowdsec/config/engine.yaml' alerts list
LET’S BUILD
Stop only this child Nginx and preserve evidence
The dedicated prefix/config/PID select this child Nginx. Stop terminalA with Ctrl+C. Preserve private state until you have reviewed false positives; do not delete unrelated decisions, services or logs. A fresh root is safer than reusing a half-completed lab. To revoke a compromised dedicated bouncer, use the separate scoped command below and register a replacement in a new protected file; revocation may make live-mode traffic fail open.
Dedicated disposable VM · terminal
sudo nginx -p '/srv/academy-crowdsec/' -c '/srv/academy-crowdsec/config/nginx.conf' -s quit
Only the dedicated Nginx listener exits; private files remain for review.