Introducing CrowdSec – an advanced, collaborative security solution that analyzes system activity, detects hostile behavior, and blocks malicious actors in real time. Unlike traditional tools, CrowdSec leverages community-driven threat intelligence (crowd-sourced IP reputation) on top of local behavior analysis to protect your website and server.
In this comprehensive guide, we will integrate CrowdSec into a WordPress LEMP environment, covering installation, configuration, how it works, maintenance, and potential caveats. We’ll focus on an Ubuntu-based setup (Debian/Ubuntu), with notes for other Linux distributions where applicable, and assume the reader has advanced familiarity with server administration.
Table of Contents
Understanding the CrowdSec Security Stack
Before diving into implementation, it’s important to understand CrowdSec’s architecture and how it secures your stack:
- CrowdSec Security Engine (Detection) – This is the core of CrowdSec, running on your server as an agent. It continuously monitors logs and events from various services (Nginx, SSH, WordPress, etc.) and uses scenarios (rulesets similar to intrusion detection patterns) to spot suspicious behavior. For example, CrowdSec can detect a brute-force attack on
wp-login.php
by observing multiple failed POST requests, or an IP scanning for vulnerable files. When a scenario is triggered, the engine generates an alert and a decision (e.g. “ban IP 203.0.113.45 for 4 hours”). CrowdSec comes with an extensive hub of pre-made scenarios – over 100 out-of-the-box – covering common attacks (SSH bruteforce, web scans) as well as virtual patches for many known CVEs (including WordPress-specific vulnerabilities). (In fact, CrowdSec’s library includes “virtual patch” rules inspired by the CISA KEV catalogue to detect exploitation attempts for dozens of vulnerabilities in web applications, WordPress plugins, etc.) - Remediation Components (Bouncers) – Detection alone is not enough; you need to block or mitigate the malicious traffic. CrowdSec employs bouncers – separate components that retrieve the decisions from the Security Engine’s local API and enforce them at various levels. There are bouncers for firewalls, web servers, CDN services, and applications. For instance, a firewall bouncer can drop packets from banned IPs at the Linux kernel level, an Nginx bouncer can serve a CAPTCHA or block page at the web server level, and a WordPress bouncer plugin can challenge or block the attacker at the application level. These bouncers ensure that once the engine flags an IP, subsequent requests from that IP are automatically remedied (blocked or challenged) according to your configured policy. We will cover several bouncers (firewall, Nginx, Cloudflare, WordPress) in this guide.
- CrowdSec Console and Threat Intelligence – By enrolling your CrowdSec engine with the CrowdSec Console (the cloud web console), you gain a centralized view and management of your security data. More importantly, you receive Community Blocklists – curated lists of known malicious IPs gathered from all CrowdSec users. CrowdSec’s philosophy is “Safer together,” meaning every participant contributes to a crowdsourced IP reputation database. If your WordPress server is enrolled and regularly contributing attack signals, it will automatically fetch a tailored blocklist of the top offending IPs targeting similar services (e.g. web servers and WordPress). This proactive blocking, updated in real-time, greatly reduces the chance of known bad actors ever reaching your site. (Free contributors get a Community Blocklist of ~15,000 IPs relevant to their setup, whereas non-contributors get a smaller “Lite” list.) The Console also allows managing multiple CrowdSec installations (engines) across various servers in one place, viewing aggregated alerts, and subscribing to additional blocklists or Attack Insights. We will show how to enroll your instance to the Console in a later section.
In summary, CrowdSec will act as an intelligent guardian for our WordPress LEMP stack: the Security Engine detects attacks by reading logs (e.g. Nginx access logs, auth logs, etc.), and bouncers block or deter those attacks automatically. All of this is reinforced by a community-driven reputation system to preempt threats. Now, let’s proceed with setting up the CrowdSec engine on our server.
Installing CrowdSec on Ubuntu/Debian (Security Engine Setup)
Our first step is to install the CrowdSec Security Engine on the Linux server. The official installation instructions for Linux are as follows (for Ubuntu/Debian systems):
Start detecting attacks by installing a Security Engine. Before installing the package, you might want to check the ports that will be used.
Downloading repository:
curl -s https://install.crowdsec.net | sudo sh
CrowdSec Installation (Debian/Ubuntu):
sudo apt install crowdsec
As shown above, CrowdSec provides a one-liner to download and configure its official package repository, after which we install the crowdsec
package via APT. On Ubuntu, this will install CrowdSec v1.x as a system daemon (typically running under crowdsec
user) along with its CLI (cscli
). By default, the service starts immediately and loads a base configuration.
Note: The installation script may auto-detect your system’s services and configure log file collection accordingly. It also opens a local REST API (localhost:8080
by default) for bouncers to query decisions. Make sure this local API port is firewalled from external access, as only your bouncers should communicate with it. Typically, the installer will restrict the API to localhost
. If you want to adjust the listening port or address, you can do so in /etc/crowdsec/config.yaml
(the default Local API listens on port 8080).

