Point a fresh VPS at the public internet and within minutes the logs fill with SSH password guesses, WordPress login probes, and scanners poking at paths you have never heard of. Fail2Ban handles a lot of this by watching one server's logs and banning noisy IPs. CrowdSec takes the same idea further: it parses logs against shared behavior scenarios, then blocks attackers through a separate firewall component - and it taps into a crowd-sourced blocklist so you benefit from IPs that already attacked thousands of other machines.
This guide is written for Ubuntu 22.04 and 24.04, but the packages work the same on Debian, and similar steps apply to Alma and Rocky. We will install the CrowdSec agent, add a firewall bouncer to actually drop traffic, install detection collections for SSH and Nginx, whitelist our own IP so we do not lock ourselves out, and test a real ban.
CrowdSec pairs nicely with the basics. If you have not already locked down SSH, start with our SSH hardening guide - key-only auth plus CrowdSec is a strong combination.
apt install crowdsec)crowdsec-firewall-bouncer-nftables) - this does the actual blockingcrowdsecurity/sshd, plus crowdsecurity/nginx if you run a web servercscli metrics, cscli alerts list, and cscli decisions listTotal time: about 20 minutes.
curl -4 ifconfig.me from your laptop)CrowdSec is light. The agent and a firewall bouncer together use well under 100 MB of RAM, so any small Linux plan is fine.
Start clean:
sudo apt update
sudo apt full-upgrade -y
sudo apt autoremove -y
Reboot if the kernel was upgraded:
sudo reboot
CrowdSec publishes an install script that adds its package repository and GPG key, then you install with apt as usual:
curl -s https://install.crowdsec.net | sudo sh
sudo apt install -y crowdsec
That one package installs the agent (which reads logs and runs scenarios) and the Local API (which stores decisions). On Ubuntu it auto-detects common log sources during setup, including /var/log/auth.log and journald, so SSH detection works out of the box.
Confirm it is running:
sudo systemctl status crowdsec
sudo cscli version
cscli is the command-line tool you will use for everything. Take a quick look at what got detected:
sudo cscli metrics
If the service is up and cscli metrics prints a table of acquisition sources and parsers, the agent is alive. It is watching, but not yet blocking.
This is the piece that turns detections into actual DROP rules. On Ubuntu 24.04 the firewall is nftables by default, so install the nftables bouncer:
sudo apt install -y crowdsec-firewall-bouncer-nftables
If your server still uses legacy iptables (some older 22.04 setups, or if you run UFW configured against iptables), install the iptables variant instead:
sudo apt install -y crowdsec-firewall-bouncer-iptables
The bouncer registers itself with the Local API automatically during install. Verify the link:
sudo cscli bouncers list
sudo systemctl status crowdsec-firewall-bouncer
You should see one bouncer listed with a valid API key and a recent "last pull" time. The bouncer creates its own nftables table (crowdsec) and continuously pulls the current ban list from the agent, so blocked IPs are dropped before they reach SSH, your web server, or anything else.
A note on UFW: the firewall bouncer works alongside UFW because it inserts its own table rather than editing UFW's rules. You do not need to disable UFW. Just make sure UFW is still allowing the ports you actually use.
Collections are bundles of parsers and scenarios for a given service. The SSH collection is the one everyone wants:
sudo cscli collections install crowdsecurity/sshd
If you run a web server, add the matching collection. For Nginx:
sudo cscli collections install crowdsecurity/nginx
For Apache:
sudo cscli collections install crowdsecurity/apache2
There are collections for many common stacks - WordPress, Caddy, Traefik, MariaDB, and more. Browse what is available with sudo cscli collections list -a and the hub at hub.crowdsec.net.
If you installed a web collection, tell CrowdSec where the access logs live. Edit the acquisition config:
sudo nano /etc/crowdsec/acquis.yaml
Add a block for Nginx (adjust the path if you use custom log locations):
---
filenames:
- /var/log/nginx/access.log
- /var/log/nginx/error.log
labels:
type: nginx
Reload the agent so it picks up the new collections and log sources:
sudo systemctl reload crowdsec
sudo cscli metrics
In the metrics output you should now see your new parsers and scenarios listed with read/parsed counts climbing as traffic comes in.
Before you test anything, protect yourself. CrowdSec scenarios can trip on your own behavior - a few mistyped SSH logins or a burst of requests during testing - and the bouncer will happily firewall you off at the network level.
Create a whitelist parser. CrowdSec applies whitelists early in the pipeline, so a whitelisted IP never generates a decision in the first place:
sudo nano /etc/crowdsec/parsers/s02-enrich/mywhitelists.yaml
Paste this, replacing the example IP with your own (you can list several, and CIDR ranges work too):
name: crowdsecurity/whitelists
description: "Whitelist trusted source IPs"
whitelist:
reason: "trusted admin IPs"
ip:
- "203.0.113.10"
cidr:
- "198.51.100.0/24"
Reload and confirm there are no parse errors:
sudo systemctl reload crowdsec
sudo cscli parsers list | grep -i whitelist
If your home IP is dynamic, consider whitelisting your VPN or Tailscale range instead, or simply rely on the second-session-plus-console safety net.
You do not need a real attacker to confirm the chain works end to end. Add a manual decision against a throwaway test IP (never your own):
sudo cscli decisions add --ip 192.0.2.123 --duration 4m --reason "manual test"
List active decisions:
sudo cscli decisions list
You should see your test IP with a ban action and a countdown. Now confirm the bouncer actually pushed it into the firewall:
sudo nft list table ip crowdsec 2>/dev/null | grep 192.0.2.123
(On an iptables setup, check sudo iptables -L -n | grep 192.0.2.123 instead.) Seeing the IP in the table proves the agent, Local API, and bouncer are all talking to each other. Clean up:
sudo cscli decisions delete --ip 192.0.2.123
To watch real activity once the box has been online a while:
sudo cscli alerts list
sudo cscli decisions list
After a day on the public internet, the alerts list usually has plenty of SSH brute-force entries, and the decisions list shows the IPs currently banned.
One of CrowdSec's best features is free. When the agent installs, it registers an anonymous machine with the Central API, and in return it pulls a curated blocklist of IPs that have aggressively attacked other CrowdSec users recently. These are blocked proactively, before they ever touch your server.
Check that the registration happened:
sudo cscli capi status
If it reports the machine is registered and can reach the API, you are already getting community decisions. You can see how many in the metrics output under the Central API / blocklist counters. No configuration needed - it just works, and the data shared back is limited to attack signals, not your traffic.
The command line covers everything, but the free hosted console at app.crowdsec.net gives you a dashboard, alert timelines, and the ability to manage multiple servers in one place. It is optional and separate from the community blocklist.
Sign up, create an account, and grab your enrollment key from the console. Then on the server:
sudo cscli console enroll YOUR_ENROLLMENT_KEY
sudo systemctl reload crowdsec
Accept the new instance in the web console and your server's alerts start flowing into the dashboard within a minute or two. From there you can also subscribe to additional curated blocklists.
To get notified when something is banned, wire CrowdSec notifications into a push channel - our self-hosted ntfy guide is a simple target for that.
CrowdSec's strength is its scenarios, and those get updated. Refresh the hub periodically (a weekly cron or unattended-upgrades-style schedule is plenty):
sudo cscli hub update
sudo cscli hub upgrade
sudo systemctl reload crowdsec
The Debian/Ubuntu package also updates via normal apt upgrade, so if you run unattended security upgrades the engine itself stays patched. The hub commands above keep the detection content fresh.
Attackers show up in cscli alerts but are never blocked. You skipped the bouncer, or it is not running. Check sudo cscli bouncers list and sudo systemctl status crowdsec-firewall-bouncer. No bouncer means no blocking.
cscli metrics shows zero lines parsed for SSH. The auth log path or backend was not detected. Confirm /var/log/auth.log exists and check /etc/crowdsec/acquis.yaml. On minimal images that log to journald only, make sure a journald source is present.
Bouncer installed but nft list table ip crowdsec is empty. The bouncer may be using a different backend than your firewall. If your system is nftables but you installed the iptables bouncer (or vice versa), remove it and install the matching package. Check the mode in /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml.
I locked myself out. Use your provider's web or VNC console to log in, then run sudo cscli decisions delete --ip YOUR_IP and add yourself to the whitelist parser from Step 5. Reload with sudo systemctl reload crowdsec.
cscli capi status reports an error. Outbound HTTPS to the Central API is blocked, or registration failed. Confirm the server can reach the internet on 443, then re-register with sudo cscli capi register and reload the agent.
CrowdSec is not a replacement for the fundamentals - key-only SSH, a firewall, and least privilege still come first. But layered on top, it turns the constant background noise of the internet into a quiet, self-updating wall, and it does it on a few megabytes of RAM.
Need a VPS to run CrowdSec on? Our Linux VPS plans ship with current Ubuntu images, fast NVMe storage, and a web console for the day you firewall yourself out. See the options.