How to Install CrowdSec on Ubuntu 24.04 — The Modern Alternative to Fail2Ban
Every public-facing Linux server is under constant attack — SSH brute force, WordPress login spam, scanner bots, credential stuffing — 24/7 against any IP answering on port 22 or 443. This guide walks you through installing CrowdSec on an Ubuntu 24.04 VPS: apt repo setup, community blocklist enrollment, nginx/Traefik bouncers, and the Layer 7 WAF shipped in 1.6+.
Skip the setup? Deploy a hardened VPS with security tooling pre-configured on the CloudCore Starter plan and start with a protected baseline.
Table of Contents
What is CrowdSec?
CrowdSec is an open-source, Go-based intrusion prevention system (IPS) built around two ideas Fail2Ban never had: crowd-sourced threat intelligence and a decoupled detect/enforce architecture. Think of it as an immune system for your fleet — every participating server reports malicious IPs, signals are aggregated and curated centrally, and every participant gets the resulting blocklist. One server being attacked benefits the whole community.
Internally, CrowdSec is two things. The agent (crowdsec service) reads logs from files, systemd-journald, Docker, or syslog, runs them through parsers that extract structured fields, and feeds the result into scenarios — leaky-bucket detectors that fire alerts when a pattern matches (for example, "more than 5 failed SSH logins from the same IP in 10 minutes"). Alerts become decisions stored in a local database. The agent itself does not block anything. That job belongs to the bouncers — small binaries or plugins that pull the decision list and enforce it at the right layer (iptables/nftables, nginx, Traefik, Cloudflare, CAPTCHA, or application middleware).
This separation is what makes CrowdSec composable: detect on one host and enforce on ten, share decisions fleet-wide via LAPI/PAPI, mix firewall bans for SSH scanners with nginx CAPTCHA for suspicious web clients — all driven by the same agent. CrowdSec 1.6+ also ships AppSec, a native Layer 7 WAF that loads OWASP Core Rule Set (CRS) rules and inspects HTTP traffic for injection, XSS, LFI, and CVE exploitation before it reaches your backend.
CrowdSec vs Fail2Ban
Fail2Ban still works for basic SSH brute-force protection, but the architectural gap compared to CrowdSec is wide:
| Feature | Fail2Ban | CrowdSec |
|---|---|---|
| Language / Runtime | Python, single-threaded | Go, concurrent, low footprint |
| Performance at scale | Slows on large logs, high-volume services | Streams logs, handles millions of events/day |
| IPv6 support | Partial, fragile regex handling | Native first-class IPv6 |
| systemd-journald | Workaround via backend | Native journald acquisition |
| Detection model | Regex + time window | Parsers + leaky-bucket scenarios + post-overflows |
| Community blocklist | None (each box is alone) | Crowd-sourced blocklist, curated, free tier |
| Management UI | None (log files + CLI) | Free web Console (fleet view, alerts, decisions) |
| Decoupled enforcement | No, iptables hardcoded | Yes, bouncers for iptables, nginx, Traefik, CF, CAPTCHA |
| Layer 7 WAF | No | AppSec component (OWASP CRS compatible) |
| Docker / Kubernetes | Awkward, host-coupled | First-class containers, Helm chart, k3s chart |
| Metrics | No | Prometheus endpoint out of the box |
| Configuration reuse | Copy-paste between hosts | Hub: versioned collections you install/update |
Prerequisites
Before you begin:
- A VPS running Ubuntu 24.04 LTS with root or sudo access
- SSH access
- At least 1 GB RAM (agent ~50 MB, AppSec adds ~100 MB)
- At least 2 GB free disk for the agent, hub content, and decisions DB
Recommended: CloudCore Starter — 4 vCPU, 6 GB RAM, 100 GB NVMe SSD, unmetered bandwidth. Enough to run the agent, AppSec, a couple of bouncers, and your web stack on one machine.
Connect to your server via SSH to get started:
ssh root@your-server-ipStep 1: Update System Packages
Refresh the package index and apply pending upgrades — a clean state avoids dependency surprises when the CrowdSec apt source is added.
sudo apt update && sudo apt upgrade -yIf the kernel was updated, reboot before continuing:
sudo rebootInstall helpers for later steps:
sudo apt install -y curl gnupg ca-certificates lsb-releaseStep 2: Add the CrowdSec Repository and Install
CrowdSec ships an official install script that detects your distribution, adds the apt repo, imports the signing key, and runs apt update. It does not install the agent itself — keeping the repo-add step idempotent.
Register the repository:
curl -s https://install.crowdsec.net | sudo bashExpected output (abbreviated):
Detected operating system as Ubuntu/24.04.
Checking for curl...
Importing CrowdSec GPG key...
Installing apt source for CrowdSec...
Running apt-get update...
The repository is setup! You can now install packages.Install the agent:
sudo apt install -y crowdsecThe post-install hook creates the crowdsec user, /etc/crowdsec/ config tree, LAPI credentials, the SQLite decisions DB, a default acquis.yaml that tails sshd via journald, and the crowdsec.service unit. Enable on boot:
sudo systemctl enable --now crowdsecStep 3: Verify the Service
Check the agent is healthy and LAPI reachable.
sudo systemctl status crowdsecExpected output:
● crowdsec.service - Crowdsec agent
Loaded: loaded (/lib/systemd/system/crowdsec.service; enabled; preset: enabled)
Active: active (running) since Wed 2026-04-16 10:00:00 UTC; 1min ago
Main PID: 1234 (crowdsec)
Tasks: 12 (limit: 14236)
Memory: 58.2MCheck the version and LAPI reachability:
cscli version
cscli lapi statusExpected output:
You can successfully interact with Local API (LAPI)Runtime metrics — the most useful diagnostic in CrowdSec:
sudo cscli metricsTables show acquisition (lines read per source), parsers (hits/misses), buckets (scenarios triggered), and LAPI. A fresh agent shows near-zero activity until log traffic flows.
Step 4: Update the Hub and Install Collections
The Hub is a versioned repository of parsers, scenarios, postoverflows, and collections (bundles of the three). Update it first:
sudo cscli hub update
sudo cscli hub upgradeExpected output:
Downloading .index.json...
Updated CrowdSec Hub index.
Nothing to upgrade.Install collections matching what runs on this host. Typical web VPS (SSH + nginx):
sudo cscli collections install crowdsecurity/linux
sudo cscli collections install crowdsecurity/sshd
sudo cscli collections install crowdsecurity/nginx
sudo cscli collections install crowdsecurity/base-http-scenarios
sudo cscli collections install crowdsecurity/http-cveWhat each does:
linux— basesyslog/journaldparsers plus generic Linux scenariossshd— parses sshd logs, detects brute force and user enumerationnginx— parses access/error logs in combined/main formatbase-http-scenarios— generic HTTP attacks (path traversal, scanners, bad bots, bruteforce)http-cve— pattern matches for publicly exploited CVEs
nginx for crowdsecurity/apache2. WordPress? Add crowdsecurity/wordpress. Traefik? crowdsecurity/traefik. Full catalog: cscli collections list -a.Then reload: sudo systemctl reload crowdsec.
Step 5: Configure Data Sources (Acquisitions)
Collections ship parsers and scenarios but don't tell the agent where to read logs. That mapping lives in /etc/crowdsec/acquis.yaml (plus optional files in /etc/crowdsec/acquis.d/). The default file already contains an sshd journald entry. Open it:
sudo nano /etc/crowdsec/acquis.yamlA complete example for a host running SSH, nginx, and WordPress:
# SSH via systemd-journald source: journalctl journalctl_filter: - "_SYSTEMD_UNIT=ssh.service" labels: type: syslognginx access + error logs
source: file filenames: - /var/log/nginx/access.log - /var/log/nginx/error.log labels: type: nginxWordPress application logs (if you export them)
source: file filenames: - /var/log/wordpress/debug.log labels: type: wordpressApache, if installed
source: file
filenames:
- /var/log/apache2/access.log
- /var/log/apache2/error.log
labels:
type: apache2
Each YAML document (--- separated) is one acquisition. labels.type is critical — parsers register against specific types. nginx logs tagged type: apache2 won't be matched by any parser.
Validate and reload:
sudo cscli config show
sudo systemctl reload crowdsec
sudo cscli metricsThe "Acquisition Metrics" table should show non-zero reads per source.
Step 6: Understand Parsers, Scenarios, and Decisions
Get this mental model right — every troubleshooting session comes back to it.
Parsers turn raw log lines into structured events. Failed password for invalid user admin from 203.0.113.10 becomes source_ip=203.0.113.10, user=admin, evt.meta.log_type=ssh_failed_auth. Parsers run in stages (s00-raw, s01-parse, s02-enrich) — extract, enrich with GeoIP, then pass to scenarios.
Scenarios are leaky-bucket detectors with a capacity, leak rate, and trigger. crowdsecurity/ssh-bf fires when 5 failed SSH logins from the same IP arrive within 10 minutes; the bucket overflow emits an alert.
Post-overflows run after the alert but before a decision lands in the DB — this is where whitelists drop alerts.
Decisions are the output ("ban 203.0.113.10 for 4h"), stored in the local SQLite DB and read by bouncers.
Inspection commands:
# List active decisions (bans)
sudo cscli decisions listList recent alerts (whether or not they led to a decision)
sudo cscli alerts listInspect a specific alert
sudo cscli alerts inspect 42Manually ban an IP for 24 hours
sudo cscli decisions add --ip 198.51.100.7 --duration 24h --reason "manual test"Unban an IP
sudo cscli decisions delete --ip 198.51.100.7List installed scenarios
sudo cscli scenarios listShow a scenario's YAML definition
sudo cscli scenarios inspect crowdsecurity/ssh-bfStep 7: Enroll the Console and Community Blocklist
The Console is a free web dashboard showing fleet-wide alerts, decisions, and scenario activity. The free tier also grants access to the Community Blocklist — curated IPs reported by the network, subscribed as extra decisions on top of your own detections.
Sign up at crowdsec.net/console, copy the enrollment key, and enroll this machine:
sudo cscli console enroll --name vps-server-01 <your-enrollment-key>Expected output:
INFO Enrolled instance vps-server-01
INFO Please log in to the Console and accept the enrollment.Accept the pending machine in the Console; metrics start streaming within seconds.
Community Blocklist
Subscribe to blocklists in the Console (Blocklists → Subscribe), then pull locally:
sudo cscli decisions list --origin listsDecisions from community lists appear with origin=lists and are respected by every bouncer automatically. The free tier blocks tens of thousands of known-bad IPs before they ever touch your services.
Privacy note: the Console receives alert metadata only (scenario name, source IP, timestamp, machine ID) — never log contents or application data. To run with zero telemetry, skip enrollment and work fully offline.
Step 8: Install Bouncers (the Enforcers)
The agent is watching and deciding — now you need something to actually block traffic. Each bouncer is a separate package with its own API key.
Firewall Bouncer (iptables / nftables)
The baseline every CrowdSec install should have. Pulls decisions from the LAPI and maintains an ipset or nftables set that drops banned traffic at L3/4.
sudo apt install -y crowdsec-firewall-bouncer-iptablesUbuntu 24.04 defaults to nftables; for the native nftables bouncer instead:
sudo apt install -y crowdsec-firewall-bouncer-nftablesThe installer registers the bouncer and writes its API key to /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml. Start it:
sudo systemctl enable --now crowdsec-firewall-bouncer
sudo systemctl status crowdsec-firewall-bouncerVerify the set is populated once a decision lands:
sudo ipset list crowdsec-blacklists
or, for nftables:
sudo nft list set inet crowdsec crowdsec-blacklistsNginx Bouncer
Runs inside nginx (via lua-nginx-module) and enforces decisions at Layer 7 — including serving a CAPTCHA page instead of a hard block, much nicer for legitimate users caught behind a shared IP.
sudo apt install -y crowdsec-nginx-bouncerThe installer prompts for which nginx sites to protect, writes config to /etc/crowdsec/bouncers/crowdsec-nginx-bouncer.conf, and drops an include into /etc/nginx/conf.d/. Test and reload:
sudo nginx -t && sudo systemctl reload nginxFor the full nginx setup underneath, see our nginx on Ubuntu 24.04 guide.
Traefik Bouncer
For Traefik (common in Docker/k3s), use the traefik-crowdsec-bouncer plugin. Static config:
experimental:
plugins:
crowdsec-bouncer:
moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin
version: v1.3.4Then a middleware in the dynamic config:
http:
middlewares:
crowdsec:
plugin:
crowdsec-bouncer:
enabled: true
crowdsecMode: live
crowdsecLapiHost: 127.0.0.1:8080
crowdsecLapiKey: <generated-with-cscli-bouncers-add>Generate the API key with sudo cscli bouncers add traefik-bouncer. For the reverse-proxy setup, see the Traefik install guide.
Cloudflare Turnstile CAPTCHA
For a softer response than an outright ban, both the nginx and Traefik bouncers support a captcha remediation mode backed by Cloudflare Turnstile. Medium-confidence scenarios challenge the visitor; only those who fail the CAPTCHA are fully banned. Enable it in the bouncer config with your Turnstile site key and secret — full walkthrough in the CrowdSec docs.
List Your Bouncers
sudo cscli bouncers listEach row is a separate enforcer pulling from the LAPI. Rotate with cscli bouncers delete <name>.
Step 9: Enable the AppSec Component (L7 WAF)
CrowdSec 1.6+ ships AppSec, a native HTTP inspection engine that loads OWASP Core Rule Set (CRS) rules plus CrowdSec's own virtual-patching rules, then returns per-request verdicts (allow / deny / captcha) over an HTTP protocol the nginx and Traefik bouncers speak natively.
Install the AppSec config and CRS ruleset:
sudo cscli appsec-configs install crowdsecurity/appsec-default
sudo cscli appsec-rules install crowdsecurity/crs
sudo cscli appsec-rules install crowdsecurity/vpatch-*Add an AppSec acquisition so the agent listens for bouncer inspection requests. Create /etc/crowdsec/acquis.d/appsec.yaml:
appsec_config: crowdsecurity/appsec-default
labels:
type: appsec
listen_addr: 127.0.0.1:7422
source: appsecReload:
sudo systemctl reload crowdsecPoint your nginx or Traefik bouncer at the AppSec endpoint (appsec_url: http://127.0.0.1:7422). Requests now pass through OWASP CRS and CrowdSec virtual patches before hitting your backend — catching SQLi, XSS, LFI, RCE, and CVE exploitation with no rule-writing required.
Step 10: Whitelists, Metrics, and Log Forwarding
Whitelisting Your Own IPs
Nothing hurts more than self-locking after a VPN reconnect. Whitelist trusted networks in /etc/crowdsec/parsers/s02-enrich/whitelists.yaml:
name: crowdsecurity/whitelists
description: "Whitelist office and home IPs"
whitelist:
reason: "trusted networks"
ip:
- "203.0.113.42"
cidr:
- "198.51.100.0/24"
- "192.168.0.0/16"Reload with sudo systemctl reload crowdsec. These ranges never generate a decision, even if a scenario matches. For a post-overflow whitelist (lets the alert through but cancels the ban), see /etc/crowdsec/postoverflows/s01-whitelist/.
Prometheus Metrics
The agent exposes Prometheus metrics on 127.0.0.1:6060/metrics by default. Add a scrape job to your Prometheus config:
scrape_configs:
- job_name: crowdsec
static_configs:
- targets: ["127.0.0.1:6060"]Useful series: cs_bucket_overflowed_total, cs_parser_hits_total, cs_appsec_reqs_total. Grafana dashboards are linked from the CrowdSec docs.
Log Forwarding
CrowdSec writes to /var/log/crowdsec.log and /var/log/crowdsec_api.log. Point Vector, Fluent Bit, or Loki Promtail at those paths for fleet-wide search.
Backups and Upgrades
What to Back Up
The only stateful directory is /var/lib/crowdsec/data/ — the SQLite decisions DB and GeoIP databases. Nightly cron:
sudo tar czf /var/backups/crowdsec-$(date +%F).tar.gz /var/lib/crowdsec/data /etc/crowdsecVersion /etc/crowdsec/ in git (minus local_api_credentials.yaml which holds a secret). /etc/crowdsec/hub/ content reinstalls from the Hub, so it doesn't need backup.
Upgrades
Upgrade via apt like any other package:
sudo apt update
sudo apt install --only-upgrade crowdsec crowdsec-firewall-bouncer-iptables crowdsec-nginx-bouncer
sudo cscli hub update
sudo cscli hub upgrade
sudo systemctl restart crowdsecMajor version jumps sometimes require config migrations — always read the release notes first.
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
cscli lapi status reports connection refused | Agent is down or LAPI bound to a different address | sudo systemctl status crowdsec; check api.server.listen_uri in /etc/crowdsec/config.yaml |
| Bouncer shows as registered but no IPs are blocked | Bouncer service not running, or no decisions to enforce yet | sudo systemctl status crowdsec-firewall-bouncer; sudo cscli decisions list — if empty, nothing to block |
| Scenarios are installed but never trigger | Acquisition not reading logs, or labels.type does not match the parser | sudo cscli metrics and check Acquisition reads > 0; verify type: in acquis.yaml matches what the parser expects |
cscli hub update fails with TLS error | System clock drift or missing CA bundle | sudo timedatectl set-ntp true; sudo apt install --reinstall ca-certificates |
| Overwhelmed scenarios / CPU spikes under attack | Leaky-bucket capacity too generous for traffic volume | Clone the scenario to /etc/crowdsec/scenarios/, lower capacity and increase leakspeed |
| False positives on legitimate users | No whitelist, or scenario too aggressive | Add network to whitelists parser; switch remediation from ban to captcha in the bouncer |
ipset: set not found after reboot | Firewall bouncer started before netfilter modules loaded | sudo systemctl edit crowdsec-firewall-bouncer and add After=network-online.target nftables.service |
| nginx bouncer returns 500s | Lua module missing or include path wrong | Confirm nginx -V shows --with-http_lua_module; reinstall crowdsec-nginx-bouncer |
| AppSec blocks nothing | Bouncer not pointed at AppSec endpoint | Set appsec_url: http://127.0.0.1:7422 in the nginx/Traefik bouncer config |
Viewing Logs
Primary live debug stream:
sudo journalctl -u crowdsec -fBouncers log separately (journalctl -u crowdsec-firewall-bouncer -f, or /var/log/crowdsec-nginx-bouncer.log).
When a scenario misbehaves, trace a single log line:
sudo cscli explain --log '203.0.113.10 - GET /wp-login.php HTTP/1.1 401' --type nginxcscli explain walks the log line through every parser and scenario and prints what happened — the fastest way to debug a detection you expected but didn't get.
FAQ
How is CrowdSec different from Fail2Ban in practice?
Fail2Ban is a regex engine that edits iptables — one host, no UI, every false positive is a local problem. CrowdSec is an event pipeline with structured parsers, leaky-bucket scenarios, a decision database, multiple enforcement plugins, a fleet-wide Console, and a shared community blocklist. For anything beyond "ban IP after 5 SSH failures," CrowdSec wins on every axis. For a single hobby box protecting only SSH, Fail2Ban still works — see our Fail2Ban guide.
Is CrowdSec really free?
The agent, bouncers, Hub, and AppSec are fully open source (MIT). The Console free tier covers fleet visibility, the community blocklist, and basic alerting — enough for almost every self-hosted VPS operator. Paid tiers add premium blocklists, longer retention, SIEM integrations, and enterprise support.
Does the Console send my logs to CrowdSec?
No. The Console receives alert metadata only — scenario name, source IP, timestamp, hashed machine ID. Your log lines never leave the server. For zero telemetry, skip Console enrollment; everything except the fleet UI and shared blocklists works locally.
Can I run CrowdSec in Docker or Kubernetes?
Yes, both are first-class. The crowdsecurity/crowdsec Docker image runs the agent and LAPI. For Kubernetes, the CrowdSec Helm chart deploys the agent as a DaemonSet plus a centralized LAPI; the same chart works on k3s (set storage class to local-path). The nginx-ingress bouncer integrates directly with ingress-nginx via a Lua plugin.
What about IPv6?
Native and fully supported everywhere — parsers, scenarios, decisions, the firewall bouncer (ip6tables and nftables inet family), and AppSec. Whitelist CIDRs can mix v4 and v6 freely.
How heavy is CrowdSec on a small VPS?
On a 4 vCPU / 6 GB box with SSH + nginx traffic, the agent idles around 50–80 MB RAM and under 1% CPU. AppSec adds 60–120 MB. The firewall bouncer is tiny (~10 MB). Negligible alongside your app stack.
Next Steps
Now that CrowdSec is watching and enforcing, natural follow-ups:
- Harden SSH further — combine CrowdSec with key-only auth, a non-default port, and a bastion. See our SSH hardening guide.
- Put a WAF-enabled reverse proxy in front — deploy nginx or Traefik with the matching CrowdSec bouncer and AppSec.
- Forward metrics to Grafana — scrape
/metricswith Prometheus and import the official CrowdSec dashboards. - Run a second agent on another host — enroll it into the same Console and share the LAPI. Decisions propagate fleet-wide via PAPI.
- Subscribe to premium blocklists — for high-value targets, paid blocklists (VPN/proxy, aggressive crawlers, CTI feeds) pay for themselves.
- Migrate off Fail2Ban entirely — once CrowdSec has been running clean for a week:
sudo systemctl disable --now fail2banand remove/etc/fail2ban/jail.local.
Get a Hardened VPS in Minutes>
The CloudCore Starter plan (4 vCPU, 6 GB RAM, 100 GB NVMe, unmetered 1 Gbps, EU GDPR-aligned) gives you a clean Ubuntu 24.04 baseline with headroom for CrowdSec, nginx/Traefik, AppSec, and your app stack on a single machine.>
Deploy a CloudCore Starter VPS now.