NetSec on a Budget: Build Your Own SOHO IDS
Intro
Network security is like flossing: everyone knows it’s important, but most skip it and hope for the best. In this guide, you'll see why you don't have to leave it to chance. We’ll walk through how to set up a home intrusion detection system (IDS) that captures, analyzes, and alerts you to network activity worth your attention.
As usual, find full scripts, prompts, and stories in the companion repository:
https://github.com/tyler-tee/SOHO-IDS-RELAY
Our toolkit includes:
- A managed switch for traffic mirroring.
- A mini-PC running Ubuntu for monitoring.
- Suricata for real-time detection.
- ELK for visualization.
- Tines and Slack for automated, actionable notifications.
All of this is built on free-tier solutions. We even dodge ELK’s paid features by offloading webhook functionality to Tines. Ready? Let’s dive in.
The Hardware: Mirrors and Monitoring
Mirroring Network Traffic
The backbone of this setup is a managed switch configured to mirror all network traffic to a single port. The make and model isn't as important as picking a managed/smart switch that allows you to do port mirroring.
We aren't concerned about QoS or other fanciness - We're solely focused on traffic capture for the time being.

Mini-PC Setup
Enter the mini-PC, our silent sentinel running Ubuntu 24.04.1. It needs two network interfaces: 1. A management interface for day-to-day access. 2. A monitoring interface for capturing mirrored traffic.
Here’s how we configured them using ip link:
# Enable the management interface and assign an IP
sudo ip link set enp0s3 up
sudo ip addr add 192.168.1.10/24 dev enp0s3
# Enable the monitoring interface and set it to promiscuous mode
sudo ip link set enp0s8 up
sudo ip link set enp0s8 promisc on
Promiscuous mode ensures the monitoring interface captures everything, while keeping management tasks isolated.
Real-Time Detection with Suricata
Suricata is the watchdog of this operation. It sniffs traffic, flags anomalies, and writes alerts to eve.json. Here’s how to get it up and running:
# Add the Suricata repository
sudo apt update
sudo apt install -y software-properties-common
sudo add-apt-repository ppa:oisf/suricata-stable
sudo apt update
# Install Suricata
sudo apt install -y suricata
Start Suricata on the monitoring interface (replace enp0s8 with yours):
sudo suricata -c /etc/suricata/suricata.yaml -i enp0s8
Next, configure Suricata to log JSON alerts:
outputs:
- eve-log:
enabled: yes
filetype: regular
filename: /var/log/suricata/eve.json
types:
- alert
Data Visualization with ELK
Raw logs are great for machines. Humans? Not so much. Enter the ELK stack (Elasticsearch, Logstash, Kibana). Technically, we’ll be using Filebeat in lieu of Logstash, as it’s simpler to set up and comes with pre-built dashboards. However, feel free to combine these solutions or omit one entirely based on your preferences.
Installing the ELK Stack
- Elasticsearch: Install Elasticsearch to act as the central data store for our logs:
bash
curl -fsSL https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.list
sudo apt update
sudo apt install -y elasticsearch
- Kibana: Install Kibana for visualizing and exploring data in Elasticsearch:
bash
sudo apt install -y kibana
- Filebeat: Filebeat will handle shipping Suricata logs to Elasticsearch:
bash
sudo apt install -y filebeat
sudo filebeat modules enable suricata
sudo filebeat setup -e
- Start Everything: Start Elasticsearch, Kibana, and Filebeat services:
bash
sudo systemctl start elasticsearch
sudo systemctl start kibana
sudo systemctl start filebeat
Acquainting Filebeat with Elasticsearch
Let's ensure Filebeat sends our Suricata logs directly to Elasticsearch: 1. Open the Filebeat configuration file:
bash
sudo nano /etc/filebeat/filebeat.yml
- Update the
output.elasticsearchsection to point to your Elasticsearch instance:
yaml
output.elasticsearch:
hosts: ["https://localhost:9200"] # Replace "localhost" with your Elasticsearch server's IP or hostname
- Update filebeat's suricata module (
/etc/filebeat/modules.d/suricata.yml) with the location of our eve output.
yaml
- module: suricata
eve:
enabled: true
var.paths: ["/var/log/suricata/eve.json"] # Confirm this location
- Test the connection:
bash
sudo filebeat test output
- Restart Filebeat to apply changes:
bash
sudo systemctl restart filebeat
Visualizing Data in Kibana
Once Filebeat is set up, navigate to the Kibana interface (usually accessible at https://<your-server-ip>:5601). Use Filebeat’s preloaded dashboards to start exploring Suricata logs.
Parsing Alerts with Python
Suricata alerts land in eve.json, but raw data is noisy. Our Python script, suricata_relay.py, sifts through the clutter, deduplicating alerts by signature, IPs, and ports.
Set it up like so:
# Clone the repository
git clone https://github.com/tyler-tee/SOHO-IDS-RELAY.git
cd SOHO-IDS-RELAY/scripts
cp ./suricata_relay.py /opt/suricata_relay/suricata_relay.py
In suricata_relay.py, make sure to replace the dummy webhook with one that works:
9 TINES_WEBHOOK_URL = 'https://your-tines-tenant.tines.com/path/secret'
Configure the relay script as a service:
sudo cp suricata_relay.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable suricata_relay
sudo systemctl start suricata_relay
Alerts are now cleaned, prepped, and sent for further processing.
Alerting with Tines and Slack
Tines acts as the glue that binds our detection system with actionable notifications. It processes Suricata alerts, refines them with an LLM (Large Language Model), and sends detailed, well-formatted updates to Slack.
Tines Workflow Overview
The Tines story consists of several agents working together:
1. Receive Suricata Alerts: Captures incoming alerts from suricata_relay.py and passes them to subsequent agents.
2. Analyze Alerts: Uses either OpenAI's API OR Tines's built-in AI Action (your choice) to interpret alerts. The agent is guided by a detailed prompt to generate summaries, highlight the severity, describe the potential impact, and recommend actions. These are formatted as JSON blocks compatible with Slack's Block Kit.
3. Send Slack DM): Sends the formatted summary to a designated Slack channel or user, ensuring alerts are timely and actionable.
4. Post Raw Alert to Thread: Appends the raw Suricata alert as a thread reply to the summary, providing additional context for further investigation.
Prompt Design for LLM
The LLM's prompt is tightly scoped to ensure consistency and relevance. Here's an excerpt:
### Role ###
You are a cybersecurity analyst tasked with interpreting alerts from an intrusion detection system.
### Task ###
Your task is to analyze the following Suricata alert (provided in JSON format) and create a detailed summary for the Security Operations (SecOps) team...
The complete prompt is available here.
Workflow in Action
- Suricata Relay: Alerts are deduplicated and sent to the Tines webhook.
- Analysis and Formatting: The LLM interprets the alert, focusing on severity, impact, and recommendations.
- Slack Notifications: Alerts are sent to Slack as primary messages, with raw alert data added as threaded replies. This two-tiered approach ensures immediate visibility and without losing detailed context.
Conclusion
In one fell swoop, we’ve built an IDS that captures, analyzes, and alerts—all without touching ELK’s gold-tier paywall. By combining open-source tools with automation, this setup is as powerful as it is accessible.
Future iterations could include: - Custom Suricata rules. - Advanced Tines workflows. - More tailored visualizations.
For now, you’re equipped with a system that takes network security from “good enough” to “well-oiled machine.”
Be vigilant, automate often, and let your tools do the heavy lifting.