{"id":166234,"date":"2026-04-15T00:28:03","date_gmt":"2026-04-14T21:28:03","guid":{"rendered":"https:\/\/computingforgeeks.com\/install-crowdsec-ubuntu-2604\/"},"modified":"2026-04-15T00:28:03","modified_gmt":"2026-04-14T21:28:03","slug":"install-crowdsec-ubuntu-2604","status":"publish","type":"post","link":"https:\/\/computingforgeeks.com\/install-crowdsec-ubuntu-2604\/","title":{"rendered":"Install CrowdSec on Ubuntu 26.04 (Fail2ban Alternative)"},"content":{"rendered":"<p>Fail2ban has been the default answer for &#8220;block brute-force attempts&#8221; on Linux servers for over a decade. It works, but it is a lonely tool. Every server bans in isolation, every ruleset is hand-maintained, and every attacker gets 100+ fresh IPs to burn through before anyone notices. CrowdSec flips that model. It parses the same logs Fail2ban does, but the decisions it makes feed into a global community blocklist shared across thousands of servers. Your server benefits from bans other servers already issued, and vice versa.<\/p>\n\n<p>This guide installs CrowdSec v1.7 on Ubuntu 26.04 LTS, enables the SSH brute-force collection, triggers a real attack to show detection in action, then deploys the nftables bouncer so offending IPs are dropped at the kernel layer. It also covers enrolling the engine in the free CrowdSec Console, subscribing to community blocklists, and the most useful <code>cscli<\/code> commands to keep in your terminal history. Every command below was run on a fresh Ubuntu 26.04 LTS VM with real output captured.<\/p>\n\n<p><em>Tested <strong>April 2026<\/strong> on Ubuntu 26.04 LTS (kernel 7.0.0-10-generic), CrowdSec v1.7.7, firewall bouncer v0.0.34 with nftables backend<\/em><\/p>\n\n<h2>How CrowdSec differs from Fail2ban<\/h2>\n\n<p>Both tools read logs and block IPs. The differences show up once traffic scales.<\/p>\n\n<table>\n<thead><tr><th>Aspect<\/th><th>Fail2ban<\/th><th>CrowdSec<\/th><\/tr><\/thead>\n<tbody>\n<tr><td>Detection<\/td><td>Regex on logs, per-host<\/td><td>YAML scenarios + leaky buckets, per-host<\/td><\/tr>\n<tr><td>Enforcement<\/td><td>Same process writes iptables rules<\/td><td>Separate <em>bouncers<\/em> consume decisions (firewall, Nginx, Cloudflare, etc.)<\/td><\/tr>\n<tr><td>Threat intel<\/td><td>Local only<\/td><td>Decisions optionally shared with central API, community blocklist pushed back<\/td><\/tr>\n<tr><td>Scenarios<\/td><td>Jails you write<\/td><td>Hub: 780+ scenarios maintained by community<\/td><\/tr>\n<tr><td>Language<\/td><td>Python<\/td><td>Go (lower RAM\/CPU, single binary)<\/td><\/tr>\n<tr><td>Firewall backend<\/td><td>iptables, nftables, firewalld<\/td><td>nftables, iptables, ipset, pf, Cloudflare, AWS WAF, many more<\/td><\/tr>\n<\/tbody>\n<\/table>\n\n<p>The split between detection (engine) and enforcement (bouncers) is the part that matters. You can run CrowdSec on a log aggregator that has no internet-facing traffic, and push decisions to bouncers on edge servers.<\/p>\n\n<h2>Prerequisites<\/h2>\n\n<ul>\n<li>Ubuntu 26.04 LTS, x86_64 or arm64, with root or sudo access<\/li>\n<li>Outbound HTTPS to <code>api.crowdsec.net<\/code> (for hub installs and community pull)<\/li>\n<li>At least 512 MB RAM (CrowdSec idles around 80 MB)<\/li>\n<li>nftables available (default on Ubuntu 26.04, no action needed)<\/li>\n<\/ul>\n\n<p>If you are coming from a stripped setup, sort out basic hardening first. See <a href=\"https:\/\/computingforgeeks.com\/ubuntu-2604-initial-server-setup\/\">initial server setup for Ubuntu 26.04 LTS<\/a> and the companion <a href=\"https:\/\/computingforgeeks.com\/harden-ubuntu-2604-server\/\">server hardening guide<\/a>.<\/p>\n\n<h2>Add the official CrowdSec repository<\/h2>\n\n<p>CrowdSec ships a one-shot script that adds their packagecloud repo and imports the signing key. It is safe to read before running, it does exactly what the docs say.<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>curl -s https:\/\/install.crowdsec.net | sudo sh<\/code><\/pre>\n\n\n<p>The script imports the GPG key to <code>\/etc\/apt\/keyrings\/crowdsec_crowdsec-archive-keyring.gpg<\/code> and writes <code>\/etc\/apt\/sources.list.d\/crowdsec_crowdsec.list<\/code>. Update the package index and pull the engine:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo apt update\nsudo apt install -y crowdsec<\/code><\/pre>\n\n\n<p>The post-install hook registers the local machine with the embedded Local API (LAPI), creates a machine ID, and starts the <code>crowdsec<\/code> service. It also installs a default collection based on what it detects in <code>\/var\/log<\/code>. On a fresh Ubuntu 26.04 box that means the <code>crowdsecurity\/linux<\/code> and <code>crowdsecurity\/sshd<\/code> collections.<\/p>\n\n<h2>Verify the install<\/h2>\n\n<p>Check the version and service state:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>cscli version\nsystemctl status crowdsec --no-pager<\/code><\/pre>\n\n\n<p>You should see version <strong>v1.7.7<\/strong> (or newer) and the service in <em>active (running)<\/em> state:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>version: v1.7.7-debian-pragmatic-amd64-027974f2\nCodename: alphaga\nBuildDate: 2026-03-30_14:47:55\nGoVersion: 1.25.8\nPlatform: linux<\/code><\/pre>\n\n\n<p>CrowdSec listens on two local ports by default: <strong>8080<\/strong> for the Local API (where bouncers and cscli talk to it) and <strong>6060<\/strong> for Prometheus metrics. Both bind to <code>127.0.0.1<\/code>. Confirm with ss:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo ss -tlnp | grep crowdsec<\/code><\/pre>\n\n\n<p>The output confirms the engine is bound locally:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>LISTEN 0 4096 127.0.0.1:8080 0.0.0.0:* users:((\"crowdsec\",pid=8988,fd=15))\nLISTEN 0 4096 127.0.0.1:6060 0.0.0.0:* users:((\"crowdsec\",pid=8988,fd=19))<\/code><\/pre>\n\n\n<p>CrowdSec does not need inbound ports open. Bouncers connect outbound to the LAPI, which is why it works fine behind firewalls and NAT.<\/p>\n\n<h2>Understand the moving parts<\/h2>\n\n<p>Before installing more pieces, it helps to know what you already have.<\/p>\n\n<ul>\n<li><strong>Engine \/ LAPI<\/strong>: the <code>crowdsec<\/code> process. Reads logs, applies parsers, runs scenarios, stores alerts and decisions in a local SQLite database, exposes the LAPI on port 8080.<\/li>\n<li><strong>Agent<\/strong>: the detection side of the engine. Same binary, same process. In multi-server setups the agent runs separately and ships alerts to a central LAPI.<\/li>\n<li><strong>cscli<\/strong>: the admin CLI. You will use this constantly.<\/li>\n<li><strong>Bouncers<\/strong>: separate programs that pull decisions from the LAPI and enforce them. nftables, Nginx, Traefik, Cloudflare, AWS WAF, many others.<\/li>\n<li><strong>Hub<\/strong>: the online catalog of parsers, scenarios, collections, and postoverflows at <code>hub.crowdsec.net<\/code>. cscli installs from the hub.<\/li>\n<\/ul>\n\n<p>The detection pipeline is: log line arrives, acquisition module reads it, parser turns it into a structured event, scenario counts events into a leaky bucket, when the bucket overflows an alert fires, the alert creates a decision, the decision is what bouncers enforce.<\/p>\n\n<h2>List installed collections<\/h2>\n\n<p>A collection is a bundle of parsers and scenarios for a given service. The sshd collection installed automatically because the installer detected <code>\/var\/log\/auth.log<\/code>.<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>cscli collections list<\/code><\/pre>\n\n\n<p>You should see the linux core plus sshd:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>NAME                                 \ud83d\udce6 STATUS   VERSION  LOCAL PATH\n---------------------------------------------------------------------\ncrowdsecurity\/linux                  \u2714\ufe0f  enabled  0.4      core linux support: syslog + geoip + ssh\ncrowdsecurity\/sshd                   \u2714\ufe0f  enabled  0.9      sshd support: parser and brute-force detection\ncrowdsecurity\/whitelist-good-actors  \u2714\ufe0f  enabled  0.3      whitelist for known-good scanners<\/code><\/pre>\n\n\n<p>If you run other services (Nginx, Apache, Postfix, MySQL), pull their collections now:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo cscli collections install crowdsecurity\/nginx\nsudo cscli collections install crowdsecurity\/base-http-scenarios\nsudo systemctl reload crowdsec<\/code><\/pre>\n\n\n<p>Reload is enough; a full restart is only needed when you change <code>\/etc\/crowdsec\/config.yaml<\/code>.<\/p>\n\n<h2>A note on the private IP whitelist<\/h2>\n\n<p>CrowdSec ships with <code>crowdsecurity\/whitelists<\/code> enabled, and it whitelists RFC1918 ranges (10\/8, 172.16\/12, 192.168\/16) plus localhost. That is the right default for production. If all your traffic comes from the internet, the whitelist does exactly what you want: it prevents friendly-fire bans from an office IP or a load balancer.<\/p>\n\n<p>For a lab demonstration where you want to trigger detection from a private subnet, temporarily narrow the whitelist in <code>\/etc\/crowdsec\/parsers\/s02-enrich\/whitelists.yaml<\/code>. Restore it before going to production. The file is a YAML list under <code>whitelist.cidr<\/code>.<\/p>\n\n<h2>Inspect runtime metrics<\/h2>\n\n<p>The <code>cscli metrics<\/code> command is your first stop when something does not look right. It shows what the engine is reading, parsing, and bucketing.<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>cscli metrics<\/code><\/pre>\n\n\n<p>Key sections to watch: <strong>Acquisition Metrics<\/strong> (files being tailed, lines read, lines parsed), <strong>Parser Metrics<\/strong> (which parsers are hitting), and <strong>Bucket Metrics<\/strong> (which scenarios are actively filling):<\/p>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" src=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/04\/wm-crowdsec-metrics-ubuntu-2604.png\" alt=\"CrowdSec metrics output on Ubuntu 26.04 showing acquisition, parser, and API metrics\" title=\"\"><\/figure>\n<\/div>\n\n<p>If <code>Lines parsed<\/code> is zero for a source you expect to parse, the collection is either missing or the log format does not match. For sshd on Ubuntu 26.04 this happens if systemd journal is the only log sink. Check that rsyslog is installed and writing to <code>\/var\/log\/auth.log<\/code>.<\/p>\n\n<h2>Trigger a real brute-force to see detection fire<\/h2>\n\n<p>From a second host on the network, run a batch of failed SSH logins against the CrowdSec server. Eight to ten attempts in under a minute is enough to overflow every sshd bucket:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>for i in 1 2 3 4 5 6 7 8 9 10; do\n  sshpass -p \"wrong${i}\" ssh -o StrictHostKeyChecking=no \\\n    -o PreferredAuthentications=password -o PubkeyAuthentication=no \\\n    -o ConnectTimeout=3 baduser${i}@10.0.1.50 true\ndone<\/code><\/pre>\n\n\n<p>Back on the CrowdSec server, list the alerts and decisions that fired. Three distinct scenarios should match: <code>ssh-bf<\/code> (classic brute force), <code>ssh-slow-bf<\/code> (slower-paced probing), and <code>ssh-bf_user-enum<\/code> (attacker cycling through usernames).<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>cscli alerts list\ncscli decisions list<\/code><\/pre>\n\n\n<p>The attacker IP now has three bans pending, each valid for four hours by default:<\/p>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" src=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/04\/wm-crowdsec-alerts-decisions-ubuntu-2604.png\" alt=\"CrowdSec alerts and decisions after an SSH brute-force attack from a test host\" title=\"\"><\/figure>\n<\/div>\n\n<p>At this point CrowdSec has <em>decided<\/em> to ban the IP, but nothing is actually dropping the packets. The engine does not touch iptables or nftables on its own. That is the bouncer&#8217;s job.<\/p>\n\n<h2>Install the nftables firewall bouncer<\/h2>\n\n<p>Ubuntu 26.04 uses nftables as the default packet filter, so the <code>crowdsec-firewall-bouncer-nftables<\/code> package is the right fit. There is an iptables variant if you have legacy rules you are not ready to migrate.<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo apt install -y crowdsec-firewall-bouncer-nftables<\/code><\/pre>\n\n\n<p>The post-install step tries to register the bouncer with the LAPI automatically. On some installs the API key is not substituted into the config and the service fails to start. If <code>systemctl status crowdsec-firewall-bouncer<\/code> shows <em>bouncer stream halted<\/em>, register manually:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>API_KEY=$(sudo cscli bouncers add cs-firewall-bouncer -o raw)\nsudo sed -i \"s|\\${API_KEY}|${API_KEY}|\" \/etc\/crowdsec\/bouncers\/crowdsec-firewall-bouncer.yaml\nsudo systemctl restart crowdsec-firewall-bouncer<\/code><\/pre>\n\n\n<p>Verify the bouncer is registered and actively pulling decisions:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo cscli bouncers list\nsudo systemctl status crowdsec-firewall-bouncer --no-pager<\/code><\/pre>\n\n\n<p>A healthy bouncer shows a recent <code>Last API pull<\/code> timestamp and a non-empty IP Address field:<\/p>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" src=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/04\/wm-crowdsec-bouncer-list-ubuntu-2604.png\" alt=\"cscli bouncers list and systemctl status for crowdsec-firewall-bouncer on Ubuntu 26.04\" title=\"\"><\/figure>\n<\/div>\n\n<h2>Confirm nftables is actually dropping traffic<\/h2>\n\n<p>The bouncer creates two tables, <code>ip crowdsec<\/code> for IPv4 and <code>ip6 crowdsec6<\/code> for IPv6. Each has a named set that bouncer populates from LAPI decisions.<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo nft list table ip crowdsec<\/code><\/pre>\n\n\n<p>Look for the offending IP in the <code>crowdsec-blacklists-crowdsec<\/code> set, and a non-zero <code>crowdsec-blacklists-crowdsec<\/code> counter showing packets have actually been dropped:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>table ip crowdsec {\n    counter processed {\n        packets 192 bytes 56295\n    }\n\n    counter crowdsec-blacklists-crowdsec {\n        packets 2 bytes 144\n    }\n\n    set crowdsec-blacklists-crowdsec {\n        type ipv4_addr\n        flags timeout\n        elements = { 10.0.1.75 timeout 3h58m51s expires 3h58m22s }\n    }\n\n    chain crowdsec-chain-input {\n        type filter hook input priority filter - 10; policy accept;\n        counter name \"processed\"\n        ip saddr @crowdsec-blacklists-crowdsec counter name \"crowdsec-blacklists-crowdsec\" drop\n    }\n}<\/code><\/pre>\n\n\n<p>Try to SSH again from the banned source. The connection should time out at the packet-filter layer, not just fail at the authentication layer. This is the visible difference between &#8220;CrowdSec knows you are bad&#8221; and &#8220;CrowdSec is actively blocking you.&#8221;<\/p>\n\n<h2>Unban and ban manually<\/h2>\n\n<p>To remove a decision (useful after accidentally banning yourself from an office IP):<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo cscli decisions delete --ip 10.0.1.75<\/code><\/pre>\n\n\n<p>To issue a manual ban, for example when your WAF caught something before CrowdSec did:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo cscli decisions add --ip 203.0.113.42 --duration 24h --reason \"manual ban, web WAF hit\"<\/code><\/pre>\n\n\n<p>Both changes propagate to bouncers within <code>update_frequency<\/code> seconds (10 by default).<\/p>\n\n<h2>Enroll in the CrowdSec Console<\/h2>\n\n<p>The Console is a free web dashboard at <a href=\"https:\/\/app.crowdsec.net\" target=\"_blank\" rel=\"noreferrer noopener\">app.crowdsec.net<\/a>. It gives you per-engine alert history, a world map of attack sources, and access to community blocklists. It is optional, but the blocklists are genuinely useful.<\/p>\n\n<p>Create an account, then on the &#8220;Engines&#8221; page generate an enrollment key. Back on the server:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo cscli console enroll YOUR_ENROLL_KEY\nsudo systemctl restart crowdsec<\/code><\/pre>\n\n\n<p>After restart, click &#8220;Accept&#8221; next to the pending engine in the Console UI. Within a minute the engine starts shipping anonymized alert metadata and pulling subscribed blocklists.<\/p>\n\n<h2>Subscribe to the community blocklist<\/h2>\n\n<p>The real value of the Console free tier is the CrowdSec Community Blocklist (CTI), a list of IPs reported by the whole CrowdSec network within the last few hours. Enable it from the Console under &#8220;Blocklists&#8221; -> &#8220;Free blocklists&#8221; -> &#8220;CrowdSec Community Blocklist&#8221; -> subscribe. Within seconds the engine pulls tens of thousands of IPs and the firewall bouncer installs them into the nftables set:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo cscli decisions list --origins lists | head -20\nsudo nft list set ip crowdsec crowdsec-blacklists-crowdsec | head -10<\/code><\/pre>\n\n\n<p>Most of those IPs have been attacking other servers in the last few hours. Your server now drops them before they reach sshd or nginx.<\/p>\n\n<h2>The cscli commands you will actually use<\/h2>\n\n<p>After the initial setup, day-to-day CrowdSec work reduces to a handful of commands:<\/p>\n\n<table>\n<thead><tr><th>Command<\/th><th>Purpose<\/th><\/tr><\/thead>\n<tbody>\n<tr><td><code>cscli alerts list<\/code><\/td><td>Recent alerts, newest first<\/td><\/tr>\n<tr><td><code>cscli alerts inspect ID<\/code><\/td><td>Full event timeline for one alert<\/td><\/tr>\n<tr><td><code>cscli decisions list<\/code><\/td><td>Active bans right now<\/td><\/tr>\n<tr><td><code>cscli decisions delete --ip X.X.X.X<\/code><\/td><td>Unban an IP<\/td><\/tr>\n<tr><td><code>cscli decisions add --ip X.X.X.X --duration 24h<\/code><\/td><td>Manual ban<\/td><\/tr>\n<tr><td><code>cscli bouncers list<\/code><\/td><td>Health of each bouncer (last pull time)<\/td><\/tr>\n<tr><td><code>cscli collections list<\/code><\/td><td>Installed collections<\/td><\/tr>\n<tr><td><code>cscli hub update && cscli hub upgrade<\/code><\/td><td>Update hub index and upgrade installed items<\/td><\/tr>\n<tr><td><code>cscli metrics<\/code><\/td><td>Full runtime stats<\/td><\/tr>\n<tr><td><code>cscli explain --file \/var\/log\/auth.log<\/code><\/td><td>Dry-run what would have fired against a log file<\/td><\/tr>\n<\/tbody>\n<\/table>\n\n<p>The last one is gold when you are writing or tuning a scenario. Pipe a saved log sample through it and CrowdSec tells you what it would have done.<\/p>\n\n<h2>Troubleshooting<\/h2>\n\n<h3>Error: &#8220;bouncer stream halted&#8221;<\/h3>\n\n<p>This is the nftables bouncer failing to authenticate with LAPI. The cause is almost always an unsubstituted <code>${API_KEY}<\/code> in <code>\/etc\/crowdsec\/bouncers\/crowdsec-firewall-bouncer.yaml<\/code>. Register the bouncer with <code>cscli bouncers add<\/code>, paste the returned key into the config, restart the service.<\/p>\n\n<h3>Logs show &#8220;Lines parsed: 0&#8221; despite activity<\/h3>\n\n<p>The acquisition source is reading the file but no parser is matching. Ubuntu 26.04 minimal installs sometimes ship without rsyslog, which means <code>\/var\/log\/auth.log<\/code> does not exist. Install it:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo apt install -y rsyslog\nsudo systemctl enable --now rsyslog\nsudo systemctl reload crowdsec<\/code><\/pre>\n\n\n<p>Alternative: configure CrowdSec to read sshd events directly from the journal. Add a block to <code>\/etc\/crowdsec\/acquis.yaml<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>source: journalctl\njournalctl_filter:\n  - \"_SYSTEMD_UNIT=ssh.service\"\nlabels:\n  type: syslog<\/code><\/pre>\n\n\n<h3>Bouncer shows last pull &#8220;never&#8221;<\/h3>\n\n<p>The bouncer is installed but not reaching the LAPI. Check <code>journalctl -u crowdsec-firewall-bouncer -n 50<\/code>. If you see connection refused to 127.0.0.1:8080, the engine is not listening. Confirm with <code>ss -tlnp | grep 8080<\/code>. If the engine is up and the bouncer still cannot pull, the API key in the bouncer config does not match any registered bouncer. Regenerate with <code>cscli bouncers delete NAME<\/code> followed by <code>cscli bouncers add NAME<\/code>.<\/p>\n\n<h3>Bans issued but nothing dropped<\/h3>\n\n<p>The bouncer is pulling decisions but the nftables set is empty. This happens when another firewall tool (ufw with an aggressive ruleset, Docker reloading iptables) flushes CrowdSec&#8217;s chains. Either add CrowdSec&#8217;s tables to the managed set, or bump its hook priority in <code>\/etc\/crowdsec\/bouncers\/crowdsec-firewall-bouncer.yaml<\/code>. A priority of <code>-100<\/code> puts CrowdSec before most things.<\/p>\n\n<h2>Running both CrowdSec and Fail2ban<\/h2>\n\n<p>You can, but there is no good reason to. They will happily issue duplicate bans against the same logs. Pick one. If the server already runs Fail2ban and you do not want to migrate immediately, disable the sshd jail in Fail2ban before enabling the equivalent CrowdSec collection, otherwise you will burn CPU on two parsers analysing the same file. For a separate guide on the Fail2ban side, see the upcoming Fail2ban on Ubuntu 26.04 walkthrough.<\/p>\n\n<h2>Integrations worth setting up next<\/h2>\n\n<p>Now that the engine and firewall bouncer are in place, a few additions turn CrowdSec into a proper layered defense:<\/p>\n\n<ul>\n<li><strong>Nginx bouncer<\/strong>: if the server runs a web stack (see <a href=\"https:\/\/computingforgeeks.com\/install-nginx-ubuntu-2604-lets-encrypt\/\">Nginx with Let&#8217;s Encrypt on Ubuntu 26.04<\/a>), install <code>crowdsec-nginx-bouncer<\/code> to block malicious requests before they hit your app<\/li>\n<li><strong>UFW coexistence<\/strong>: if you rely on <a href=\"https:\/\/computingforgeeks.com\/configure-ufw-firewall-ubuntu-2604\/\">UFW for baseline rules<\/a>, CrowdSec&#8217;s bouncer runs alongside it without conflict because both target nftables at different priorities<\/li>\n<li><strong>WireGuard-only admin<\/strong>: reduce attack surface further by requiring <a href=\"https:\/\/computingforgeeks.com\/install-wireguard-ubuntu-2604\/\">WireGuard VPN<\/a> for SSH, so CrowdSec only sees scan noise hitting the public surface<\/li>\n<li><strong>Appsec component<\/strong>: CrowdSec 1.7 ships with an Application Security component that sits in front of web apps and applies WAF-style rules pulled from the hub. Worth a second article of its own.<\/li>\n<\/ul>\n\n<p>For broader context on what Ubuntu 26.04 brings to the table, the <a href=\"https:\/\/computingforgeeks.com\/ubuntu-2604-lts-features\/\">Ubuntu 26.04 LTS features overview<\/a> covers the kernel, systemd, and packaging changes you will run into while building this stack.<\/p>\n\n<p>At this point the server detects, decides, and drops SSH brute force with per-IP bans, shares signal with the community, and pulls known-bad IPs from a continuously-updated blocklist. That is a meaningful upgrade over a Fail2ban jail file, for roughly the same operational effort.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Fail2ban has been the default answer for &#8220;block brute-force attempts&#8221; on Linux servers for over a decade. It works, but it is a lonely tool. Every server bans in isolation, every ruleset is hand-maintained, and every attacker gets 100+ fresh IPs to burn through before anyone notices. CrowdSec flips that model. It parses the same &#8230; <a title=\"Install CrowdSec on Ubuntu 26.04 (Fail2ban Alternative)\" class=\"read-more\" href=\"https:\/\/computingforgeeks.com\/install-crowdsec-ubuntu-2604\/\" aria-label=\"Read more about Install CrowdSec on Ubuntu 26.04 (Fail2ban Alternative)\">Read more<\/a><\/p>\n","protected":false},"author":7,"featured_media":166233,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[50,75,81],"tags":[39820,35656,282,205,2254,39816],"cfg_series":[39802],"class_list":["post-166234","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-linux-tutorials","category-security","category-ubuntu","tag-crowdsec","tag-fail2ban","tag-linux","tag-security","tag-ubuntu","tag-ubuntu-26-04","cfg_series-ubuntu-2604-security"],"_links":{"self":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts\/166234","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/comments?post=166234"}],"version-history":[{"count":0,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts\/166234\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/media\/166233"}],"wp:attachment":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/media?parent=166234"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/categories?post=166234"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/tags?post=166234"},{"taxonomy":"cfg_series","embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/cfg_series?post=166234"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}