Threat Detection 11 min read
SIEM for Homelab: Wazuh vs Graylog Performance Comparison
Deploy and benchmark Wazuh and Graylog SIEM solutions in your homelab. Performance analysis, resource usage, and integration patterns for security monitoring.
Security monitoring needs centralized log analysis. I deployed both Wazuh and Graylog in my homelab to compare performance, resource usage, and detection capabilities. Wazuh excelled at threat detection (it caught all five test scenarios out of the box, and was quicker than Graylog on the two attacks both tools caught), Graylog dominated log search speed.
Here’s how to choose and deploy the right SIEM for your homelab.
one eye, all the logs
The Homelab SIEM Problem
Distributed logs across 47 services make security monitoring impossible. Firewall blocks attack at 14:32, IDS flags suspicious traffic at 14:35, application crashes at 14:38. Are these related? Manual correlation takes 45 minutes. You need SIEM.
What SIEM solves:
- Centralized visibility: All logs in one place (firewall, IDS, application, system)
- Correlation: “SSH brute force + successful login + sudo su” = potential compromise
- Alerting: Real-time notifications for security events
- Investigation: Query logs from the last 30 days quickly
Why homelab SIEMs different from enterprise: Resource constraints (8-64GB RAM vs enterprise 256GB+), complexity tolerance (manual setup OK), cost sensitivity (free open source only).
Options compared: Wazuh (security-focused), Graylog (log management-focused), ELK Stack (not tested - resource intensive), Splunk (not free).
Architecture: Wazuh vs Graylog
Both use agent-based collection, centralized storage, and web UI. Architectures differ in focus.
Wazuh architecture:
Graylog architecture:
Key differences:
| Feature | Wazuh | Graylog |
|---|---|---|
| Log collection | Wazuh agent (C binary) | Filebeat/Logstash/Syslog |
| Storage backend | OpenSearch/Elasticsearch | Elasticsearch + MongoDB |
| Primary focus | Threat detection | Log aggregation |
| Built-in rules | 4,400+ security rules | Basic extraction rules |
| Alert correlation | Event-driven | Stream-based |
Homelab Deployment: Both SIEMs Side-by-Side
I deployed both SIEMs in parallel to compare real-world performance. Infrastructure: Proxmox cluster, 3 VMs (16GB RAM each), Ubuntu 24.04.
Wazuh deployment (Docker Compose)
# Host prerequisite: the indexer needs at least 262,144 memory-mapped areas
# (persist it in /etc/sysctl.conf)
sudo sysctl -w vm.max_map_count=262144
# Official single-node stack (Wazuh 4.9 Docker documentation)
git clone https://github.com/wazuh/wazuh-docker.git -b v4.9.2
cd wazuh-docker/single-node
# Generate the self-signed certificates the stack expects
docker-compose -f generate-indexer-certs.yml run --rm generator
# Deploy stack
docker-compose up -d
# Verify deployment
docker-compose ps
# -k because the lab certificate is self-signed; SecretPassword is the shipped
# default -- change it. A 401 body has no cluster_name, so bad credentials fail here.
curl -sk -u admin:SecretPassword https://localhost:9200/ | grep -q cluster_name && echo "indexer up"
Correction (October 2026): an earlier version of this block downloaded
https://packages.wazuh.com/4.9/docker-compose.yml with curl -sO. That URL
answers 403 with an XML AccessDenied body, and without --fail curl saves the
error as docker-compose.yml and exits 0. The block now follows the
Wazuh 4.9 Docker deployment guide.
It also exported WAZUH_MANAGER_RAM and WAZUH_INDEXER_RAM, which the
v4.9.2 single-node compose file
never reads; the indexer heap is set there by OPENSEARCH_JAVA_OPTS. The
vm.max_map_count prerequisite comes from Wazuh’s
Docker installation requirements,
and the health check now looks for cluster_name in the indexer’s response
instead of trusting curl’s exit status, which is 0 on a 401 too.
Wazuh components:
- Wazuh Manager: Log processing, rule engine, alerting
- Wazuh Indexer: OpenSearch cluster (3 nodes in production, 1 for homelab)
- Wazuh Dashboard: Kibana fork for visualization
Graylog deployment (Docker Compose)
# MongoDB for metadata
docker run -d --name mongodb mongo:6.0
# Elasticsearch for log storage
docker run -d --name elasticsearch \
-e "discovery.type=single-node" \
-e "ES_JAVA_OPTS=-Xms2g -Xmx2g" \
docker.elastic.co/elasticsearch/elasticsearch:8.11.0
# Graylog server
docker run -d --name graylog \
-e "GRAYLOG_ROOT_PASSWORD_SHA2=$(echo -n password | shasum -a 256 | cut -d' ' -f1)" \
-e "GRAYLOG_HTTP_EXTERNAL_URI=http://localhost:9000/" \
-e "GRAYLOG_ELASTICSEARCH_HOSTS=http://elasticsearch:9200" \
-e "GRAYLOG_MONGODB_URI=mongodb://mongodb:27017/graylog" \
-p 9000:9000 \
graylog/graylog:5.2
Complete deployment scripts: https://gist.github.com/williamzujkowski/79146ef623363155e85d244a91c383cf
Agent deployment (both)
- 47 homelab hosts monitored (Docker containers, VMs, physical servers)
- Wazuh agents: Installed via package manager (
apt-get install wazuh-agent) - Filebeat agents: Configured for Graylog syslog input
Deployment time: Wazuh took longer (manager + indexer + dashboard + 47 agents) than Graylog (server + MongoDB + Elasticsearch + 47 Filebeat agents). I did not keep the timings, so I won’t quote minutes.
Performance Benchmark: Detection Speed
I simulated 5 common attack patterns to measure detection speed.
Test scenarios:
- SSH brute force: 50 failed login attempts in 60 seconds
- Port scan: Nmap SYN scan of 1,000 ports
- Web attack: SQL injection attempts (20 requests)
- Privilege escalation: Unauthorized sudo command
- File integrity: Modify /etc/passwd
Detection results (I did not retain the per-scenario timings from these runs, so the table shows coverage rather than seconds):
| Attack Type | Wazuh | Graylog* |
|---|---|---|
| SSH brute force | Detected | Detected, slower than Wazuh |
| Port scan | Detected | N/A (no built-in rule) |
| SQL injection | Detected | N/A (requires custom rule) |
| Privilege escalation | Detected | Detected, slower than Wazuh |
| File integrity | Detected | N/A (no FIM capability) |
| Scenarios caught | 5 of 5 | 2 of 5 |
*Graylog detection via custom stream rules. No packaged security detection content in Graylog Open — the aggregation event processor does correlation, but curated rules and the Correlation Engine sit behind Enterprise.
Why Wazuh faster: Built-in correlation rules trigger on pattern match. Graylog requires manual stream creation and alert conditions.
Alert accuracy:
- Wazuh false positives: fewer, though it flagged legitimate SSH retries as brute force
- Graylog false positives: more (stream rules less sophisticated)
I did not retain the false-positive counts, so I won’t quote rates.
Winner (detection): Wazuh excels at security-specific use cases with minimal configuration.
Performance Benchmark: Log Search Speed
Query performance matters when investigating incidents.
Test queries:
- Simple keyword: Search “error” in last 24 hours
- Field filter: Find all SSH events (
program:sshd) in last 7 days - Time range: Load all events from 14:00-15:00 yesterday
- Aggregation: Count events by source IP, last 30 days
- Complex: Multi-field correlation (source IP + failed auth + 10 minute window)
Query speed results: Graylog (Elasticsearch) was faster than Wazuh (OpenSearch) across the query types I tried. I did not retain the per-query timings, so I won’t quote seconds.
Data volume: a week of retention across 47 hosts logging.
Why Graylog faster: Elasticsearch-first design optimizes for search speed. Wazuh adds security processing overhead (rule evaluation, enrichment).
Winner (search): Graylog delivers clearly faster queries for log investigation workflows.
Resource Usage Comparison
Both SIEMs consume significant resources. Graylog lighter footprint.
Memory: the Wazuh stack used more RAM at steady state than Graylog. In both, the storage layer (Wazuh indexer, Elasticsearch) took the largest share, and Graylog adds a small MongoDB footprint on top.
CPU: during log ingestion the Wazuh manager used more CPU than the Graylog server.
Disk I/O: the Wazuh indexer sustained heavier writes than Elasticsearch under Graylog. MongoDB’s writes were small (metadata only).
Storage growth: Wazuh grew faster per day than Graylog across the 47 hosts.
I did not retain the measurements behind these comparisons, so I won’t quote numbers.
Winner (resources): Graylog uses less memory and less disk space.
Integration: Custom Python Automation
Both SIEMs expose REST APIs for automation. I built Python scripts to automate alert enrichment and response.
Wazuh API example (alert query):
import requests
from requests.auth import HTTPBasicAuth
WAZUH_API = "https://wazuh-manager:55000"
AUTH = HTTPBasicAuth(os.environ["WAZUH_USER"], os.environ["WAZUH_PASSWORD"])
# Query recent alerts
response = requests.get(
f"{WAZUH_API}/security/alerts",
auth=AUTH,
params={"limit": 100, "severity": "high"},
verify=True
)
alerts = response.json()["data"]
for alert in alerts:
print(f"[{alert['severity']}] {alert['rule']['description']}")
Graylog API example (stream query):
import requests
GRAYLOG_API = "http://graylog-server:9000/api"
TOKEN = "your_api_token_here"
# Query security stream
response = requests.get(
f"{GRAYLOG_API}/streams/stream_id/alerts",
headers={"Authorization": f"Bearer {TOKEN}"},
params={"limit": 100}
)
alerts = response.json()["alerts"]
for alert in alerts:
print(f"[{alert['condition_title']}] Triggered at {alert['triggered_at']}")
Automation built:
- Auto-remediation: Block IP addresses after 10 failed SSH attempts (firewall API integration)
- Enrichment: Query VirusTotal for file hashes in malware alerts
- Escalation: Create PagerDuty incident for critical alerts
- Reporting: Daily security summary (Slack notification)
API comparison:
| Feature | Wazuh API | Graylog API |
|---|---|---|
| Authentication | HTTP Basic | API tokens |
| Documentation | Good | Excellent |
| Response format | JSON | JSON |
| Rate limiting | 300 req/min | not documented |
Python integration examples: https://gist.github.com/williamzujkowski/4df107e30a0d2e5f5156df1d9203ca13
Security Detection: Built-In Rules vs Custom
Wazuh ships with 4,400+ security rules. Graylog requires custom stream creation.
Wazuh out-of-box detections:
- SSH brute force (8 failed attempts in 120 seconds, rule 5712’s shipped default)
- Web attacks (SQL injection, XSS, LFI patterns)
- File integrity monitoring (detects /etc, /bin changes)
- Privilege escalation (unauthorized sudo, su)
- Malware detection (ClamAV integration)
- Compliance (PCI-DSS, GDPR, HIPAA rule sets)
Graylog custom rule example (SSH brute force):
# Create stream: "Failed SSH Logins"
Field: program
Value: sshd
Condition: message matches "Failed password"
# Create alert:
Condition: message count > 10 in 2 minutes
Action: Send email notification
Detection coverage (my homelab):
| Detection Type | Wazuh (Built-in) | Graylog (Custom) |
|---|---|---|
| Brute force | ✅ Default rule | ⚠️ Manual stream |
| Port scanning | No host-based default rule; needs an IDS in the loop | Aggregation event definition in core |
| Web attacks | ✅ ~120 rules | ⚠️ Manual rules |
| File integrity | ✅ FIM module | ❌ Not supported |
| Malware | ✅ ClamAV integration | ❌ External only |
| Anomaly detection | ⚠️ Basic | Licensed content pack (Graylog Security) |
Winner (detection): Wazuh requires zero configuration for common threats. Graylog demands security expertise to replicate coverage.
Hybrid Deployment: Best of Both
Some teams run Wazuh + Graylog together. Wazuh handles threat detection, Graylog provides flexible log search.
Hybrid architecture:
Integration patterns:
- Wazuh → Graylog: Forward Wazuh alerts to Graylog for unified dashboard
- Graylog → Wazuh: Send suspicious events from Graylog to Wazuh for correlation
- Shared storage: Both write to same Elasticsearch cluster (resource optimization)
Real-world example: Use Wazuh for security monitoring (SSH, malware, FIM). Use Graylog for application logs (Django debug logs, Nginx access logs). Graylog’s stream processing creates custom alerts Wazuh doesn’t cover (business logic errors, API rate limiting).
Why hybrid works: Separate concerns (security vs operations), leverage strengths (Wazuh rules vs Graylog search).
Configuration: https://gist.github.com/williamzujkowski/c5ea53300957068928678f3f6927cab6
When to Choose Wazuh vs Graylog
Choose Wazuh if:
- Primary goal is security threat detection
- Need out-of-box coverage (brute force, malware, compliance)
- File integrity monitoring required
- Regulatory compliance matters (PCI-DSS, HIPAA)
- Limited security expertise (pre-built rules)
Choose Graylog if:
- Primary goal is centralized log aggregation
- Need fast log search and investigation
- Application debugging more important than security
- Custom log parsing and enrichment critical
- Resource constrained (Graylog lighter footprint)
My homelab choice: Started with Graylog (easier setup, faster search). Added Wazuh later for security-specific rules. Now run hybrid deployment.
Limitations and Trade-Offs
Wazuh challenges:
- Resource usage: Plan for a lot of RAM in production (Indexer memory hungry)
- Learning curve: Dashboard overwhelming (100+ pre-built visualizations)
- Alert noise: Default rules generate high false positive rate (tuning required)
Graylog challenges:
- Security rules: Manual creation time-consuming (building the streams took hours)
- No FIM: File integrity monitoring requires external tools (OSSEC, AIDE)
- Correlation limits: Stream-based correlation less powerful than Wazuh event engine
Common challenges (both):
- Retention costs: Storing 30 days of logs for 47 hosts takes substantial disk
- Agent deployment: Manual install on 47 hosts took hours (automation needed)
- **Tune
vs alert fatigue:** The first week was far noisier than after tuning.
Further Reading
SIEM comparisons and research:
- Comparative Analysis of Wazuh, Graylog, and ELK Stack - ICITST 2024 conference
- Wazuh vs Graylog: Which SIEM Tools Wins in 2025? - SelectHub analysis
Official documentation:
- Wazuh Documentation - Deployment, configuration, rule reference
- Graylog Documentation - Stream processing, extractors, alerts
- OpenSearch - Wazuh backend (Elasticsearch fork)
Deployment guides:
Alternative SIEMs (not tested):
- Elastic Security - Commercial ELK Stack with security
- Splunk Free - 500MB/day limit
- Security Onion - Network security monitoring platform
Implementation references:
- Deployment scripts: https://gist.github.com/williamzujkowski/79146ef623363155e85d244a91c383cf
- Python automation: https://gist.github.com/williamzujkowski/4df107e30a0d2e5f5156df1d9203ca13
- Hybrid configuration: https://gist.github.com/williamzujkowski/c5ea53300957068928678f3f6927cab6
Deploy centralized security monitoring. Start with one SIEM, validate detection coverage, then optimize. Most homelabs need Graylog’s search speed OR Wazuh’s security rules, not both.
Run hybrid if resources allow. Alert fatigue comes from poor tuning, not too many tools. In my homelab, SIEM caught a handful of real security incidents. Manual log review would have missed them.