HOWTOIntermediate

Suricata IDS/IPS Deployment: From Install to Active Threat

Deploy Suricata as a full-featured Network Intrusion Detection and Prevention System on Ubuntu. Covers installation, interface capture, Emerging Threats...

Dylan H.

Tutorials

March 30, 2026
10 min read
Suricata IDS/IPS Deployment: From Install to Active Threat

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/log

You 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 -5

Enable and start the service (it will be reconfigured before it captures anything useful):

sudo systemctl enable suricata
sudo systemctl stop suricata   # stop until fully configured

Step 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-sources

2b — 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-update

Rules 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.rules

2c — Schedule daily rule updates via cron

echo "0 3 * * * root /usr/bin/suricata-update && systemctl reload suricata" \
  | sudo tee /etc/cron.d/suricata-update

Step 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.yaml

3a — 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: yes

3c — 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
        - flow

3d — Point Suricata at the merged rule file

default-rule-path: /var/lib/suricata/rules
 
rule-files:
  - suricata.rules

3e — 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 --force

Add the following to the systemd override file:

[Service]
ExecStart=
ExecStart=/usr/bin/suricata -c /etc/suricata/suricata.yaml -i eth0 --pidfile /run/suricata.pid

Then reload and start:

sudo systemctl daemon-reload
sudo systemctl start suricata
sudo systemctl status suricata

Watch 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 nftables

5b — 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 0

For 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 0

Save the ruleset so it survives reboots:

sudo nft list ruleset | sudo tee /etc/nftables.conf

5c — 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: yes

5d — 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.pid
sudo systemctl daemon-reload
sudo systemctl restart suricata

Note: fail-open: yes ensures that if Suricata crashes or is overloaded, packets are passed rather than dropped. For high-security environments, set this to no.


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.rules

Example 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.rules

Reload rules without restarting:

sudo kill -USR2 $(cat /run/suricata.pid)
# Or: sudo systemctl reload suricata

Step 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.socket

A 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 filebeat

Option 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-agent

Wazuh 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 10 to confirm traffic is present on the interface.
  • Check HOME_NET: If HOME_NET doesn't include your subnet, many rules won't fire.
  • Rule action: Ensure rules use alert (not drop) 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: auto

Also 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: yes in the nfq config 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.rules

Suricata consuming excessive CPU

  • Reduce the number of monitored flow types in eve-log (disable flow and files logging)
  • Enable hardware timestamping if supported by your NIC
  • Use stream.memcap to limit TCP reassembly memory:
stream:
  memcap: 1gb
  checksum-validation: yes

Summary

You now have a functional Suricata deployment covering:

ComponentConfiguration
Rule managementsuricata-update + ET/Open, daily cron refresh
Capture modeAF_PACKET (IDS) or NFQUEUE via nftables (IPS)
Custom rules/etc/suricata/rules/local.rules (persists updates)
Structured loggingEVE JSON at /var/log/suricata/eve.json
SIEM integrationFilebeat module or Wazuh agent localfile
Reload without restartkill -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/pro or abuse.ch SSL blacklist sources via suricata-update
  • Build a Grafana dashboard from EVE JSON metrics using Loki or Elasticsearch
  • Tune rule thresholds in /etc/suricata/threshold.config to reduce alert fatigue
  • Explore lua scripting 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.