Skip to main content
Cybersecurity & Hardening

CrowdSec Installation and Server Protection on Ubuntu

How I install CrowdSec on every fresh Ubuntu server: package repo, firewall bouncer, the collections worth running, and the console wiring that closes the loop.

Published Updated 9 min read

A fresh VPS without intrusion detection is a server flying blind. Your firewall blocks the ports nobody should reach, and that’s it. Everything that does land on port 22, 80, or 443, the SSH brute-force noise, the WordPress login probes, the scanners hammering wp-login.php and /.env, gets through to the application unchallenged. CrowdSec is the layer I install next on every server, right after the SSH-and-UFW baseline. It watches the logs, recognises attack patterns, and bans the offenders at the firewall before they get a second swing.

I’ve had CrowdSec catch a slow-distributed brute force from 600+ IPs on a client’s WordPress server within 48 hours of deployment. None of those IPs were noisy enough to trip a per-source rate limit. Together they hammered xmlrpc.php at a pace designed to slip under fail2ban’s radar. CrowdSec’s wordpress collection picked up the pattern, the firewall bouncer dropped them at iptables, and the auth log went quiet again. That’s the day the tool earned its place in my standard build.

This post is the install pass I run on every Ubuntu server: the apt repo, the agent, the firewall bouncer, the collections that pull their weight, and the console wiring that lets me see what’s happening across a fleet without SSHing into each host.

Why CrowdSec earns the slot over fail2ban

I ran fail2ban for years and it did the job for what it was: read logs, count failed logins, ban the IP. The trouble is everything outside that narrow definition. Slow brute-force where each IP only tries twice. Distributed attacks coming from a fresh /24 every minute. Layer-7 probes that don’t trigger an auth failure because they hit endpoints that don’t require auth. fail2ban sees none of that.

CrowdSec was built for the threat model that actually shows up in 2024 and beyond. A few things make the difference on a working server:

  • Behavioural scenarios beyond per-source counters. A scenario can fire on patterns across many IPs, on slow time windows, or on combinations of signals (a 404 storm followed by a successful login from the same range, for example).
  • Multi-layer enforcement. The same agent feeds bouncers at the firewall (iptables/nftables), at the web server (Nginx, Apache), at the app (WordPress, Traefik, Cloudflare), or at the CDN. You pick where to drop traffic based on the use case.
  • A community blocklist that’s actually useful. When a CrowdSec user anywhere on the network flags an IP as malicious, every other instance can refuse it on first contact. Your server skips the part where the bot has to attack you for you to know the bot is malicious.

What CrowdSec actually does on a single host

Two pieces work together. The agent (crowdsec) reads logs from configured datasources (auth.log, Nginx access logs, WordPress logs, anything you point it at), runs them through parsers and scenarios, and writes a “decision” against any offending IP. A decision is a record in the local SQLite database saying “this IP is banned for X minutes.”

A bouncer enforces that decision. Bouncers are separate processes that subscribe to the agent’s decision feed and apply the ban somewhere. The one I install on every host is the firewall bouncer. It writes iptables/nftables rules that drop banned IPs at the kernel.

Mental model: agent decides, bouncer enforces. One agent can feed many bouncers (firewall, Nginx, WordPress) all working off the same decision feed. On a single web server, the firewall bouncer alone covers the SSH layer; application-level bouncers come later for the layer-7 patterns you can’t reliably stop at L3.

Installing CrowdSec on Ubuntu or Debian

The install is three apt commands once the repo is configured. These steps follow the official CrowdSec install guide and apply to Debian and Ubuntu derivatives. For other distributions, check the CrowdSec docs.

Add the package repository

The CrowdSec team ships an apt repo via PackageCloud. Add it with the maintainer’s install script:

curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | sudo bash

The script registers the repo and runs apt update so the next install picks up the latest CrowdSec package. If you’re allergic to piping curl into bash (a fair instinct), download the script first, read it, then run it locally. It’s short.

Install the agent

sudo apt install crowdsec -y

This installs the agent and starts the systemd service. On first run it auto-detects services running on the host (sshd, Nginx, etc.) and pulls down the relevant default collections. You can check what got installed with sudo cscli collections list.

Install the firewall bouncer

sudo apt install crowdsec-firewall-bouncer-iptables -y

The bouncer is what actually drops traffic. Without it, the agent detects attacks and writes decisions but nothing gets enforced. The package auto-registers with the local agent and starts dropping traffic from any IP that picks up a decision, including the community blocklist on first sync.

Warning: If your server runs nftables natively rather than the iptables compatibility layer, install crowdsec-firewall-bouncer-nftables instead. The iptables bouncer on a pure nftables host looks like it works but won’t actually filter traffic. Check with sudo nft list ruleset.

Verify the agent is running:

sudo systemctl status crowdsec
sudo cscli metrics

If cscli metrics shows acquisition counts climbing as your access logs fill, the agent is reading logs as expected. If they’re stuck at zero, the usual cause is a non-standard log path the auto-detected acquisition file missed. Check /etc/crowdsec/acquis.yaml and adjust as needed.

