Something Is Probably Happening on Your Network Right Now
You’ve got a firewall. You’re running UFW or OPNsense with strict rules. But a firewall only controls what traffic can enter and exit — it has no opinion about what that traffic contains. A connection to port 443 is allowed. The firewall doesn’t care if that connection is someone trying SQL injection, scanning for vulnerabilities, or your kid’s laptop running a cryptominer.
An IDS (Intrusion Detection System) watches actual traffic content, matches it against signatures of known attacks, and alerts you. An IPS (Intrusion Prevention System) goes further — it blocks the traffic in real time.
Snort and Suricata are the two main open-source options. You’ve probably heard of Snort. You should probably be using Suricata.
What IDS/IPS Actually Does
An IDS/IPS sits in the traffic path (or listens on a mirrored port) and:
- Reassembles network streams into protocol-aware views
- Matches traffic against a rule set of known attack signatures
- Alerts (IDS) or drops (IPS) matching traffic
- Logs detailed information about what it found
Rules look like this:
alert http any any -> $HOME_NET any (msg:"ET SCAN Nmap User-Agent";
content:"Nmap Scripting Engine"; http_user_agent;
classtype:web-application-attack; sid:2000537;)
That rule says: if we see an HTTP request with “Nmap Scripting Engine” in the User-Agent header going to our network, fire an alert. Simple in concept, powerful at scale with thousands of such rules covering every known attack pattern.
Snort: The Pioneer
Snort has been around since 1998. It essentially invented the modern IDS. The rule format is the industry standard — “Snort rules” is a synonym for IDS signatures in many contexts.
Snort 3 (the current version) is a significant rewrite with better performance than Snort 2, but it has a long history of being single-threaded and not scaling well on high-bandwidth networks.
Pros:
- Industry standard rule format
- Massive community and documentation
- Tight integration with various security tools
- Free Snort Community rules
Cons:
- Historically single-threaded (Snort 3 improved this)
- Cisco bought it — development velocity has changed
- The free rule set lags the paid Talos ruleset by 30 days
Suricata: The Modern Choice
Suricata was built by the OISF (Open Information Security Foundation) starting in 2009, specifically designed to be multi-threaded from the ground up.
Pros:
- Multi-threaded: uses all your CPU cores. On modern hardware, this is a big deal.
- Compatible with Snort rules (mostly — minor syntax differences)
- EVE JSON logging: structured JSON output for everything, Elastic/Splunk-friendly
- Built-in support for more protocols (HTTP/2, TLS/JA3, DNS, SMTP, etc.)
- Active open-source development
- Better TLS/JA3 fingerprinting for encrypted traffic analysis
- Built-in
suricatascsocket for live rule updates and stats
Cons:
- Configuration is more complex initially
- More moving parts
For a home lab on modern hardware (even a Pi 4 or a modest VM), use Suricata. The multi-threading alone is worth it, and the EVE JSON logging makes it actually useful for analysis rather than just generating alerts you ignore.
Installing Suricata
# Debian/Ubuntu — use the official OISF PPA for latest version
sudo add-apt-repository ppa:oisf/suricata-stable
sudo apt update
sudo apt install suricata
# Verify
suricata --version
# RHEL/Fedora
sudo dnf install suricata
Getting Rules
# Install suricata-update for rule management
sudo apt install python3-suricata-update # or pip3 install suricata-update
# Download the free Emerging Threats Open ruleset
sudo suricata-update
# List available rule sources
sudo suricata-update list-sources
# Enable additional free sources
sudo suricata-update enable-source et/open
sudo suricata-update enable-source oisf/trafficid
sudo suricata-update enable-source ptresearch/attackdetection
# Update all enabled sources
sudo suricata-update
Rules are saved to /var/lib/suricata/rules/suricata.rules by default.
suricata.yaml: The Essential Config
The default config is enormous (2000+ lines). Here’s what you actually need to change:
sudo nano /etc/suricata/suricata.yaml
# Your home network definition — CRITICAL, get this right
vars:
address-groups:
HOME_NET: "[192.168.0.0/16,10.0.0.0/8,172.16.0.0/12]"
EXTERNAL_NET: "!$HOME_NET"
HTTP_SERVERS: "$HOME_NET"
DNS_SERVERS: "$HOME_NET"
port-groups:
HTTP_PORTS: "80"
HTTPS_PORTS: "443"
# Network interface to listen on
af-packet:
- interface: eth0
cluster-id: 99
cluster-type: cluster_flow
defrag: yes
threads: auto # Uses all CPU cores
# EVE JSON logging — your main output
outputs:
- eve-log:
enabled: yes
filetype: regular
filename: /var/log/suricata/eve.json
types:
- alert:
metadata: yes
http: yes
tls: yes
- http:
extended: yes
- dns:
query: yes
answer: yes
- tls:
extended: yes
- stats:
totals: yes
# Rules location
default-rule-path: /var/lib/suricata/rules
rule-files:
- suricata.rules
# Test the configuration
sudo suricata -T -c /etc/suricata/suricata.yaml
# Start in IDS mode (AFPACKET - listening, not blocking)
sudo systemctl enable --now suricata
# Check it's running
sudo systemctl status suricata
sudo tail -f /var/log/suricata/eve.json | python3 -m json.tool
Running in IDS Mode vs IPS Mode
IDS mode (AF_PACKET): Suricata listens on a copy of traffic. It can alert but not block. Safe for initial deployment — you see what would have been blocked without actually affecting traffic.
# IDS mode — specify interface
sudo suricata -c /etc/suricata/suricata.yaml -i eth0
IPS mode (NFQueue): Traffic is redirected through Suricata via Linux netfilter. Suricata can drop packets. Affects real traffic — be careful.
# Set up NFQueue
sudo iptables -I FORWARD -j NFQUEUE --queue-num 0
sudo iptables -I INPUT -j NFQUEUE --queue-num 0
sudo iptables -I OUTPUT -j NFQUEUE --queue-num 0
# Run in IPS mode
sudo suricata -c /etc/suricata/suricata.yaml -q 0
For a home lab, start with IDS mode. Run it for a week, review the alerts, tune the rules, then consider IPS mode if you want actual blocking.
Reading EVE JSON Logs
EVE JSON is Suricata’s superpower — every alert, HTTP request, DNS query, and TLS connection logged as structured JSON.
# Watch alerts in real time
sudo tail -f /var/log/suricata/eve.json | jq 'select(.event_type=="alert")'
# See what's being hit
sudo jq 'select(.event_type=="alert") | {src: .src_ip, dest: .dest_ip, sig: .alert.signature}' \
/var/log/suricata/eve.json
# DNS queries (great for finding malware C2 traffic)
sudo jq 'select(.event_type=="dns" and .dns.type=="query") | {src: .src_ip, query: .dns.rrname}' \
/var/log/suricata/eve.json | head -50
# Top talkers
sudo jq -r 'select(.event_type=="alert") | .src_ip' /var/log/suricata/eve.json \
| sort | uniq -c | sort -rn | head -20
Integration with Elastic/Splunk
EVE JSON was designed for ingestion into SIEM platforms:
# Filebeat config to ship to Elasticsearch
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/suricata/eve.json
json.keys_under_root: true
json.add_error_key: true
output.elasticsearch:
hosts: ["localhost:9200"]
index: "suricata-%{+yyyy.MM.dd}"
The official Suricata Kibana dashboards give you visual traffic analysis, alert timelines, and top-threats views in minutes once the data is flowing.
OPNsense and pfSense Integration
Both OPNsense and pfSense have Suricata (and Snort) available as packages:
OPNsense: Services → Intrusion Detection
- Choose interface (WAN, LAN, or both)
- Select rule sets (ET Open is included)
- Enable IDS or IPS mode
- EVE logging available
This is the easiest path for home labs — no separate box needed. The IDS/IPS runs directly on your gateway.
For dedicated IDS on a separate machine, a Pi 4 with Suricata watching a mirrored port from a managed switch works well and keeps load off your router.
Tuning to Reduce False Positives
The biggest mistake: enabling every rule and drowning in alerts. Start with less and tune up:
# Disable noisy rules by SID
sudo suricata-update add-command --suppress-rule 2101411 # Suppress specific SID
# Or create a threshold file
cat > /etc/suricata/threshold.conf << 'EOF'
# Suppress alerts from your own scanners/tools
suppress gen_id 1, sig_id 2001219, track by_src, ip 192.168.1.100
# Threshold — only alert once per minute for this rule
threshold gen_id 1, sig_id 2002992, type both, track by_src, count 5, seconds 60
EOF
Run IDS for a week, collect your baselines, suppress the legitimate traffic patterns, then the remaining alerts are actually interesting.
The paranoia is warranted. The signal is there. You just need to turn down the noise first.