Before we let an LLM make security decisions, we need to answer a harder question: what data do we actually send to it? Spoiler: not everything.
The Telemetry Problem: Garbage In, Hallucinations Out
Here’s the uncomfortable truth about running a SIEM in your homelab: most logs are noise. Your firewall drops 10,000 packets per hour from Chinese botnets probing port 22. Your DNS server logs every time.windows.com query. Your web server records 404s for /wp-admin.php from script kiddies who don’t know you’re running nginx.
If you pipe all of this into an LLM, you’ll accomplish three things:
- Burn through your GPU’s bandwidth
- Dilute the signal with noise (LLMs get distracted by irrelevant context)
- Generate responses like “This looks suspicious because there are many failed login attempts, but also it might be normal traffic, I’m 50% confident, good luck”
The solution: Filter at the source. Only send high-fidelity alerts to the AI.
This is what separates a functional autonomous SOC from a very expensive random number generator.
Wazuh Deployment: The All-in-One Install
Wazuh has three components:
- Wazuh Manager: Processes events, runs detection rules
- Wazuh Indexer: Stores logs (OpenSearch fork, basically Elasticsearch without the SSPL drama)
- Wazuh Dashboard: The web UI (Kibana fork)
For a homelab, we’ll run all three on a single VM. In production, you’d split these across servers, but we’re not paying bills here.
Installation Steps
SSH into your Wazuh VM (Ubuntu 26.04):
# Update system
sudo apt update && sudo apt upgrade -y
# Download and run the all-in-one installer
curl -sO https://packages.wazuh.com/4.8/wazuh-install.sh
chmod +x wazuh-install.sh
sudo ./wazuh-install.sh -a
# The script will output:
# - Dashboard URL: https://<wazuh-ip>
# - Admin credentials: admin / <random-password>
# SAVE THESE. You'll need them.
The installer takes about 10-15 minutes. It configures the manager, indexer, and dashboard, generates TLS certificates, and starts all services.
When it’s done:
# Verify services are running
sudo systemctl status wazuh-manager
sudo systemctl status wazuh-indexer
sudo systemctl status wazuh-dashboard
# Check open ports
sudo ss -tulnp | grep -E '1514|1515|9200|443'
You should see:
- 1514/UDP: Wazuh agent communication
- 1515/TCP: Wazuh agent enrollment
- 9200/TCP: Wazuh indexer API
- 443/TCP: Dashboard (HTTPS)
Access the dashboard at https://<wazuh-ip> and log in with the admin credentials.
Deploying Wazuh Agents: The Eyes on the Ground
Agents run on your endpoints (Windows, Linux, macOS) and send telemetry to the manager.
Linux Agent
On any Linux box you want to monitor:
# Download the agent
wget https://packages.wazuh.com/4.x/apt/pool/main/w/wazuh-agent/wazuh-agent_4.8.0-1_amd64.deb
# Install
sudo dpkg -i wazuh-agent_4.8.0-1_amd64.deb
# Configure the manager IP
sudo sed -i "s|<address>MANAGER_IP</address>|<address>192.168.1.11</address>|g" /var/ossec/etc/ossec.conf
# Enable and start
sudo systemctl enable wazuh-agent
sudo systemctl start wazuh-agent
# Verify it's connected
sudo /var/ossec/bin/agent-control -l
Windows Agent
- Download the MSI from Wazuh’s site
- Run the installer, specify the manager IP during setup
- The service starts automatically
Agent Configuration: What to Monitor
Edit /var/ossec/etc/ossec.conf on the agent (or push config from the manager):
<ossec_config>
<!-- Monitor /var/log for new entries -->
<localfile>
<log_format>syslog</log_format>
<location>/var/log/syslog</location>
</localfile>
<!-- Monitor authentication logs -->
<localfile>
<log_format>syslog</log_format>
<location>/var/log/auth.log</location>
</localfile>
<!-- File integrity monitoring on /etc -->
<syscheck>
<directories>/etc</directories>
<frequency>3600</frequency>
</syscheck>
<!-- Process monitoring (this is the good stuff) -->
<wodle name="syscollector">
<disabled>no</disabled>
<interval>1h</interval>
<network>yes</network>
<os>yes</os>
<processes>yes</processes>
<packages>yes</packages>
</wodle>
</ossec_config>
Restart the agent:
sudo systemctl restart wazuh-agent
Within 30 seconds, you’ll see events flowing into the Wazuh dashboard.
The Filtering Strategy: Signal vs. Noise
This is the critical part. Not every alert deserves AI analysis.
Level 1: Wazuh’s Built-In Rules
Wazuh ships with ~3,000 detection rules covering:
- Failed SSH logins
- Privilege escalation attempts
- Suspicious process execution
- File integrity changes
- Known CVE exploitation patterns
Each rule has a severity level (0-15):
- 0-4: Informational (ignored)
- 5-7: Low severity (log only)
- 8-11: Medium severity (alert, potential AI review)
- 12-15: High severity (alert + AI analysis + potential auto-response)
Our filtering logic:
- Severity < 8: Discard (or log to cold storage)
- Severity 8-11: Send to n8n, AI analyzes and recommends action
- Severity ≥ 12: Send to n8n, AI analyzes with priority flag
Level 2: Custom Rules for Homelab Threats
Wazuh’s default rules are great for enterprise threats. For homelab-specific detections, we write custom rules.
Example: Detect cryptocurrency miners (because your Proxmox host shouldn’t be mining Monero (or should it?)):
<group name="crypto,">
<rule id="100001" level="12">
<if_group>process_monitoring</if_group>
<match>xmrig|cpuminer|ethminer|phoenixminer</match>
<description>Cryptocurrency miner detected on $(hostname)</description>
<mitre>
<id>T1496</id> <!-- Resource Hijacking -->
</mitre>
</rule>
</group>
Save this to /var/ossec/etc/rules/local_rules.xml on the Wazuh manager, then:
sudo systemctl restart wazuh-manager
Now any process matching those strings triggers a severity-12 alert.
Level 3: Pre-AI Enrichment
Before sending an alert to the LLM, we enrich it with context. The more structured data the model has, the better its analysis.
Enrichment fields:
- Process tree: Parent/child relationships (is
curlbeing spawned bybashorsystemd?) - User context: Is this a service account or a human user?
- Network context: Source/destination IPs, geolocation
- File hashes: MD5/SHA256 for binary execution
- Threat intel: Check the hash against VirusTotal API (optional, but useful)
Wazuh can do some of this automatically via integrations. We’ll wire this up in n8n.
Routing to n8n: The Alert Pipeline
Wazuh can forward alerts to external systems via webhooks. We’ll configure it to POST JSON payloads to n8n.
Configure Wazuh Webhook Integration
Edit /var/ossec/etc/ossec.conf on the manager:
<integration>
<name>custom-webhook</name>
<hook_url>http://192.168.1.12:5678/webhook/wazuh-alerts</hook_url>
<level>8</level>
<alert_format>json</alert_format>
</integration>
This tells Wazuh: “For any alert with severity ≥ 8, POST the JSON to n8n.”
Restart the manager:
sudo systemctl restart wazuh-manager
n8n Deployment
SSH into your n8n VM:
# Install Docker (n8n runs best in a container)
sudo apt update
sudo apt install -y docker.io docker-compose
sudo systemctl enable docker
sudo systemctl start docker
# Create n8n directory
mkdir -p ~/n8n-data
# Run n8n
sudo docker run -d \
--name n8n \
-p 5678:5678 \
-v ~/n8n-data:/home/node/.n8n \
--restart unless-stopped \
n8nio/n8n
Access n8n at http://192.168.1.12:5678. Create an account (local auth, no cloud).
Create the Webhook Workflow
In n8n:
- Add a Webhook node:
- Method: POST
- Path:
wazuh-alerts - Response: “Alert received”
- Add a Function node (to parse the Wazuh JSON):
// Extract key fields from Wazuh alert
const alert = $json.body;
return {
alert_id: alert.id,
timestamp: alert.timestamp,
rule_id: alert.rule.id,
rule_description: alert.rule.description,
severity: alert.rule.level,
agent_name: alert.agent.name,
agent_ip: alert.agent.ip,
full_log: alert.full_log,
process_name: alert.data?.process?.name || "N/A",
process_cmdline: alert.data?.process?.cmdline || "N/A",
user: alert.data?.srcuser || "N/A"
};
- Add a Switch node (to route by severity):
- If
severity >= 12: Route to “High Priority” branch - If
severity 8-11: Route to “Medium Priority” branch - Else - rais an error flag in Telegram (should never happen but a good practice…)
- If
- For now, add HTTP Request nodes to POST to a test endpoint (we’ll replace these with Ollama calls in Part 3):
High Priority → POST to http://192.168.1.13:11434/api/generate (Ollama)
Medium Priority → POST to http://192.168.1.13:11434/api/generate (Ollama)
Activate the workflow. n8n will now listen for Wazuh alerts.
Testing the Pipeline: Generate Some Noise
Let’s trigger an alert and watch it flow through the pipeline.
On a monitored Linux host:
# Trigger a failed SSH login (Wazuh rule 5710, severity 5 - won't route to n8n)
ssh nonexistentuser@localhost
# Trigger multiple failed logins (Wazuh rule 5712, severity 10 - will route to n8n)
for i in {1..15}; do ssh nonexistentuser@localhost; done
# Trigger a high-severity alert: execute a suspicious binary name
cp /bin/ls /tmp/xmrig
/tmp/xmrig
Check the Wazuh dashboard: you should see alerts for the brute-force attempt and the “xmrig” execution.
Check n8n: you should see executions in the workflow log, with JSON payloads from Wazuh.
Why Not Send Everything to the AI?
Let’s do some napkin math.
Scenario: Your homelab generates 100,000 log entries per day.
- Wazuh’s rules reduce this to ~500 alerts.
- Of those, 50 are severity ≥ 8 (our AI analysis threshold).
- Each alert, when serialized with context, is ~2KB of JSON.
- Total daily payload to LLM: 100KB (manageable).
If you skipped filtering:
- 100,000 log entries × 1KB average = 100MB of logs per day.
- Llama-3 8B context window: 8,192 tokens (~32KB of text).
- You’d need to batch, summarize, or truncate. The model would miss critical patterns because it’s drowning in firewall drops.
Filtering is not optional. It’s the difference between “AI-assisted detection” and “expensive log shipper.”
The Data Flow Recap
Here’s what we’ve built:
Endpoint (Agent)
→ Wazuh Manager (Rule Evaluation)
→ Severity < 8: Discard
→ Severity ≥ 8: Enrich + Forward to n8n
→ n8n Webhook (Routing Logic)
→ High Priority: Ollama Analysis (Part 3)
→ Medium Priority: Ollama Analysis (Part 3)
What’s Next?
In Part 3: The Local AI Brain, we’ll:
- Configure Ollama on Proxmox with GPU pass-through
- Write system prompts that force structured JSON output with confidence scores
- Connect n8n to Ollama and parse the LLM’s responses
- Test the AI’s ability to analyze real process trees and command-line payloads
Key takeaway: The quality of your detections is upstream of the AI. If you’re feeding it garbage, no amount of prompt engineering will save you.
Building your own autonomous SOC? I’m on LinkedIn. Let me know what you’re using for telemetry—Wazuh, Elastic, something cursed like Splunk on a Raspberry Pi?
