Snort is an open-source network intrusion detection and prevention system (IDS/IPS). It reads packets off an interface, decodes them, and matches them against rules that describe known-bad traffic — exploit attempts, scanning, malware callbacks, policy violations — and raises an alert (or, inline, drops the packet). It has been the reference open-source IDS since 1998; Snort 3 (2021) is a rewrite with a Lua configuration, multithreading and a cleaner rule language.
This guide installs Snort 3 on Ubuntu 22.04 and 24.04 from source, because the snort package in Ubuntu's repositories is the legacy 2.9 branch with a different configuration format and rule set. It then does the minimum real configuration: your network definition, the free community rules, a local rule you can trigger on purpose, running on a live interface, a systemd unit, and the NIC setting that otherwise makes Snort miss traffic.
Snort's three modes
- Sniffer — print decoded packets to the console (
snort -i eth0). A slowertcpdump; mostly for checking Snort sees the interface. - Packet logger — write packets to disk (
-l /var/log/snort). - IDS/IPS — apply rules; alert (IDS, passive) or drop (IPS, inline with two interfaces or NFQUEUE). This guide sets up IDS mode; IPS is a configuration change on top once rules are tuned.
1. Build dependencies
sudo apt update && sudo apt upgrade -y
sudo apt install -y build-essential cmake pkg-config git wget curl \
libpcap-dev libpcre3-dev libpcre2-dev libdumbnet-dev zlib1g-dev libluajit-5.1-dev \
libhwloc-dev libssl-dev libunwind-dev libfl-dev flex bison libtool \
autoconf automake libmnl-dev libtirpc-dev uuid-dev libnghttp2-dev \
libgoogle-perftools-dev libhyperscan-dev
libhyperscan-dev (Intel Hyperscan; on Ubuntu 24.04 the drop-in fork is libvectorscan-dev) and libgoogle-perftools-dev (tcmalloc) are optional but make rule matching and memory behaviour noticeably better; the configure step picks them up automatically. Older Snort 3 releases link against libpcre3, releases from 3.3 onward against libpcre2 — installing both covers either.
2. Build libdaq
Snort 3 captures packets through the Data Acquisition library, which must be built first:
mkdir -p ~/snort-src && cd ~/snort-src
git clone https://github.com/snort3/libdaq.git
cd libdaq
./bootstrap
./configure
make -j"$(nproc)"
sudo make install
sudo ldconfig
3. Build Snort 3
cd ~/snort-src
git clone https://github.com/snort3/snort3.git
cd snort3
./configure_cmake.sh --prefix=/usr/local --enable-tcmalloc
cd build
make -j"$(nproc)"
sudo make install
sudo ldconfig
snort -V
Expect a banner ending in Version 3.x.y.z. If you prefer a release tarball over the git head, download it from the snort3 GitHub releases page and run the same configure_cmake.sh from the extracted directory.
4. Stop the NIC from hiding traffic
Modern NICs reassemble packets in hardware (GRO/LRO). Snort then sees a few giant packets instead of the real stream and misses rule matches. Turn offloading off on the sniffing interface and make it persistent:
IFACE=eth0 # your capture interface: ip -br link
sudo ethtool -K "$IFACE" gro off lro off
sudo tee /etc/systemd/system/snort-nic.service >/dev/null <<EOF2
[Unit]
Description=Disable NIC offloading for Snort on $IFACE
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/sbin/ip link set dev $IFACE promisc on
ExecStart=/usr/sbin/ethtool -K $IFACE gro off lro off
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF2
sudo systemctl daemon-reload
sudo systemctl enable --now snort-nic.service
In a VM, do the same for the virtual NIC; on a SPAN/mirror port, put the interface in promiscuous mode as above and give it no IP address.
5. Configure snort.lua
The main configuration is /usr/local/etc/snort/snort.lua. Three edits:
sudo nano /usr/local/etc/snort/snort.lua
-
HOME_NET — the networks you are protecting. Alerts and many rules are directional, so this matters:
HOME_NET = '192.168.1.0/24' -- or '[10.0.0.0/8,192.168.0.0/16]' EXTERNAL_NET = '!$HOME_NET' -
Rule files — find the
ips =block and point it at the rules (created in the next step):ips = { enable_builtin_rules = true, include = RULE_PATH .. '/local.rules', variables = default_variables }Snort 3 reads one
includehere; put further files insidelocal.ruleswithinclude snort3-community.ruleslines, or pass extra files on the command line with-R. -
Alert output — leave the defaults; we select the output format on the command line / in the service (
-A alert_fast).
Check the file parses:
sudo snort -c /usr/local/etc/snort/snort.lua -T
# ...
# Snort successfully validated the configuration (with 0 warnings).
6. Rules: community set plus a local test rule
sudo mkdir -p /usr/local/etc/rules /var/log/snort
cd /tmp
wget https://www.snort.org/downloads/community/snort3-community-rules.tar.gz
tar xzf snort3-community-rules.tar.gz
sudo cp snort3-community-rules/snort3-community.rules /usr/local/etc/rules/
sudo cp snort3-community-rules/sid-msg.map /usr/local/etc/rules/ 2>/dev/null || true
Now a rule you can trigger yourself:
sudo tee /usr/local/etc/rules/local.rules >/dev/null <<'RULES'
include snort3-community.rules
alert icmp any any -> $HOME_NET any ( msg:"LOCAL ICMP echo to HOME_NET"; itype:8; sid:1000001; rev:1; )
alert tcp any any -> $HOME_NET 22 ( msg:"LOCAL SSH connection attempt"; flow:to_server,established; sid:1000002; rev:1; )
RULES
Local rule SIDs must be ≥ 1,000,000 to stay out of the reserved ranges. Re-validate with -T (it now loads the rules and reports how many).
Set RULE_PATH in snort.lua if it is not already /usr/local/etc/rules:
RULE_PATH = '/usr/local/etc/rules'
7. Run Snort in IDS mode
sudo snort -c /usr/local/etc/snort/snort.lua -i eth0 -A alert_fast -s 65535 -k none
-A alert_fast— one line per alert to stdout;-A alert_jsonfor machine-readable output;-l /var/log/snortto write files instead.-s 65535— full snap length, so large packets are not truncated before matching.-k none— ignore checksum errors; needed when offloading cannot be disabled (checksums are computed by the NIC after Snort sees the packet) or you get zero alerts.
From another machine, ping the Snort host and try an SSH connection. You should see:
10/18-10:42:07.113201 [**] [1:1000001:1] "LOCAL ICMP echo to HOME_NET" [**] [Priority: 0] {ICMP} 203.0.113.5 -> 192.168.1.10
10/18-10:42:19.880412 [**] [1:1000002:1] "LOCAL SSH connection attempt" [**] [Priority: 0] {TCP} 203.0.113.5:51234 -> 192.168.1.10:22
Press Ctrl+C; Snort prints packet and rule statistics on exit.
8. Run it as a service
sudo tee /etc/systemd/system/snort3.service >/dev/null <<'EOF2'
[Unit]
Description=Snort 3 NIDS
After=network-online.target snort-nic.service
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/snort -c /usr/local/etc/snort/snort.lua -i eth0 -A alert_fast -s 65535 -k none -l /var/log/snort -D -u snort -g snort --create-pidfile
ExecReload=/bin/kill -SIGHUP $MAINPID
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF2
sudo useradd -r -s /usr/sbin/nologin -M snort 2>/dev/null || true
sudo chown -R snort:snort /var/log/snort
sudo systemctl daemon-reload
sudo systemctl enable --now snort3
sudo systemctl status snort3 --no-pager
tail -f /var/log/snort/alert_fast.txt
Remove -D if you prefer systemd to manage the foreground process (Type=simple works either way on current Snort builds; if the unit flaps, drop -D). Rotate /var/log/snort/alert_fast.txt with a logrotate stanza and copytruncate.
9. Keeping rules current
The community rules are a free, delayed subset. For production use register at snort.org for the Registered (free, 30-day delayed) or Subscriber rule sets and automate updates with PulledPork 3:
cd ~/snort-src
git clone https://github.com/shirkdog/pulledpork3.git
Configure pulledpork.conf with your oinkcode and snort_path, run it from a daily timer, and systemctl reload snort3 afterwards. OpenAppID (application detection — "this is Dropbox traffic") is an optional add-on; download the detector package from snort.org and point appid = { app_detector_dir = '/usr/local/lib' } at it in snort.lua.
Troubleshooting
snort: error while loading shared libraries: libdaq.so.3: cannot open shared object file—sudo ldconfigafter installing libdaq, or add/usr/local/libto/etc/ld.so.conf.d/local.confand runldconfig.ERROR: can't find local.rules—RULE_PATHinsnort.luadoes not match where you put the files, or theincludeline inipsis missing. Paths inincludelines inside rule files are relative to that file.- No alerts at all, even for the ICMP test rule — checksum offloading (
-k none), wrong interface (-i), orHOME_NETdoes not contain the destination address. Run once with-A alert_fastand--warn-allto see what Snort thinks it is doing; the exit statistics show whether any packets were received. Snort successfully validatedbut the service exits immediately — thesnortuser cannot read the config/rules or write/var/log/snort;journalctl -u snort3 -n 30shows the permission error. Also check the-iinterface exists at boot (predictable names).- Very high CPU — too many rules for the traffic volume, or Hyperscan not compiled in (
snort --help-config search_enginelists available engines). Start with the community set, disable categories you do not need, then add. WARNING: No preprocessors configured for policy 0— harmless on 3.x; it refers to legacy 2.9 terminology.- Ubuntu's
apt install snortasks for HOME_NET and installs 2.9.x — that is the legacy branch; itssnort.confand rules are not compatible with anything in this guide. Remove it (sudo apt purge snort snort-common snort-rules-default) if you installed it by accident.
Summary
- Build libdaq, then Snort 3, from source on Ubuntu (
configure_cmake.sh,make,make install,ldconfig). - Disable GRO/LRO and enable promiscuous mode on the capture NIC, persistently.
- Set
HOME_NET,RULE_PATHand theips.includeinsnort.lua; validate with-T. - Install the community rules and a local test rule (SID ≥ 1,000,000).
- Run with
-A alert_fast -s 65535 -k none, confirm the test rule fires, then install the systemd unit. - Automate rule updates with PulledPork 3 and move to the registered rule set.
Related Resources
- How to install and use tcpdump — confirm what is on the wire when Snort is quiet
- Netstat monitoring — the connections and listening ports on the host Snort protects
- Port scanner — generate a controlled scan against your own host to see Snort's scan-detection rules fire
- Server monitoring — Snort is CPU-hungry under load; watch the sensor host itself