Skip to content
Sysadmin

Self-Hosting Security: Wazuh + CrowdSec on a VPS

Attackers automate their reconnaissance. The window between exposing a service and receiving the first probe is minutes, not days. My setup uses Wazuh as the SIEM backbone and CrowdSec as the active defence layer. They complement each other in ways that took me a while to understand.

What Wazuh actually does

Wazuh is a SIEM on top of OSSEC with a better dashboard and a more manageable rule engine. Lightweight agents run on each monitored host, collect log data and file integrity events, and ship everything to a central manager.

The two features I care about most:

File integrity monitoring. Define a list of paths — /etc/, /usr/bin/, whatever matters on your box — and Wazuh checksums them. Any change generates an alert. This catches both successful attackers and botched package updates.

Log analysis. The agent parses auth.log, syslog, and application logs against a rule set and alerts on things like SSH brute force clusters, repeated sudo failures, and privilege escalation attempts. When a rule fires above a threshold it can execute a script — the default for SSH brute force blocks the IP for a configurable window. Time-limited, not permanent, because permanent auto-blocks accumulate noise.

The manager with dashboard and indexer needs around 1–2 GB RAM on its own VPS. Don’t co-host it with your application on a small box.

What CrowdSec adds

Wazuh is reactive — it sees what’s happening on your machine. CrowdSec adds crowd-sourced threat intelligence.

When an attacker hits my SSH port, CrowdSec detects it, blocks the IP locally, and reports it to the CrowdSec community. Every other instance pulling the community blocklist gets that IP preemptively. A meaningful fraction of incoming attacks are blocked before the first packet reaches your application, because someone else already saw that IP.

The architecture is agent (detects, decides) plus bouncer (enforces). I run the firewall bouncer for everything — drops packets at the kernel level via nftables — and the Caddy bouncer for HTTP specifically, so blocked requests get a proper 403 rather than a silent drop.

Where they overlap and where they don’t

Both detect brute force. Both block source IPs. The overlap is intentional.

What Wazuh has that CrowdSec doesn’t: deep log context. It can alert on a sudo command at 3 AM from a user who’s never used sudo before. CrowdSec doesn’t have that.

What CrowdSec has that Wazuh doesn’t: the community feed. An IP that’s been scanning the internet for exposed Redis instances all week will arrive in your blocklist before it ever touches your server.

Running one and not the other leaves a gap.

Alert routing

If you send every alert to a notification channel, you’ll turn it off within a week. Route Wazuh level 12+ to immediate notification (Slack, whatever you’re watching). Level 7–11 to a daily digest. Everything below 7 to storage only — you’ll look at it for context when something higher fires.

CrowdSec is better reviewed as trends in its dashboard: how many decisions per day, which scenarios are firing, whether community blocklist coverage is growing. Not real-time alerts.

Docs: Wazuh, CrowdSec.

← All articles