AIO Ep22. Configuring Port Mirroring on PVE Host and Suricata IDS Firewall简体中文 / [English]<br>Home<br>About<br>Writing<br>Category<br>Friends<br>Search
Previous post Next post Back to top Share post
1. Background<br>2. Installation2.1. LXC Container and Port Mirroring<br>2.2. Suricata<br>2.3. EveBox
This article is currently an experimental machine translation and may contain errors. If anything is unclear, please refer to the original Chinese version. I am continuously working to improve the translation.
Background<br>My HomeLab PVE host has long been running a chaotic mix of workloads — from simple SMB/Syncthing file sharing, various scrapers and databases, to Windows/Linux VMs for development.<br>Although I’ve already configured proper internal firewall rules in the PVE console, I still notice unexplained and hard-to-trace internet traffic in Netdata monitoring. I’ve used tcpdump to investigate some of it, but it’s time-consuming and tedious.<br>So I decided to set up enterprise-grade traffic monitoring and analysis capabilities — something that can listen to all internal network traffic, perform DPI (Deep Packet Inspection) to understand application-level protocols, log events, and provide a dashboard for inspection.<br>An IDS (Intrusion Detection System) is a common feature in such network analysis tools. It automatically flags suspicious traffic based on rules, helping detect misconfigurations or signs of malicious intrusion.<br>At first, I tried some truly late-night enterprise-grade products, like FortiGate and Sophos free trial VMs. But the experience wasn’t satisfying — their configurations were complex and obscure, and event logging/viewing wasn’t clear enough.<br>Eventually, I settled on the open-source Suricata paired with the frontend Evebox. While Evebox’s UI is a bit barebones, it basically meets my needs and has very low CPU and memory usage.<br>Installation<br>LXC Container and Port Mirroring<br>Create a Debian 12 LXC container on PVE, name it suricata for example. First, add a normal network interface eth0 attached to vmbr0, and assign it an IP address for regular access to the container.<br>In the PVE Dashboard, go to Node - System - Network, and create a Linux bridge vmbr1. This bridge will be used solely for traffic mirroring — don’t assign an IP address or gateway, and don’t bind any physical interface yet.<br>Run the following script on the PVE host to mirror all traffic from VMs, containers, and the host itself to the vmbr1 bridge:<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br>23<br>24<br>25<br>26<br>27<br>28<br>#!/bin/bash<br>apply_tc_rules() {<br>local port_name=$1
echo "Applying tc rules to $port_name"<br>tc qdisc del dev $port_name root<br>tc qdisc del dev $port_name ingress
tc qdisc add dev $port_name ingress<br>tc filter add dev $port_name parent ffff: protocol all u32 match u8 0 0 action mirred egress mirror dev vmbr1<br>tc qdisc add dev $port_name root handle 1: prio<br>tc filter add dev $port_name parent 1: protocol all u32 match u8 0 0 action mirred egress mirror dev vmbr1
apply_tc_to_fwpr_ports() {<br>local bridge_port="vmbr0"<br>apply_tc_rules $bridge_port<br>for port in /sys/class/net/$bridge_port/brif/fwpr*; do<br>if [ -d "$port" ]; then<br>port_name=$(basename "$port")<br>if [[ $port_name == fwpr* ]]; then<br>apply_tc_rules $port_name<br>fi<br>fi<br>done
apply_tc_to_fwpr_ports<br>The syntax of these tc (traffic control) commands is admittedly bizarre — take for instance tc filter add dev vmbr0 parent ffff: protocol all u32 match u8 0 0 action mirred egress mirror dev vmbr1. Not many commands have such long and cryptic parameter lists. Since I don’t fully understand it myself, I won’t go into detail. Interested readers can look up tc usage — this was the simplest method I found for port mirroring on Linux.<br>Back to the topic: the apply_tc_rules function mirrors bidirectional traffic from a given port to vmbr1, and apply_tc_to_fwpr_ports applies this rule to vmbr0 and all interfaces bridged to it.<br>After running the script, all traffic on vmbr0 gets copied to vmbr1. (Note: if new VMs or containers are added later, you’ll need to re-run the script or manually apply the rules to new interfaces.)<br>Now, add a second network interface eth1 to the suricata container, connected to vmbr1. No IP configuration is needed. This way, inside the container, you can listen to all host traffic via eth1. You can verify this with tcpdump.<br>Suricata<br>As mentioned earlier, Suricata is a high-performance, open-source network analysis and threat detection engine. We’ll run it inside the LXC container, listening on eth1.<br>The official Debian package is outdated, so follow the official guide to compile from source: https://docs.suricata.io/en/latest/install.html. Be sure to run make install-conf to generate default configuration files.<br>Set up the systemd service file /etc/systemd/system/suricata.service:<br>10<br>11<br>12<br>13<br>[Unit]<br>Description=Suricata Intrusion Detection Service<br>After=syslog.target network-online.target
[Service]<br># Environment file to pick up $OPTIONS.<br>#EnvironmentFile=-/etc/default/suricata<br>ExecStartPre=/bin/rm -f...