Introduction
Suricata is a high-performance, open-source Network Intrusion Detection System (NIDS) and Intrusion Prevention System (NIPS) maintained by the Open Information Security Foundation (OISF). Unlike older tools such as Snort, Suricata is multi-threaded from the ground up, supports hardware-accelerated packet capture via AF_PACKET and DPDK, and ships with a built-in Lua scripting engine for custom detection logic.
In this guide you will:
- Install Suricata from the OISF PPA on Ubuntu
- Configure it to capture traffic on a live interface in IDS (passive) mode
- Download and enable the Emerging Threats Open rule set
- Switch to inline IPS mode using nftables NFQUEUE
- Validate detection with a safe test payload
- Integrate JSON alert logs with a SIEM
By the end, your host will be alerting—and optionally blocking—malicious traffic in real time.
Prerequisites
Before starting, confirm the following:
# Ubuntu version
lsb_release -a
# Available interfaces (pick the one that sees production traffic)
ip link show
# Kernel version (AF_PACKET requires >= 3.6, NFQUEUE requires >= 2.6.14)
uname -r
# Sufficient disk space for logs (recommend ≥ 20 GB)
df -h /var/logYou will also need internet access to pull packages and rule updates during setup.
Step 1 — Install Suricata from the OISF PPA
The Ubuntu default repos often ship an outdated Suricata version. Use the official OISF PPA to get the latest stable release.
# Add OISF stable PPA
sudo add-apt-repository ppa:oisf/suricata-stable -y
sudo apt update
# Install Suricata
sudo apt install suricata suricata-update -y
# Verify version (should be 7.x or later)
suricata --build-info | head -5Enable and start the service (it will be reconfigured before it captures anything useful):
sudo systemctl enable suricata
sudo systemctl stop suricata # stop until fully configuredStep 2 — Update and Enable Rule Sets
Suricata ships with suricata-update, a rule management tool that fetches, merges, and installs rule sets automatically.
2a — Fetch available sources
# List all available rule sources (community + commercial)
sudo suricata-update list-sources2b — Enable Emerging Threats Open (free, no registration)
# Enable the ET/Open rule set
sudo suricata-update enable-source et/open
# Download and install all enabled sources
sudo suricata-updateRules are written to /var/lib/suricata/rules/suricata.rules. You should see thousands of rules:
wc -l /var/lib/suricata/rules/suricata.rules
# Example: 47382 /var/lib/suricata/rules/suricata.rules2c — Schedule daily rule updates via cron
echo "0 3 * * * root /usr/bin/suricata-update && systemctl reload suricata" \
| sudo tee /etc/cron.d/suricata-updateStep 3 — Configure Suricata
The main config lives at /etc/suricata/suricata.yaml. Back it up, then make targeted edits.
sudo cp /etc/suricata/suricata.yaml /etc/suricata/suricata.yaml.bak
sudo nano /etc/suricata/suricata.yaml3a — Define your HOME_NET
Find and set HOME_NET to your local subnet(s). This controls which side of traffic is treated as "internal":
vars:
address-groups:
HOME_NET: "[192.168.0.0/16,10.0.0.0/8,172.16.0.0/12]"
EXTERNAL_NET: "!$HOME_NET"3b — Set the capture interface
Find the af-packet section and set your interface. Replace eth0 with your actual interface name:
af-packet:
- interface: eth0
cluster-id: 99
cluster-type: cluster_flow
defrag: yes
use-mmap: yes
tpacket-v3: yes3c — Enable EVE JSON logging
EVE JSON is the preferred structured log format for SIEM integration. Ensure it is enabled:
outputs:
- eve-log:
enabled: yes
filetype: regular
filename: /var/log/suricata/eve.json
types:
- alert:
payload: yes
payload-printable: yes
packet: yes
metadata: yes
- http:
extended: yes
- dns:
- tls:
extended: yes
- files:
force-magic: no
- ssh
- flow3d — Point Suricata at the merged rule file
default-rule-path: /var/lib/suricata/rules
rule-files:
- suricata.rules3e — Validate the config
sudo suricata -T -c /etc/suricata/suricata.yaml -v
# Should end with: Configuration provided was successfully loaded. Exiting.Step 4 — Run Suricata in IDS (Passive) Mode
Start Suricata against your interface in IDS mode. This does not block traffic—it only alerts.
# Start in IDS mode on eth0
sudo suricata -c /etc/suricata/suricata.yaml -i eth0 --daemon
# Or via systemd after editing the service drop-in
sudo systemctl edit suricata --forceAdd the following to the systemd override file:
[Service]
ExecStart=
ExecStart=/usr/bin/suricata -c /etc/suricata/suricata.yaml -i eth0 --pidfile /run/suricata.pidThen reload and start:
sudo systemctl daemon-reload
sudo systemctl start suricata
sudo systemctl status suricataWatch live alerts:
sudo tail -f /var/log/suricata/eve.json | jq 'select(.event_type=="alert")'Step 5 — Switch to Inline IPS Mode via NFQUEUE
IPS mode allows Suricata to actively drop malicious packets. This uses the Linux NFQUEUE target to intercept packets before they are forwarded.
5a — Install nftables (if not present)
sudo apt install nftables -y
sudo systemctl enable --now nftables5b — Create NFQUEUE rules
Route traffic through Suricata's NFQUEUE. The queue number must match the Suricata config:
sudo nft add table inet filter
sudo nft add chain inet filter forward '{ type filter hook forward priority 0; policy accept; }'
sudo nft add rule inet filter forward queue num 0For a host-based deployment (protecting the host itself, not forwarding traffic):
sudo nft add chain inet filter input '{ type filter hook input priority 0; policy accept; }'
sudo nft add chain inet filter output '{ type filter hook output priority 0; policy accept; }'
sudo nft add rule inet filter input queue num 0
sudo nft add rule inet filter output queue num 0Save the ruleset so it survives reboots:
sudo nft list ruleset | sudo tee /etc/nftables.conf5c — Update Suricata config for IPS mode
In /etc/suricata/suricata.yaml, replace the af-packet section with:
nfq:
mode: repeat
repeat-mark: 1
repeat-mask: 1
route-queue: 2
batchcount: 20
fail-open: yes5d — Restart with NFQUEUE mode
Update the systemd override to use -q 0 instead of -i eth0:
[Service]
ExecStart=
ExecStart=/usr/bin/suricata -c /etc/suricata/suricata.yaml -q 0 --pidfile /run/suricata.pidsudo systemctl daemon-reload
sudo systemctl restart suricataNote:
fail-open: yesensures that if Suricata crashes or is overloaded, packets are passed rather than dropped. For high-security environments, set this tono.
Step 6 — Write a Custom Detection Rule
Suricata rules follow the Snort-compatible syntax. Add custom rules to a local file that persists across suricata-update runs.
Create /etc/suricata/rules/local.rules:
sudo mkdir -p /etc/suricata/rules
sudo nano /etc/suricata/rules/local.rulesExample rules:
# Alert on any HTTP request to a known bad domain
alert http any any -> any any (msg:"POLICY Suspicious domain access"; \
http.host; content:"malicious-example.com"; nocase; \
classtype:policy-violation; sid:9000001; rev:1;)
# Alert on SSH brute force (>5 connections in 60 seconds from same src)
alert tcp any any -> $HOME_NET 22 (msg:"SCAN SSH Brute Force Attempt"; \
flags:S; threshold: type both, track by_src, count 5, seconds 60; \
classtype:attempted-admin; sid:9000002; rev:1;)
# Drop outbound DNS queries to port 53 going to non-standard resolvers (IPS mode)
drop dns $HOME_NET any -> ![$DNS_SERVERS] 53 (msg:"POLICY DNS to unauthorized resolver"; \
classtype:policy-violation; sid:9000003; rev:1;)Add the local rules file to suricata.yaml:
rule-files:
- suricata.rules
- /etc/suricata/rules/local.rulesReload rules without restarting:
sudo kill -USR2 $(cat /run/suricata.pid)
# Or: sudo systemctl reload suricataStep 7 — Verification and Testing
7a — Test with the EICAR string over HTTP
The EICAR test string is a safe, universally recognized anti-malware test payload. Fetch it via HTTP (not HTTPS, since TLS decryption isn't configured yet):
# From a monitored host (not the Suricata host itself in IDS mode)
curl -o /dev/null http://testmyids.com
# Watch for the alert
sudo tail -f /var/log/suricara/eve.json | jq 'select(.event_type=="alert") | {sig: .alert.signature, src: .src_ip, dest: .dest_ip}'7b — Check Suricata statistics
# View the stats log
sudo tail -50 /var/log/suricata/stats.log
# Or via EVE
sudo tail -f /var/log/suricata/eve.json | jq 'select(.event_type=="stats") | .stats.decoder'7c — Verify rule count loaded
sudo suricatasc -c "ruleset-reload-nonblocking" /var/run/suricata/suricata-command.socket
sudo suricatasc -c "dump-counters" /var/run/suricata/suricata-command.socket | jq '.message.detect'7d — Check interface capture stats
sudo suricatasc -c "iface-list" /var/run/suricata/suricata-command.socket
sudo suricatasc -c "iface-stat eth0" /var/run/suricata/suricata-command.socketA healthy deployment will show captured packets increasing and zero or near-zero drops.
Step 8 — SIEM Integration (EVE JSON Forwarding)
Option A — Filebeat to Elasticsearch/Wazuh
Install Filebeat and configure it to ship Suricata's EVE JSON log:
# /etc/filebeat/modules.d/suricata.yml
- module: suricata
eve:
enabled: true
var.paths: ["/var/log/suricata/eve.json"]sudo filebeat modules enable suricata
sudo filebeat setup
sudo systemctl restart filebeatOption B — Wazuh Agent (ossec.conf)
Add a local file entry to the Wazuh agent config at /var/ossec/etc/ossec.conf:
<localfile>
<log_format>json</log_format>
<location>/var/log/suricata/eve.json</location>
</localfile>sudo systemctl restart wazuh-agentWazuh ships built-in decoders and rules for Suricata EVE JSON under ruleset ID 86xxx.
Troubleshooting
Suricata starts but no alerts appear
- Check interface: Run
tcpdump -i eth0 -c 10to confirm traffic is present on the interface. - Check HOME_NET: If
HOME_NETdoesn't include your subnet, many rules won't fire. - Rule action: Ensure rules use
alert(notdrop) in IDS mode. - TLS traffic: Suricata cannot inspect encrypted HTTPS without TLS decryption or mirrored traffic. Look for DNS/HTTP alerts first.
High packet drop rate in stats.log
# Increase the AF_PACKET ring buffer size in suricata.yaml
af-packet:
- interface: eth0
buffer-size: 67108864 # 64 MB
ring-size: 2048
threads: autoAlso increase worker threads to match CPU cores:
threading:
set-cpu-affinity: yes
cpu-affinity:
- management-cpu-set:
cpu: [ 0 ]
- worker-cpu-set:
cpu: [ "1-7" ]
mode: "exclusive"NFQUEUE mode: traffic stops flowing
- Confirm Suricata is running and connected to the queue:
sudo ss -lnp | grep suricata - Temporarily flush nftables rules to restore connectivity:
sudo nft flush ruleset - Set
fail-open: yesin thenfqconfig block to prevent drops on Suricata failure
Rules fail to load after suricata-update
# Check for syntax errors in custom rules
sudo suricata -T -c /etc/suricata/suricata.yaml 2>&1 | grep -i error
# Verify the rules path exists
ls -la /var/lib/suricata/rules/suricata.rules
ls -la /etc/suricata/rules/local.rulesSuricata consuming excessive CPU
- Reduce the number of monitored flow types in
eve-log(disableflowandfileslogging) - Enable hardware timestamping if supported by your NIC
- Use
stream.memcapto limit TCP reassembly memory:
stream:
memcap: 1gb
checksum-validation: yesSummary
You now have a functional Suricata deployment covering:
| Component | Configuration |
|---|---|
| Rule management | suricata-update + ET/Open, daily cron refresh |
| Capture mode | AF_PACKET (IDS) or NFQUEUE via nftables (IPS) |
| Custom rules | /etc/suricata/rules/local.rules (persists updates) |
| Structured logging | EVE JSON at /var/log/suricata/eve.json |
| SIEM integration | Filebeat module or Wazuh agent localfile |
| Reload without restart | kill -USR2 $(cat /run/suricata.pid) |
Next steps to harden your deployment:
- Enable TLS logging with JA3/JA3S fingerprinting for encrypted traffic visibility
- Add the
et/proorabuse.chSSL blacklist sources viasuricata-update - Build a Grafana dashboard from EVE JSON metrics using Loki or Elasticsearch
- Tune rule thresholds in
/etc/suricata/threshold.configto reduce alert fatigue - Explore
luascripting for behavioral detection rules that signature-based approaches miss
Suricata's combination of high throughput, protocol-aware parsing, and rich output formats makes it one of the most capable open-source network security sensors available. With ET/Open rules providing daily-updated threat intelligence and NFQUEUE enabling active blocking, this stack gives you enterprise-grade network visibility at zero license cost.