Picking the right CrowdSec collections

Collections are bundles of parsers and scenarios for a specific service. You install only the ones that match what’s running on the host. Here’s what I install on a generic web server, and why each one is on the list:

sudo cscli collections install crowdsecurity/endlessh
sudo cscli collections install crowdsecurity/http-cve
sudo cscli collections install crowdsecurity/linux-lpe
sudo cscli collections install crowdsecurity/mariadb
sudo cscli collections install crowdsecurity/wordpress

A quick read on each:

  • endlessh: if you run the SSH tarpit on port 22 and move real SSH to a high port, this collection parses tarpit logs to flag persistent scanners.
  • http-cve: generic HTTP CVE patterns. Anything looking for /.env, /wp-config.php.bak, vulnerable plugin paths, or known exploit URLs gets matched here. I install it on every web server.
  • linux-lpe: local privilege escalation patterns from auth.log. Catches the rarer-but-loud cases where someone with shell access tries to escalate.
  • mariadb: only if you actually expose MariaDB to the network. On a server with MariaDB bound to localhost, skip it.
  • wordpress: only on hosts that actually run WordPress. The xmlrpc and login-bruteforce scenarios are the high-value parts.

You can browse the full catalogue at the CrowdSec hub. The rule I follow: if I can’t name what scenario in a collection is going to fire on this server, the collection doesn’t go on the server. Every parser adds startup time and a bit of memory; collections you don’t need just get in the way of reading the decisions log later.

After installing collections, restart the agent so it picks them up:

sudo systemctl restart crowdsec

Verify:

sudo cscli collections list
sudo cscli scenarios list

The scenarios list is the more interesting view. It shows every detection rule the agent is currently running and which collection pulled it in.

Hooking CrowdSec into the web console

The free CrowdSec console at app.crowdsec.net gives you a real-time dashboard across every instance you enrol. On a single server, it’s a nice-to-have. Across a fleet, it’s how I avoid SSHing into five servers to compare what they’re seeing.

To enrol an instance:

  1. Register an account at app.crowdsec.net.
  2. The console gives you a one-line cscli console enroll <token> command. Copy it and run it on the server.
  3. Approve the instance in the console UI.
  4. Restart CrowdSec so the console connection is fully wired:
sudo systemctl restart crowdsec

Warning: The restart is not optional. Skipping it means the console will show the instance as enrolled but no signal data will flow until the agent reloads its configuration. I’ve watched a junior engineer spend 20 minutes wondering why the dashboard was empty before checking whether the service had been restarted.

After the restart, the console populates with active alerts, decisions, top attacked services, and a map of where the traffic is coming from. The historical view is where the real value sits, you can pull up a 30-day trend and see whether attack patterns are climbing or stable.

What I deliberately don’t do with CrowdSec

A few things look tempting in the docs but I’ve learned to skip on agency-sized infrastructure:

  • Custom scenarios from scratch. The community scenarios cover the common cases. Writing your own is a time sink unless you have a genuinely unusual workload, and a badly-written scenario either misses attacks or false-positives your monitoring.
  • The Cloudflare bouncer in front of an already-Cloudflare-fronted site. If Cloudflare is filtering the traffic, the CrowdSec Cloudflare bouncer is redundant. Use the firewall bouncer on the origin instead and let Cloudflare’s L7 stack do its job.
  • Running CrowdSec on a host without the Linux server security baseline in place. CrowdSec is a layer, not a foundation. SSH keys, UFW, and a non-root sudo user come first.

What I do add on top of CrowdSec, depending on the workload: the WordPress integration for any site running WordPress, Nginx security hardening for the web server itself, and either Authentik or 2FAuth for the dashboards CrowdSec doesn’t reach.

For the broader picture of what each layer is doing in the stack, the comprehensive WordPress security guide walks through how CrowdSec fits with the application-layer rules, and the human element in cybersecurity defense post is the companion on why no amount of tooling beats a careful operator.

Closing the loop

The full CrowdSec install on a fresh Ubuntu server is roughly five minutes of typing: the apt repo, the agent, the firewall bouncer, the four or five collections that match the workload, and a console enrol. After that the server is no longer flying blind. It’s reading its own logs, matching them against community-maintained scenarios, and dropping attackers at the firewall before they reach the application.

The community blocklist alone is reason enough to pick it over any single-source IDS, and the multi-layer bouncer model is why it scales from one VPS to a fleet without changing tools. Get the SSH and UFW baseline right first, layer CrowdSec on top, and the day-to-day attack noise on a public-facing server drops to the point where you actually notice the rare event that matters.

Watch on YouTube

Video walkthrough

Prefer the screen-recording version of this guide? Watch it on YouTube — opens in a new tab so the player only loads when you ask for it.

Frequently Asked Questions

Want this handled, not just understood?

Reading the playbook is one thing. Running it on production at 2am is another. If you'd rather have me run it for you, the door is open.

Apply for Access