Since this guide focuses on Ubuntu, the above steps cover Debian/Ubuntu installation. For other Linux distributions (CentOS, Fedora, Amazon Linux, etc.) the process is slightly different – the one-line installer script will set up the appropriate repository, and you would use the system’s package manager (yum install crowdsec
on CentOS/RHEL, etc.) to install the agent. Refer to CrowdSec’s documentation for distro-specific details if you are not on Ubuntu. The supported platforms include EL7/EL8, OpenWrt, and even container/Cloud images, each with a tailored package. The core idea is the same: install the crowdsec
agent on the system you wish to protect.
After installation, verify that CrowdSec is running properly:
sudo systemctl status crowdsec
sudo cscli version # Shows the version and confirms connectivity to Local API
Also, check which log files CrowdSec is monitoring. You can list the currently enabled “collections” and “scenarios” with the CLI:
sudo cscli collections list # shows which collections (service-specific rule bundles) are installed
sudo cscli scenarios list # shows active detection scenarios
Out-of-the-box on a LEMP server, CrowdSec should have included common collections like crowdsecurity/base-http-scenarios
(for generic web attacks) and perhaps crowdsecurity/nginx
if Nginx was detected. However, to specifically cover WordPress-related attacks, it’s recommended to install the official WordPress collection from the CrowdSec Hub. This includes scenarios for WordPress brute force and malicious bots:
sudo cscli collections install crowdsecurity/wordpress
sudo systemctl reload crowdsec
The crowdsecurity/wordpress
collection will bring in scenarios such as “http-bf-wordpress_bf” (detects brute-force on wp-login.php
) and “http-wordpress_wpconfig” (detects probes for wp-config.php
backup files). As of CrowdSec v1.6+, there is also a dedicated scenario for XML-RPC abuse (which often is used for brute forcing or amplification attacks), sometimes named http-bf-wordpress_bf_xmlrpc
. If that is not included by default, you can install it individually with:
sudo cscli scenarios install crowdsecurity/http-bf-wordpress_bf_xmlrpc
sudo systemctl reload crowdsec
By ensuring these WordPress-specific scenarios are active, our CrowdSec engine will intelligently detect common WP attack patterns. Remember, the engine itself only detects and alerts – it won’t block anything on its own beyond generating decisions. Next, we will set up the remediation components to enforce those decisions and actually block malicious traffic.
Deploying Remediation Components (Blocking Malicious Traffic)
CrowdSec offers a range of bouncers to fit into different parts of your stack. You can mix and match multiple bouncers for layered defense. In this section, we will configure key remediation components suitable for a WordPress LEMP environment:
- Firewall Bouncer (System-Level) – Blocks bad IPs at the network/firewall level (iptables/nftables), dropping traffic before it even hits Nginx or PHP.
- Nginx Bouncer (Web Server Level) – Uses Nginx’s Lua module to intercept HTTP requests from banned IPs, serving a custom “blocked” or CAPTCHA page. This protects the web server and can present challenges instead of outright drops.
- WordPress Bouncer Plugin (Application Level) – A WordPress plugin that integrates CrowdSec protection into WordPress itself. It can block or CAPTCHA suspicious visitors within the application, useful for handling scenarios like behind CDN/proxies or providing user-friendly capchas.
- Cloudflare Bouncer (CDN Level) – If you use Cloudflare CDN, this bouncer syncs CrowdSec decisions to Cloudflare’s firewall, so bad actors are blocked at the edge network, never reaching your server.
- PHP Standalone Bouncer (Application Level) – (Optional) A generic PHP library that can auto-prepend to any PHP application to enforce CrowdSec decisions. We mention this for completeness, though the WordPress-specific plugin is usually preferred for WP sites.
Each of these plays a role in a comprehensive defense-in-depth strategy. For example, the firewall bouncer is extremely fast and efficient at dropping known bad IPs, while the WordPress plugin can present a CAPTCHA (“Are you human?”) for suspicious behavior, reducing false positives by not outright banning visitors who might be legitimate. It’s common (and recommended) to use the firewall bouncer plus one of the web-level bouncers together. We will now go through each component, how to install it on Ubuntu, and how it works.
Linux Firewall Bouncer (System-Level Blocking)
The CrowdSec Firewall Bouncer is a lightweight Go service that fetches new and existing decisions from the CrowdSec Local API and populates them into your system firewall (iptables or nftables)docs.crowdsec.net. In essence, it maintains IP sets of banned IP addresses, and inserts firewall rules to drop any packets from those addresses. This means attackers get blocked at the kernel level – their traffic is stopped before it can consume resources or reach your web server or WordPress.
Installation: On Ubuntu, the firewall bouncer is available via the CrowdSec repository. Depending on whether your system uses iptables or nftables as its backend, install the corresponding package:
# For iptables (legacy or ufw backend) on Debian/Ubuntu:
sudo apt install crowdsec-firewall-bouncer-iptables
# For nftables on Debian/Ubuntu:
sudo apt install crowdsec-firewall-bouncer-nftables
If you’re unsure which firewall backend is in use, run iptables -V
. If the output mentions nf_tables
, that means nftables is the underlying engine; otherwise iptables is being used. (Ubuntu 20.04 uses iptables by default, while Ubuntu 22.04 uses nftables under the hood with iptables-nft compatibility). You can also choose to use the ipset mode, but the managed iptables/nft modes are simpler for most cases.
Installing the package will place a config file (e.g. /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml
) and usually start the service. The bouncer needs to authenticate to the CrowdSec Local API – typically, the package post-installation script will prompt or automatically register an API key for it. If not, you might have to manually generate an API key and put it in the config. For example:
sudo cscli bouncers add firewall-bouncer
This will output an API key. Then edit the bouncer’s YAML config and insert the key (and the API URL if your LAPI isn’t on default localhost:8080). On Ubuntu, however, this step is often handled for you – the bouncer may register itself with the local CrowdSec during install (check the logs or /var/log/crowdsec-firewall-bouncer.log
).
Once running, the firewall bouncer will continuously pull decisions. Any IP that CrowdSec marks as “ban” is added to an ipset/nft set, and a firewall rule ensures traffic from that IP is dropped. Supported protocols include IPv4 and IPv6. The drop is immediate and affects all ports/protocols by default, though you can configure scope if needed. Because this works at a low level, it’s extremely fast and transparent – attackers will simply see their connections time out.
Tip: The firewall bouncer operates in “stream” mode (meaning it subscribes to live updates of decisions). It’s a good idea to keep this bouncer enabled at all times for baseline protection. If you use UFW on Ubuntu, note that UFW is a frontend for iptables – the CrowdSec bouncer will still function (it creates its own chains and rules). Just be mindful not to flush iptables/nft rules manually as that would remove the bouncer’s rules.
Why use it? The firewall layer blocker is important because it reduces load on your system – e.g., if a botnet is hitting your site with thousands of requests, once CrowdSec bans those IPs, the firewall will drop them so Nginx/PHP/MySQL won’t have to handle those requests at all. This bouncer has no concept of CAPTCHA or user interaction (it simply blocks traffic), so it’s often used in combination with application-level bouncers that can provide friendlier remediation to borderline cases. However, for obvious malicious sources (e.g. known attackers from the CrowdSec community blocklist), dropping at firewall is ideal.
Nginx Bouncer (Web Server Level WAF)
The CrowdSec Nginx Bouncer is a Lua module based integration that acts as a mini web application firewall inside Nginx. It uses Nginx’s access_by_lua
phase to check each client IP against the CrowdSec decisions list via the local API. If the IP is present with a ban decision, the Nginx bouncer can block the request – either by returning a custom “Forbidden” page or redirecting to a CAPTCHA challenge page (allowing the client to prove they are human). This means even before your WordPress application sees the request, Nginx can intercept and deter malicious clients.
Features: The Nginx bouncer supports two modes of operation:
- Live Mode: For each incoming HTTP request, it queries the CrowdSec Local API in real-time to see if the IP (or IP range, country, etc., as decisions can be of various scope) has an active ban. It then caches the result for a short time (to avoid excessive API calls for the same IP). Live mode ensures immediate enforcement even for new decisions, at the slight cost of an HTTP sub-request on first access by an IP.
- Stream Mode: The bouncer can also run in stream (a background loop) where it periodically pulls all new decisions from the API (e.g. every 10 seconds) and keeps an in-memory list. Then each request is just checked against this local list (very fast). Stream mode is more efficient for high-traffic sites, as it avoids per-request API calls. The trade-off is a brief delay (up to the pull interval) in applying new decisions.
The bouncer can enforce “ban” (block page) or “captcha” remediation, and supports IPv4, IPv6, and range or country-based rules. Under the hood it uses a CrowdSec Lua library and communicates with the CrowdSec API over HTTP. One thing it does not do is actually parse request payloads – its enforcing decisions made by the CrowdSec engine or fed by blocklists. (CrowdSec’s separate AppSec module can inspect HTTP requests for known attack patterns, but that is part of the detection engine, not the Nginx bouncer itself.)
Installation: The Nginx bouncer requires Nginx with Lua support. On Ubuntu, install the required packages first (if not already present):
sudo apt install nginx lua5.1 libnginx-mod-http-lua luarocks lua-cjson gettext-base
(The libnginx-mod-http-lua
provides Lua scripting in Nginx; lua-cjson
is for JSON parsing, etc. These are usually available on Ubuntu 20.04+; for Ubuntu 22.04, if you encounter issues with the Lua module, consult CrowdSec’s FAQ)
Next, install the bouncer package:
sudo apt install crowdsec-nginx-bouncer
This will install the Lua scripts and a default config file at /etc/crowdsec/bouncers/crowdsec-nginx-bouncer.conf
. It may also drop a sample Nginx configuration snippet (e.g. /etc/nginx/snippets/crowdsec.conf
or similar) that needs to be included in your Nginx site configuration. The installation script for the bouncer typically attempts to register the bouncer with CrowdSec automatically if the engine is local – meaning it will create an API key and put it in the config for you. You should verify the config file has the correct API URL (e.g. http://127.0.0.1:8080/
) and a bouncer API key. If not, you can generate one (cscli bouncers add nginx-bouncer
) and add it. The config also lets you set MODE
(live or stream) and choose the default behavior (ban or captcha) and various options like caching times.
After installation, include the CrowdSec bouncer in your Nginx configuration. Typically, you would add something like the following in your server block, before any WordPress PHP handling:
# Example Nginx config snippet to call CrowdSec bouncer (Lua)
access_by_lua_block {
crowdsec_conn = require "crowdsec.resty.bouncer":new()
local verdict = crowdsec_conn:allow(os.getenv("REMOTE_ADDR"))
if verdict ~= "allow" then
-- If banned, CrowdSec bouncer will serve the ban page or captcha
return ngx.exit(ngx.OK) -- (actual snippet from package may differ)
end
}
The exact snippet is provided by the package (it might be installed in /etc/nginx/sites-available/default
automatically if you allowed it). Ensure this Lua block runs for all requests (both HTML pages and API calls) you want protected. Reload Nginx after adding the configuration.
Now, the Nginx bouncer will intercept requests. If an IP is decided as malicious by CrowdSec, the client will get either a 403 Forbidden page or a CAPTCHA challenge, depending on the bouncer’s FALLBACK_REMEDIATION
and what type of decision CrowdSec issued. By default, the fallback is “ban” (block), but you can configure it to use CAPTCHA for certain cases (CrowdSec engine can specifically issue a captcha decision if configured, otherwise all bans are treated as ban). The CAPTCHA mechanism used by CrowdSec is a simple challenge page where the user has to click a button to prove they are legitimate; once solved, their IP gets a temporary trust so they can continue browsing. This is particularly useful to avoid blocking search engine crawlers or legitimate users who might trigger a heuristic (false positive). The CrowdSec WordPress plugin (discussed next) similarly offers a captcha feature – and in fact, uses the same underlying mechanism – but the Nginx bouncer can do it at the web server level for any site.
When to use Nginx bouncer: This component is great if you want to block at the Nginx level (perhaps you don’t want to rely solely on firewall, or you want CAPTCHA ability). It’s also useful if you are terminating SSL at Nginx and need to block abusive IPs in a multi-tenant environment where you might not have firewall access per site. However, note that using both Nginx bouncer and WordPress bouncer on the same site may be redundant – typically you’d choose one or the other for application-level blocking. Many users rely on firewall + WordPress plugin (for captcha) or firewall + Nginx bouncer. If you do enable all three (firewall, Nginx, WP plugin), keep in mind the order of enforcement: Firewall will drop traffic first (so Nginx/WP bouncers won’t even see truly banned IPs), then Nginx bouncer (for any that weren’t caught by firewall decisions, e.g. captcha decisions or if firewall bouncer isn’t used), and finally WP plugin as last line. Having multiple bouncers is not harmful – CrowdSec’s API allows any number of bouncers to pull decisions – but administratively, you might not need both Nginx and WP plugin doing similar jobs.
CrowdSec WordPress Plugin (Application-Level Protection)
For WordPress-specific integration, CrowdSec provides an official WordPress Bouncer plugin. This plugin brings CrowdSec’s protection into the WordPress application layer, allowing you to manage settings from the WP admin dashboard and presenting very user-friendly CAPTCHA or block pages that blend with your site’s design. The plugin essentially acts as a PHP bouncer: it queries the local CrowdSec engine for each visitor and decides whether to allow, block, or captcha them, leveraging CrowdSec’s threat intelligence and decisions.
What can the WP plugin do? According to the documentation, it enables you to “protect your WordPress site against malicious traffic using CrowdSec’s advanced threat detection and blocklist capabilities.” It can quickly block known bad actors (if you use the CrowdSec blocklist features) and provide real-time protection by connecting to your own CrowdSec engine. It offers a few modes of operation:
- Standalone blocklist mode: A mode where even if you don’t run a local engine, the plugin can use a curated blocklist of the top WordPress attackers (this requires a subscription or enrollment to CrowdSec’s Instant WP Blocklist service – beyond our scope here). This is for users who only want a quick IP blocklist.
- Local engine (Bouncer) mode: The plugin connects to your local CrowdSec Security Engine’s API and enforces whatever decisions your engine (and community blocklists) provide in real-time. This is our scenario – we have CrowdSec running on the server, so the plugin will function as a real-time bouncer.
- Console blocklist mode: If you have subscribed to blocklists via the CrowdSec Console, the plugin can fetch those directly via an API key, acting as a consumer of CrowdSec’s Cloud API. Again, this is an alternative for those not running the engine locally, and we won’t focus on it since we have the engine.
In our setup, the CrowdSec engine is the brain (detecting attacks in logs) and the WP plugin is one of the hands that blocks the attacker on the site front-end.
Installation of the plugin: Install it as you would any WordPress plugin:
- In your WP admin dashboard, go to Plugins -> Add New, search for “CrowdSec”. The plugin should show up (named CrowdSec – Security by CrowdSec or similar). Click Install Now, then Activate.
Alternatively, you can download it from the WordPress plugin repository and upload it or use WP-CLI (wp plugin install crowdsec --activate
). The version on the WP repository is kept in sync with CrowdSec’s releases.
Once activated, you’ll see a new CrowdSec menu in the WordPress dashboard (usually under Settings or in the main menu). The plugin will initially be in a not configured state until it can communicate with the CrowdSec engine. We need to do a one-time setup to connect it:
Configuration:
- Local API Connection: In the plugin settings page, find the Connection details section. Enter the URL to your CrowdSec Local API. If CrowdSec is on the same server, it might be
http://127.0.0.1:8080/
(port 8080 is default). If you have changed the port or if WordPress is on a different server from CrowdSec, adjust accordingly. You can use a localhost URL since WP PHP will reach out from the server to the CrowdSec API. The plugin supports using a Bouncer API key or mTLS (TLS certificates) for authentication. The simplest is the API key. - Bouncer API Key: We need to provide an API key to the plugin so it can query the CrowdSec engine. Use the command line on your server to generate a key for WordPress:
sudo cscli bouncers add wordpress-bouncer
This will output a long alphanumeric key. In the WP plugin settings, choose “Bouncer API key” as the auth method and paste this key into the field provided. (If you prefer TLS authentication, you’d have to copy the certificate and key files onto the webserver and configure paths in the plugin settings – an option for advanced scenarios, but generally the API key is fine and simpler.) - Test the connection: The WP plugin has a built-in diagnostics test where it will try to contact the CrowdSec API with the provided URL and key. Ensure that this test passes (it will confirm that the plugin can fetch decisions). If it fails, double-check that the CrowdSec local API is up and that no firewall is blocking localhost requests. Also verify the key is correct (typo-free) and has been added in CrowdSec (the
cscli bouncers list
command should show an entry for the WordPress bouncer). - “Public Website Only” setting: By default, the plugin might have an option “Protect public website only” enabled, meaning it will not apply to
/wp-admin
or logged-in users. For full security, you likely want to disable that option so that the wp-login page and admin area are also protected. Otherwise, an attacker could brute-force wp-login without hitting the plugin’s protection if that setting were left on. Most advanced users will prefer to protect the login page as well – just be aware that if you accidentally ban yourself and you’ve blocked wp-admin, you’d need to wait out the ban or remove it via CLI, so having CAPTCHA in place (see next) can be helpful. - Remediation preferences (Ban vs Captcha – “Flex Mode”): The CrowdSec WP plugin introduces a “Flex mode”, which essentially means never permanently block, only challenge. If Flex mode is on, the plugin will not fully ban any IP; in the worst case it will present a CAPTCHA to suspected bad actors. This is a safeguard against false positives locking out legitimate users. Many administrators enable Flex mode so that even if a user triggers a CrowdSec scenario (e.g. too many failed logins), they get a CAPTCHA page rather than being completely denied. You can configure this in the plugin settings (there may be a toggle for “ban IP” vs “captcha only”). If Flex mode is off, serious threats will get a block page (HTTP 403) and won’t be able to access the site at all until the ban expires. Decide based on your risk appetite – for most cases, using CAPTCHA as the maximum penalty (especially on a public website) strikes a good balance, ensuring “it is impossible to accidentally block access to your site to people who don’t deserve it”.
- Caching and Modes: Similar to the Nginx bouncer, the WP plugin can work in Live mode or Stream mode. Live mode (default) means on a new visitor’s first page load, the plugin calls the CrowdSec API immediately to check the IP, then caches the decision for that IP for a certain duration. This is fairly efficient for moderate traffic. If your site is very high traffic with many unique visitors, you might consider Stream mode: the plugin will periodically pull the ban list from CrowdSec in the background (via WP-Cron) so that checks are instantaneous without any real-time API calls on page load. To enable Stream mode, you usually tick an option in advanced settings and set up a cron schedule (the plugin will guide this). The documentation notes that stream mode can help if you have lots of simultaneous visitors, as it decouples the checking from the request serving. Additionally, the plugin supports using an external cache like Redis or Memcached to store decisions, which can improve performance further by not hitting PHP on every page view. For an advanced setup, enabling Redis cache for CrowdSec plugin responses can make the security checks virtually invisible in terms of latency.
- Customize block pages: The WP plugin outputs friendly HTML templates for banned or captcha pages. You can customize the colors, texts, and even language of these pages from the plugin settings. This way, if a user gets challenged, the page can look consistent with your site’s theme (the plugin by default tries to “blend into your design” with configurable style. Take a moment to adjust these if needed, especially if your audience is multilingual – you can present the messages in your users’ language, etc.
After configuration, test that everything works: try entering a known bad IP (if you have one) or intentionally trigger a scenario. For example, you can simulate multiple failed logins to see if CrowdSec issues a ban and if the plugin then blocks you with a captcha. Be careful doing this on a live site (perhaps try it on a staging copy) to avoid locking yourself out. If you do get banned, you can remove the ban by running sudo cscli decisions remove --ip <your_ip>
on the server, or via the Console if you have it (more on that soon).
When to use the WordPress plugin: The WP bouncer is particularly useful if:
- You are behind a reverse proxy or CDN (where blocking at the origin firewall might not be effective or possible for all traffic). The plugin will see the real visitor IP (assuming WordPress is configured with the correct
X-Forwarded-For
handling) and can block at the application level even if the request is proxied. Notably, if you cannot deploy a firewall bouncer (e.g. on a shared host) or an Nginx bouncer, the WP plugin provides an easy way to still block attackers. - You want to present CAPTCHA challenges instead of simply dropping connections. Only application-level bouncers (WordPress or PHP) can show captchas; network-level bouncers cannot.
- You prefer managing the security from WordPress admin. The plugin provides a GUI for configuration and even viewing some metrics (future versions may include a dashboard). This can be convenient.
However, as the forum discussion noted, blocking at PHP level means the request goes through Nginx and PHP, which is heavier than blocking earlier. For an advanced user, it often makes sense to block known bad actors at the firewall or Nginx level to save resources and reserve the WP plugin mainly for handling edge cases (like CAPTCHA for those not caught by firewall). The CrowdSec team recommends: “If you can block at firewall, do it. If you can’t (or don’t want to outright block and prefer captcha), use the WordPress bouncer.”. In practice, you might run the firewall bouncer and WP plugin together – the firewall will eliminate the worst offenders, and the WP plugin will challenge any that slip through or those coming via trusted proxies.
One more thing: if your WordPress site is behind a CDN or load balancer, configure the Trusted IPs/Ranges in the CrowdSec plugin settings. The plugin allows you to specify IP ranges that are proxies (e.g. Cloudflare IP ranges, or your load balancer’s IP), so that it knows to fetch the real client IP from the X-Forwarded-For
header for those requests. This is crucial; otherwise, the plugin might see all requests as coming from the proxy and not be able to identify individual visitors. CrowdSec’s Cloudflare bouncer (next topic) also emphasizes this: you must restore real IPs in your logs for CrowdSec detection to work properly.
Cloudflare Bouncer (Protecting at the CDN Edge)
If your WordPress is served through Cloudflare (a common scenario for performance and DDoS protection), you have another layer where CrowdSec can operate: the Cloudflare firewall. CrowdSec provides a Cloudflare bouncer which uses Cloudflare’s API to push IP addresses that should be blocked or challenged at the Cloudflare edge. This means malicious IPs can be stopped before they even hit your server – they’ll get blocked by Cloudflare’s network. This offloads the unwanted traffic away from your origin completely.
How it works: The Cloudflare bouncer runs on your server (or conceivably anywhere that can reach both CrowdSec API and Cloudflare API). It periodically checks CrowdSec decisions (much like other bouncers in stream mode) and updates Cloudflare Firewall rules or IP lists. It supports decisions of type IP, but also Country or ASN bans (CrowdSec can issue bans on a country level, and the bouncer will create Cloudflare rules to block those). It’s designed to handle multi-domain setups: you can configure multiple Cloudflare API tokens, covering multiple zones (domains) and even multiple Cloudflare user accounts if needed. Essentially, it automates the management of Cloudflare’s firewall IP lists based on CrowdSec.
Installation: The bouncer is available via apt:
sudo apt install crowdsec-cloudflare-bouncer
Important: This particular bouncer has undergone changes. The official note (as of latest docs) is that “this bouncer isn’t actively supported anymore, due to changes to Cloudflare’s API rate limitations”, and they recommend using the Cloudflare Workers bouncer instead. The Cloudflare Workers bouncer is a different approach where a Cloudflare Worker script checks requests against CrowdSec’s database (using a lightweight call or KV store). That setup can handle high volume without hitting API limits. However, for our purposes, we’ll briefly outline the classic Cloudflare bouncer which is easier to understand and set up initially:
After installing, you need to configure it with your Cloudflare credentials:
- Cloudflare API Token: Go to your Cloudflare dashboard and create an API Token with permissions to manage Firewall rules and IP Lists for your zone(s). Typically, you’ll grant “Account > Firewall Services: Edit” and “Zone > Firewall Rules: Edit” etc. You can also create separate tokens per site if you prefer. Once you have the token string(s), you will feed them to the bouncer.
- Configure bouncer: The package provides a command to generate a config file. For example:
sudo crowdsec-cloudflare-bouncer -g "<CLOUDFLARE_TOKEN_1>,<CLOUDFLARE_TOKEN_2>" -o /etc/crowdsec/bouncers/crowdsec-cloudflare-bouncer.yaml
This will create a YAML config including all accounts and zones accessible by those tokens (it uses Cloudflare’s API to list your zones). Alternatively, you can manually edit the config file – it needs to contain your Cloudflare API token(s), associated email or account ID, and the CrowdSec API credentials (LAPI url and key) if the bouncer is not on the same machine as the engine. By default, if running on the same server, it will use local API. - Setup Cloudflare structures: Run:
sudo crowdsec-cloudflare-bouncer -s
This step uses the Cloudflare API to create the necessary firewall IP Lists and add rules to an existing Cloudflare Firewall RuleSet. The bouncer typically creates two IP lists (one for ban decisions, one for captcha perhaps) and a firewall rule that says “if IP in ban list -> block; if IP in captcha list -> JS Challenge or Captcha” (depending on configuration). After running-s
(setup), these lists and rules are in place on your Cloudflare account. - Start the bouncer service:
sudo systemctl start crowdsec-cloudflare-bouncer
Now it will continuously synchronize decisions. Check its log for any errors (e.g. in/var/log/crowdsec-cloudflare-bouncer.log
).
With this running, whenever CrowdSec bans an IP, the Cloudflare bouncer will add that IP to Cloudflare’s blocklist (typically within a few seconds). The attacker will then be blocked at Cloudflare’s edge (receiving whatever response you configured – by default, Cloudflare will serve a blocking page or a Cloudflare CAPTCHA if set to challenge). This can greatly reduce traffic to your origin during an attack. Keep in mind Cloudflare’s API has rate limits (1,200 edits every 5 minutes on IP lists), so if you have an extremely high volume of bans, the bouncer might not keep up. The Worker-based approach mitigates this by not relying on frequent API calls.
Cloudflare Considerations: Make sure that your server is logging real visitor IPs rather than Cloudflare’s IPs. If you haven’t already, configure Nginx with Cloudflare’s IP ranges as trusted proxies (using real_ip_module
directives). This way, CrowdSec will see the actual client IP in Nginx logs to make correct decisions. If your logs only show Cloudflare IPs, CrowdSec would be banning Cloudflare’s proxies (which is wrong) – and the bouncer might then block those, effectively cutting off all traffic! So, proper real-ip configuration is a must. Cloudflare provides a guide on restoring visitor IPs (mod_cloudflare or Nginx set_real_ip_from
directives).
Additionally, if you enroll in CrowdSec Console, you can choose to use Cloudflare Worker mode from there which is a newer method. But using the above method, we have integrated Cloudflare directly.
PHP Standalone Bouncer (Alternative for PHP Applications)
Lastly, for completeness, CrowdSec has a PHP Standalone Bouncer library. This is essentially what the WordPress plugin is built on, but it can be used in any PHP website (custom apps, frameworks, etc.). It works by leveraging PHP’s auto_prepend_file
to include a script on every page load, which then checks the visitor’s IP against CrowdSec decisions and either allows the page to proceed, or halts execution to present a captcha/block page.
If you did not want to use the WordPress plugin for some reason (say you have other PHP apps on the same server or you prefer a global approach), you could use this library. Installation is done via Composer (composer require crowdsec/standalone-bouncer
or using their create-project command), and then configuring a settings.php
file with your CrowdSec API key, and updating PHP settings to auto-prepend the bounce.php
script for all requests. This is an advanced setup, and the WordPress plugin essentially automates and customizes this for WordPress specifically.
Since our focus is WordPress, we won’t detail the full process here. Just know that the standalone PHP bouncer provides similar capabilities – supporting ban and captcha decisions for IPs, ranges, or countries – across any PHP application. For an advanced user managing multiple PHP sites on one server, this could be a one-time setup to shield all of them, whereas the WordPress plugin is an easier per-site solution.
Enrolling CrowdSec Instances in the Console (Centralized Management)
Now that we have the CrowdSec engine and various bouncers running, it’s highly beneficial to connect your CrowdSec instance to the CrowdSec Console – a cloud-based dashboard and management interface. The Console (https://app.crowdsec.net) allows you to monitor alerts, approve or override decisions, manage blocklists, and handle multiple machines from one place. It also is the vehicle through which your server can receive the latest Community Blocklist feed and other threat intelligence.
Why use the Console? For advanced users with multiple servers or websites, the Console provides a single pane of glass to see what CrowdSec is catching across all your resources. You can see metrics like how many attacks were blocked, view detailed alert logs, and even get notifications. Moreover, through the Console you can subscribe to additional blocklists (such as a premium curated list of top offending IPs, or region-specific ban lists) and have those decisions automatically enforced by your CrowdSec engine. It’s not strictly required – CrowdSec can run entirely locally – but many features (like community blocklist beyond the Lite tier) require enrollment in the network.
Enrollment process: Enrolling is straightforward and one-time:
- Create a CrowdSec account on the Console (free). Go to app.crowdsec.net and sign up. Once logged in, you can organize your “machines” (security engines) under an organization (by default you’ll have one org, you can invite team members etc.).
- In the Console, navigate to Security Engines -> Engines (or an “Enroll new instance” section). There will be an option to Generate Enrollment Token. Click that – it will give you a unique command or token string.
- On your server, run the enrollment command. It usually looks like:
sudo cscli console enroll <ENROLL_TOKEN>
e.g.sudo cscli console enroll 0123456789abcdef
(replace with the actual token). This command will register your CrowdSec instance with the console using that token. If needed, you can add--name
to give the machine a friendly name, and--tags
if you want to tag it (useful if you manage many servers). - After running the command, go back to the Console web UI. You should see your engine appear, likely in a “Pending” state. Approve or accept it (the Console will have an “approve” button for the new engine). Once approved, your CrowdSec agent will sync with the console.
From this point on, your CrowdSec service will start sending encrypted, pseudonymized signals to the CrowdSec central API about attacks it observes, and in return, it will be eligible to receive the community blocklist appropriate for your setup. You can verify this by running sudo cscli decisions list --origin CAPI
on your server – after some minutes, you should see entries that came from CrowdSec’s blocklist (origin “CAPI” means Central API). The Console also shows which blocklists are active. Free users who contribute will automatically get the Community Blocklist (15k IP) feed. If an instance is not contributing (or newly enrolled), it might start with the smaller “Community Blocklist Lite” (3k IP) until it reports enough activity or if it’s a very low-traffic private server. In any case, enrollment ensures you’re leveraging the global IP reputation.
With multiple WordPress servers, repeat the enrollment for each – each will appear in the Console. You can grant each a name like “Website1-Prod” and “Website2-Dev” etc. The Console’s Engines page will list all, show their status (online/offline, version, last heartbeat), and allow you to drill down into their alerts. If you ever detect that a scenario is too aggressive, you could disable it via console or via cscli
on the machine. The console doesn’t yet push configuration (as of writing, you still configure via CLI), but it’s evolving.
Additionally, the Console provides a view of notifications – for example, if a new vulnerability is trending and CrowdSec adds a scenario for it, they might notify you. It also allows adding manual block or allow lists that can propagate to your instances. For example, you could manually blacklist a troublesome IP across all your sites using the console.
Finally, if you subscribe to CrowdSec’s premium Threat Intelligence or blocklists (for enterprise users), the Console is where that is managed. But even the free Community Blocklist is extremely valuable – essentially, you’re pre-blocking thousands of “known bad” IPs (spammers, botnet nodes, etc.) before they ever attack you. This significantly reduces noise and risk.
To summarize the flow, we have now: Our WordPress server runs CrowdSec Engine which detects attacks in real-time and also fetches community-sourced offender IPs. Our bouncers (firewall, Nginx, WP plugin, Cloudflare) all query the engine’s decisions. So an IP that attacked someone else yesterday might already be on our blocklist today (thanks to community data), and our bouncers will block them on sight – proactive protection. Meanwhile, if our site is attacked, our CrowdSec will ban the IP and share that knowledge to help others. The Console ties this together, giving us visibility and control across our defenses.
Maintenance and Best Practices
Deploying CrowdSec is not a “set and forget” entirely – you should apply regular maintenance and follow best practices to ensure the security stays effective and doesn’t inadvertently affect your legitimate users or operations. Here are some key considerations for maintaining a CrowdSec-protected WordPress LEMP stack:
- Regular Updates: Keep CrowdSec and its components up to date. The project is actively maintained, and updates often include new attack patterns, performance improvements, and bug fixes. Since we installed via apt, updating CrowdSec is as simple as running your system updates (
sudo apt update && sudo apt upgrade
). This will update the engine and any installed bouncers (firewall, nginx, etc.) to the latest available versions. New detection scenarios are frequently added in the Hub; to update those, runsudo cscli hub update
(to fetch the latest catalog) and thensudo cscli collections upgrade all
/sudo cscli scenarios upgrade all
to pull in updates for installed items. You can also update individual ones. Staying updated is crucial especially for the AppSec (virtual patching) rules, as they add coverage for newly disclosed vulnerabilities. - Monitor CrowdSec Alerts: Make it a habit to check CrowdSec’s alerts and decisions. You can do this via the Console’s dashboard or using CLI commands (
cscli alerts list
andcscli decisions list
). This will show you which IPs were banned and why (which scenario triggered). Reviewing these helps ensure that the system is catching what it should. If you notice frequent false positives (e.g., your own monitoring service’s IP keeps getting banned for making many requests), you might need to adjust things. - Tuning Scenarios and Profiles: CrowdSec’s detection is governed by YAML scenarios and a decision profile (in
/etc/crowdsec/profiles.yaml
). The default profile typically says “ban an IP for X duration on scenario trigger”. You can customize the ban durations or decide to use Captcha instead of ban for certain scenarios by editing the profile. For instance, you might configure that for “http-bf-wordpress_bf” (login bruteforce), the decision is a captcha challenge for 30 minutes rather than a hard ban. This would work in tandem with the WordPress/Nginx bouncers that support captcha. Adjusting these requires understanding the syntax, but it’s an advanced way to tailor CrowdSec to your risk tolerance. - Whitelisting Safe Actors: CrowdSec by default whitelists private IP ranges (RFC1918 LAN IPs) and some known local addresses, so it doesn’t ban internal services. If your WordPress site is regularly accessed by certain safe IPs (like your corporate office IP, or perhaps uptime monitoring services), you might consider whitelisting them to prevent any accidental bans. You can add entries to
/etc/crowdsec/whitelist.yaml
or usecscli decisions add -t whitelist -i <IP>
. For example, to whitelist Cloudflare proxy IPs (since Cloudflare will hit your origin from their datacenters), you might do that, though typically you wouldn’t ban Cloudflare IP if you configured real IP correctly. Whitelisting is also useful to ignore specific paths or patterns: e.g., if you have a script that legitimately makes many login attempts (unlikely, but for argument’s sake), you could whitelist that scenario for a given source. - Handling False Positives: If you ever find that CrowdSec banned a legitimate user (false positive), you should remove the ban (
cscli decisions delete --ip <IP>
or via Console “lift ban”). Then investigate why – check the alert to see which scenario triggered. It might be that the scenario’s thresholds are too low for your site’s normal activity. For instance, the default WordPress brute-force scenario might ban an IP after 5 failed logins in 10 seconds. If you have a scenario where a user might genuinely trigger that (maybe some API script), you might raise the threshold or disable that scenario. The “Flex mode” approach (captcha instead of ban) we discussed is a nice mitigation – it ensures even false positives can solve a captcha and continue, rather than being outright blocked. - Resource Usage: CrowdSec is pretty lightweight (comparable to fail2ban). However, if you are on a very small VPS, monitor CPU and memory. The agent will parse logs – which is usually fine, but if you have extremely high traffic, ensure the server can handle it. The bouncers (especially WP plugin) add slight overhead: e.g., the WP plugin in live mode introduces a small delay on first page load for a new IP (due to API check). Using stream mode and caching as noted can reduce that overhead significantly. The Nginx bouncer’s overhead is negligible in stream mode (just a hash table lookup per request). The firewall bouncer’s impact is also negligible (just normal iptables checks, which are very fast). So overall performance is usually not an issue but keep everything updated and test after major version upgrades.
- Backups and Recovery: Since CrowdSec directly interfaces with your firewall and your website, ensure you have a way to recover if something goes wrong. For example, if a misconfiguration caused your firewall to block all traffic (unlikely, but let’s say the bouncer was given a wrong instruction), know how to stop the bouncer service or flush rules via SSH console. It’s wise to keep SSH access whitelisted. Similarly, if the WordPress plugin malfunctioned (e.g., blocking everyone due to a configuration error), be ready to disable it by renaming the plugin folder via FTP/SSH. These are standard precautions whenever introducing a security layer.
- Logs and Visibility: CrowdSec logs to
/var/log/crowdsec.log
and each bouncer has its log. Keep an eye on these logs especially after initial setup. Look for errors such as inability to reach LAPI, or Cloudflare API errors, etc. They will help you troubleshoot. The WordPress plugin may log events in the WordPress debug log if enabled. The CrowdSec Console provides visibility as well, but local logs are the first line of debugging if something isn’t working. - Multiple Sites / Resources: If your server hosts multiple WordPress sites, you have two choices: either each site uses the same CrowdSec agent on the server (one agent can parse logs for all sites’ Nginx and one WP plugin can still query the same agent). Or, you could install the CrowdSec WP plugin on each site all pointing to the same local agent. This is a valid scenario – many sites, one engine. The engine will see combined traffic. This can be advantageous as it has a broader picture of attacks. Just ensure each plugin uses a unique bouncer API key (you can create multiple API keys for the same agent). The firewall and Nginx bouncers protect the whole server regardless of site.
- Edge cases – What CrowdSec won’t do: While CrowdSec is powerful, remember it’s mostly focused on the network/app attack behavior. It is not a malware scanner or code firewall. For example, it won’t stop an attacker from exploiting a vulnerability in a plugin if that exploit doesn’t manifest in logs or known patterns (though many common ones are covered by virtual patches). Continue to keep WordPress core and plugins updated – CrowdSec adds a layer of defense but is not a substitute for patching critical vulns. It will, however, likely detect and block the attacker after the fact (and possibly before they can do a second-stage payload) if an exploit attempt is noisy or repeats across the community.
- Community Contributions: As an advanced user, consider tuning your setup to contribute meaningful signals. CrowdSec has a concept of signal quality – avoid logging fake attacks just to get blocklist (the system will detect abuse). Instead, let it run genuinely. If you have additional logs (like perhaps a plugin that logs login failures to syslog, etc.), parse them with CrowdSec to enhance detection. The more you cover (mail server, SSH, etc.), the more you contribute and the more comprehensive your protection becomes.
By following these maintenance tips, you can ensure CrowdSec continues to protect your WordPress site effectively with minimal side effects. Many users run it in production and find that after the initial tuning, it operates quietly in the background, stepping into action only when needed.
By implementing CrowdSec on your WordPress LEMP server, you’ve added a powerful ally to your security arsenal – one that grows smarter with every attack stopped across the community. In today’s threat landscape, this collaborative approach can significantly harden your website’s defenses with relatively little overhead. Your WordPress site is now protected on multiple levels by CrowdSec’s “brain” and “muscles,” combining behavior analysis and crowd-sourced reputation to keep bad actors out and your online presence secure. Happy securing, and remember to keep an eye on those logs and updates – security is an ongoing journey, but with CrowdSec, you have a proven roadmap to follow.