CrowdSec is an open source intrusion prevention system. Its security engine reads your logs, detects attacks such as SSH brute force or web scanning with community-maintained scenarios, and decides to block the offending IP. Separate components called bouncers enforce those decisions, for example by adding the IP to the firewall. Participating instances also share the IPs they block and receive a community blocklist in return. In this tutorial you will install CrowdSec on Ubuntu 24.04, protect SSH and Nginx, install the nftables firewall bouncer, test a ban and learn the day-to-day cscli commands.
Prerequisites
To follow this tutorial you need:
- A server running Ubuntu 24.04 LTS with a public IP address, for example a CubePath VPS.
- A non-root user with
sudoprivileges. - Nginx installed if you want to protect a website (optional; SSH protection works without it).
- The public IP address you connect from, which you will allowlist so you cannot ban yourself. You can find it by running
curl -4 ifconfig.mefrom your own computer.
Step 1 - Adding the CrowdSec repository
Ubuntu's archive ships an old CrowdSec release, so use the official repository hosted on packagecloud. Download its signing key into /etc/apt/keyrings:
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://packagecloud.io/crowdsec/crowdsec/gpgkey | sudo gpg --dearmor -o /etc/apt/keyrings/crowdsec.gpg
Add the repository for Ubuntu 24.04 (noble), restricted to that key:
echo "deb [signed-by=/etc/apt/keyrings/crowdsec.gpg] https://packagecloud.io/crowdsec/crowdsec/ubuntu/ noble main" | sudo tee /etc/apt/sources.list.d/crowdsec.list
sudo apt update
Confirm that apt will install the package from packagecloud:
apt-cache policy crowdsec
crowdsec:
Installed: (none)
Candidate: 1.7.x
Version table:
1.7.x 500
500 https://packagecloud.io/crowdsec/crowdsec/ubuntu noble/main amd64 Packages
1.4.6-... 500
500 http://archive.ubuntu.com/ubuntu noble/universe amd64 Packages
The candidate must be the packagecloud version, not the older one from universe.
Step 2 - Installing the security engine
Install CrowdSec:
sudo apt install crowdsec
During installation the package detects the services running on the server, installs the matching collections (parsers and scenarios) from the CrowdSec Hub, configures the log files to read and starts the service. Check that it is running:
sudo systemctl status crowdsec --no-pager
● crowdsec.service - Crowdsec agent
Loaded: loaded (/usr/lib/systemd/system/crowdsec.service; enabled; preset: enabled)
Active: active (running) since Fri 2026-09-25 10:02:41 UTC; 30s ago
List the installed collections:
sudo cscli collections list
COLLECTIONS
Name Status Version Local Path
crowdsecurity/linux enabled 0.2 /etc/crowdsec/collections/linux.yaml
crowdsecurity/sshd enabled 0.3 /etc/crowdsec/collections/sshd.yaml
crowdsecurity/sshd contains the SSH brute force scenarios, and crowdsecurity/linux the base parsers for syslog and auth.log.
Step 3 - Adding Nginx protection
If Nginx was already installed, the installer probably added the crowdsecurity/nginx collection. If not, or if you installed Nginx afterward, add it now. It includes the web scenarios from crowdsecurity/base-http-scenarios, which detect path scanning, known exploit probes and bad user agents:
sudo cscli collections install crowdsecurity/nginx
CrowdSec reads logs defined in acquisition files. Create one for Nginx under /etc/crowdsec/acquis.d/:
sudo nano /etc/crowdsec/acquis.d/nginx.yaml
filenames:
- /var/log/nginx/access.log
- /var/log/nginx/error.log
labels:
type: nginx
The type label tells CrowdSec which parser to use for these files. Reload the service to apply the new collection and acquisition:
sudo systemctl reload crowdsec
Generate a few requests to the site, then check that CrowdSec reads and parses the logs:
sudo cscli metrics show acquisition
Acquisition Metrics:
╭────────────────────────────────┬────────────┬──────────────┬────────────────┬────────────────────────╮
│ Source │ Lines read │ Lines parsed │ Lines unparsed │ Lines poured to bucket │
├────────────────────────────────┼────────────┼──────────────┼────────────────┼────────────────────────┤
│ file:/var/log/auth.log │ 184 │ 41 │ 143 │ 12 │
│ file:/var/log/nginx/access.log │ 25 │ 25 │ - │ 3 │
╰────────────────────────────────┴────────────┴──────────────┴────────────────┴────────────────────────╯
Each log file should show lines read and parsed. Unparsed lines in auth.log are normal, since many log lines are not related to logins.
Step 4 - Allowlisting your own IP
Before enforcing bans, make sure CrowdSec will never block the addresses you administer the server from. Create an allowlist parser in the enrichment stage:
sudo nano /etc/crowdsec/parsers/s02-enrich/my-allowlist.yaml
name: my/allowlist
description: "Never ban administrator IPs"
whitelist:
reason: "administrator IPs"
ip:
- "203.0.113.10"
cidr:
- "10.10.0.0/24"
Replace 203.0.113.10 with your public IP and the CIDR with your private network, or remove the cidr block if you do not have one. Reload CrowdSec:
sudo systemctl reload crowdsec
Confirm the parser is loaded:
sudo cscli parsers list | grep allowlist
my-allowlist.yaml enabled,local /etc/crowdsec/parsers/s02-enrich/my-allowlist.yaml
Step 5 - Installing the firewall bouncer
So far CrowdSec only detects attacks and makes decisions. A bouncer enforces them. Ubuntu 24.04 uses nftables, so install the nftables variant of the firewall bouncer:
sudo apt install crowdsec-firewall-bouncer-nftables
Because the security engine runs on the same machine, the package registers the bouncer with the local API automatically and starts it. Verify both:
sudo cscli bouncers list
sudo systemctl is-active crowdsec-firewall-bouncer
Name IP Address Valid Last API pull Type Version
cs-firewall-bouncer-1727258561 127.0.0.1 true 2026-09-25T10:10:12Z crowdsec-firewall-bouncer v0.0.31
active
The bouncer adds its own nftables tables and chains. It works alongside UFW, since both use nftables on Ubuntu 24.04, and drops packets from banned IPs before they reach your UFW rules.
Step 6 - Testing a ban
Instead of attacking your own server, add a manual decision for a test address from the documentation range:
sudo cscli decisions add --ip 198.51.100.23 --duration 10m --reason "manual test"
Decision successfully added
List the active decisions:
sudo cscli decisions list
╭─────────┬────────┬──────────────────┬─────────────┬────────┬─────────┬────┬────────┬────────────┬──────────╮
│ ID │ Source │ Scope:Value │ Reason │ Action │ Country │ AS │ Events │ expiration │ Alert ID │
├─────────┼────────┼──────────────────┼─────────────┼────────┼─────────┼────┼────────┼────────────┼──────────┤
│ 1287741 │ cscli │ Ip:198.51.100.23 │ manual test │ ban │ │ │ 1 │ 9m52s │ 1 │
╰─────────┴────────┴──────────────────┴─────────────┴────────┴─────────┴────┴────────┴────────────┴──────────╯
Within a few seconds the bouncer pulls the decision and adds the IP to its nftables set. Look for it in the ruleset:
sudo nft list ruleset | grep 198.51.100.23
elements = { 198.51.100.23 timeout 9m50s expires 9m41s }
Remove the test decision:
sudo cscli decisions delete --ip 198.51.100.23
Real attacks follow the same path. For example, repeated failed SSH logins from one address trigger the crowdsecurity/ssh-bf scenario, which creates an alert and a ban decision, usually for four hours. List what was detected with:
sudo cscli alerts list
Step 7 - Enrolling in the CrowdSec Console (optional)
By default your instance already shares the IPs it bans with the CrowdSec network and receives the community blocklist in return. Check the connection to the central API:
sudo cscli capi status
You can successfully interact with Central API (CAPI)
To see alerts from all your servers in a web dashboard and subscribe to additional blocklists, create a free account at app.crowdsec.net, copy the enrollment key it shows and run:
sudo cscli console enroll your_enroll_key
Accept the new instance in the Console, then restart the engine so it picks up the enrollment:
sudo systemctl restart crowdsec
Step 8 - Keeping the Hub up to date
Parsers and scenarios improve over time. Update the Hub index and upgrade everything installed:
sudo cscli hub update
sudo cscli hub upgrade
sudo systemctl reload crowdsec
Run these commands every few weeks, or from a monthly cron job. Upgrade the engine and bouncer themselves with your normal sudo apt upgrade.
Troubleshooting
CrowdSec fails to start with bind: address already in use. The local API listens on 127.0.0.1:8080 by default, which clashes with any other service on that port. Change listen_uri under api.server in /etc/crowdsec/config.yaml to another port, for example 127.0.0.1:8081, set the same URL in /etc/crowdsec/local_api_credentials.yaml, update api_url in /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml and restart both services.
A log file shows 0 lines read. Check that the path in the acquisition file exists and that the type label matches an installed parser. Run sudo journalctl -u crowdsec -n 50 to see acquisition errors.
You banned yourself. From the server console (or from another IP), run sudo cscli decisions delete --ip your_ip and add the address to the allowlist from Step 4.
Conclusion
You installed CrowdSec from the official repository, protected SSH and Nginx with Hub collections, allowlisted your administrative IPs, enforced decisions with the nftables firewall bouncer and verified a ban end to end. From here you can add collections for other services you expose (for example crowdsecurity/postfix or crowdsecurity/wordpress), send notifications on new alerts with CrowdSec's notification plugins, and enroll every server in the Console to watch them from one place.
