Comparing Suricata Deployment Models on Linux
When building an intrusion detection and prevention system (IDS/IPS), the most critical decision is selecting the right network topology. Do you want Suricata to observe traffic out-of-band or actively inspect and filter every packet? There are three primary architectures:
- Passive IDS (Passive Sniffing via AF_PACKET/SPAN Port): The network interface receives mirrored traffic from a switch SPAN port or network TAP. Suricata inspects and analyzes packets in the background. When it detects malicious activity or a port scan, the system only logs an alert.
- Traditional Inline IPS (NFQUEUE / iptables): Packets traversing the Netfilter firewall are sent to a userspace queue (NFQUEUE). Suricata inspects each packet against its rule set and then issues a verdict:
ACCEPT(allow through) orDROP(terminate the connection immediately). - Modern Inline IPS with eBPF/XDP: Instead of forwarding packets to userspace through the kernel network stack, Suricata loads eBPF bytecode directly into the network card driver (XDP). Malicious packets are dropped at the hardware/driver layer before consuming CPU cycles.
Pros and Cons of Each Architecture
Each deployment model balances infrastructure safety against server resource consumption:
1. Passive IDS (AF_PACKET)
- Pros: Maximum uptime preservation. Even if Suricata becomes overloaded or crashes, your web server and database remain unaffected. Additional network latency is zero.
- Cons: Cannot automatically block ongoing attacks. By the time a SQL injection alert hits your dashboard, data may have already been exfiltrated. Administrators must write custom scripts or configure fail2ban to ban offending IPs after the fact.
2. Inline IPS via NFQUEUE
- Pros: Stops exploits in real time. Malicious packets are dropped right at the gateway, never reaching your Nginx reverse proxy or backend services.
- Cons: Network latency increases by approximately 0.2ms to 1.5ms per request due to context switching between kernel space and userspace. If Suricata hangs and you fail to enable fail-open bypass, the server will lose network connectivity entirely.
3. Inline IPS with eBPF/XDP
- Pros: Blazing-fast performance. Capable of filtering 5 to 10 million packets per second (pps) on a 10GbE interface, effortlessly mitigating Layer 4 DoS attacks.
- Cons: Requires Linux kernel 5.4 or later. Network interfaces must have drivers supporting Native XDP (such as Intel ixgbe/i40e or Mellanox). Debugging signatures is more complex than with NFQUEUE.
Which Solution Should You Choose for Production?
A safe, battle-tested rollout for production servers consists of two clear phases:
- Week 1: Run in Passive IDS mode. Let Suricata inspect real traffic for 3 to 7 days. Carefully review log files to weed out false positives from partner webhooks or internal backup jobs.
- Enforcement Phase: Switch to Inline IPS with NFQUEUE using the
--queue-bypassflag. This is the practical choice for medium-sized VPS instances or bare-metal servers (4–16 vCPUs), blocking web exploits while keeping traffic flowing if the process crashes.
How to Deploy Suricata IPS on Ubuntu/Debian
Step 1: Prepare the Server and Secure User Accounts
Before modifying firewall rules and opening ports, ensure your user accounts are properly secured. You can use the password generator at toolcraft.app/en/tools/security/password-generator to generate strong, random passwords for sudo users. It runs entirely client-side in the browser without transmitting data over the network, making SSH operations safer.
# Update repositories and install required dependencies
sudo apt update && sudo apt upgrade -y
sudo apt install -y software-properties-common curl libpcap-dev libnetfilter-queue-dev jq
Step 2: Install Suricata from the Official PPA
Suricata packages in default Ubuntu repositories are often outdated. Use the official OISF PPA to get the latest engine updates and security patches:
sudo add-apt-repository ppa:oisf/suricata-stable -y
sudo apt update
sudo apt install -y suricata
Run the following command to verify that Suricata was compiled with NFQUEUE support:
suricata --build-info | grep -E "NFQueue|AF_PACKET"
If the terminal outputs NFQueue support: yes, your system is ready for IPS mode.
Step 3: Fine-Tune suricata.yaml
Open the primary configuration file:
sudo nano /etc/suricata/suricata.yaml
Review the following three critical sections:
- Define protected networks (HOME_NET): Enter your server’s internal subnet or public IP to prevent false alerts:
vars: address-groups: HOME_NET: "[192.168.1.0/24, 10.0.0.0/8, 203.0.113.15/32]" EXTERNAL_NET: "!$HOME_NET" - Configure the nfq queue: Locate the
nfq:block and ensure queue number 0 is properly assigned:nfq: mode: accept repeat-mark: 1 repeat-mask: 1 route-queue: 2 - Configure EVE JSON logging: Enable
eve-logso Suricata writes all alerts, DNS queries, and HTTP metadata to/var/log/suricata/eve.json. This file can be ingested directly into ELK, Grafana Loki, or Vector.
Step 4: Update Rulesets from Emerging Threats (ET Open)
Suricata includes the suricata-update utility to fetch the latest signatures:
# Download the latest rules from the OISF repository
sudo suricata-update
# List available rule sources
sudo suricata-update list-sources
By default, rules in the ET Open ruleset use the alert action. To have Suricata automatically convert high-severity alerts into drop rules, create /etc/suricata/modify.conf:
echo 're:drop "^alert (tcp|udp|icmp) \$EXTERNAL_NET any -> \$HOME_NET"' | sudo tee /etc/suricata/modify.conf
sudo suricata-update --modify-conf /etc/suricata/modify.conf
Step 5: Create a Test Drop Rule
We will create a rule that blocks inbound Ping packets (ICMP Echo Request) to verify the drop functionality. Open /var/lib/suricata/rules/local.rules:
sudo nano /var/lib/suricata/rules/local.rules
Add the following line to the file:
drop icmp any any -> $HOME_NET any (msg:"LOCAL TEST - Blocked Ping Echo Request"; itype:8; sid:1000001; rev:1;)
Ensure that - local.rules is listed under rule-files: in /etc/suricata/suricata.yaml. Next, test the configuration file syntax:
sudo suricata -T -c /etc/suricata/suricata.yaml -v
If the output shows Configuration provided was successfully verified, your configuration is valid.
Step 6: Route Traffic through NFQUEUE using iptables
Now insert Suricata directly into the traffic path. Use the --queue-bypass flag to ensure your server does not lose connectivity if Suricata unexpectedly stops:
# Send INPUT and FORWARD traffic to NFQUEUE queue 0
sudo iptables -I INPUT -j NFQUEUE --queue-num 0 --queue-bypass
sudo iptables -I FORWARD -j NFQUEUE --queue-num 0 --queue-bypass
Start Suricata bound to queue 0 in daemon mode:
sudo suricata -c /etc/suricata/suricata.yaml -q 0 -D
If managing Suricata via systemd, edit /etc/default/suricata, set LISTENMODE=nfqueue, and restart the service:
sudo systemctl restart suricata
sudo systemctl status suricata
Step 7: Verify Blocking and Analyze Logs
From another machine on the network, send a ping to the server:
ping 203.0.113.15
Packets will be immediately blocked, displaying Request timed out or 100% packet loss. Inspect the eve.json file on the server to view the event details:
sudo tail -f /var/log/suricata/eve.json | jq 'select(.event_type=="alert") | {timestamp: .timestamp, src_ip: .src_ip, alert: .alert.signature, action: .alert.action}'
The terminal will display output similar to:
{
"timestamp": "2026-10-19T10:47:30.123456+0000",
"src_ip": "192.168.1.50",
"alert": "LOCAL TEST - Blocked Ping Echo Request",
"action": "blocked"
}
The "action": "blocked" field confirms that the packet was dropped before reaching the Linux network stack. This setup proactively mitigates Nmap scans, SSH brute-force attempts, and web exploits while ensuring overall server stability.

