Suricata on Ubuntu 24.04 LTS on Azure
This image ships Suricata 8.0.6 on Ubuntu 24.04 LTS, ready to inspect traffic from the first boot of every deployed virtual machine. Suricata is installed unmodified from the Suricata project's own apt repository, so the engine stays patchable through the normal apt path for the life of the release.
Suricata is a high performance network threat detection engine. It reads frames off a network interface, reassembles the flows they belong to, evaluates them against a signature set, and writes alerts and rich protocol metadata to a JSON event log. It is an intrusion detection system (IDS), an intrusion prevention system (IPS) when placed inline, and a network security monitor that records what happened on the wire even when nothing matched.
What this sensor can and cannot see on Azure
Read this section before you deploy. It is the difference between a sensor that does what you think it does and one that quietly does not.
Suricata's core mechanism works exactly as designed on Azure. The engine inspects the packets it is given, and on an Azure virtual machine it is genuinely given this machine's traffic. That is not an assumption: it was verified during the build of this image, with a real signature firing on real traffic captured from the network interface.
What Azure changes is not the mechanism but the visibility scope. An Azure virtual network interface receives only the frames addressed to it. The software defined network does not flood traffic to every host, there is no promiscuous mode that would let one machine observe a neighbour's traffic, and Azure Virtual Network TAP, which would have provided a packet mirror to subscribe to, never reached general availability. So this appliance cannot passively monitor a subnet the way a physical network tap or a switch SPAN port can. No configuration of this image, or any other Suricata image, changes that.
Three deployment topologies are real, and this image supports all three:
| Topology | What it sees | Configuration needed |
|---|---|---|
| Host sensor (default) | This virtual machine's own inbound and outbound traffic | None. Works on first boot. |
| Inline network virtual appliance | Everything you route through this machine | IP forwarding plus a user defined route. See section 7. |
| Offline analysis | Any packet capture you bring to it | None. See section 6. |
The host sensor default is genuinely useful: it protects the machine it runs on, which is exactly what you want on a jump box, a bastion, a public facing web server or any workload whose traffic you want a second opinion on. The inline topology is the only honest way to cover other machines, and it is a first class Azure pattern rather than a workaround.
What makes this image different
The image contains no signature ruleset at all. Most IDS images bake a ruleset in at build time, which means the threat intelligence is already stale on the day you deploy, and an IDS with stale rules is worse than no IDS: it reports healthy while missing everything published since the image was captured. This image ships the engine only. A first boot service fetches a current ruleset onto your virtual machine directly from its provider, and a daily timer keeps it current for the life of the machine.
There are no credentials anywhere in this image, because the product has none. Suricata has no login, no web interface, and no management port that listens on the network. It binds nothing. It is controlled locally through a root owned unix socket, and administered over SSH with the key you supplied at deployment. There is no default password to rotate and nothing to leak.
The engine refuses to start until it has been configured for your virtual machine. The shipped configuration is a template: the network it should treat as home, and the interface it should watch, are facts about your machine that cannot be known at build time. Two independent mechanisms enforce this, so the engine can never run on values left over from the build.
No traffic from the build survives. A network sensor does not merely leak configuration if it is captured carelessly, it leaks other people's traffic. The build of this image is torn down before capture: the event log, every rule file, all rule update state and any packet capture are removed, and the configuration is restored to the template.
1. Deploy the virtual machine
In the Azure portal, search the Marketplace for Suricata on Ubuntu 24.04 LTS by cloudimg and select Create. Choose your subscription, resource group and region, set the authentication type to SSH public key and the username to azureuser, then review and create.
To deploy from the Azure CLI instead:
az vm create \
--resource-group my-resource-group \
--name my-suricata-vm \
--image cloudimg:suricata-ubuntu-24-04:suricata-ubuntu-24-04:latest \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
Suricata needs no inbound port of its own, so nothing beyond SSH is opened. The sensor listens on no network port at all.
Allow SSH from your own address only, never from the whole internet:
az vm open-port --resource-group my-resource-group --name my-suricata-vm \
--port 22 --source-address-prefixes "$(curl -s https://api.ipify.org)/32"
2. Connect to the virtual machine
ssh azureuser@<vm-ip>
3. Confirm the sensor is running
First boot configures the engine for your machine and fetches a current ruleset. On a Standard_B2s this takes a minute or two. Confirm it finished and the engine is live:
sudo systemctl is-active suricata
sudo systemctl is-active suricata-firstboot
Both report active. The engine is running with a configuration derived from your machine, not from the build.

Suricata is a passive sensor and binds no network port. You can confirm that it has opened nothing:
sudo ss -lntup | awk '/suricata/' | wc -l
This reports 0. The only management surface is a unix socket on the filesystem, readable by root alone.
(awk is used rather than grep deliberately: grep exits non zero when it finds no match, so under set -o pipefail the pipeline would report failure on the very result you want to see here, zero. awk prints the same count and exits cleanly.)
Your machine's own facts, recorded at first boot, are in a plain note. It holds no secrets, because there are none:
sudo cat /root/suricata-instance.txt
4. Confirm the ruleset is current
The ruleset was fetched onto this machine at first boot, not baked into the image. Ask the running engine what it actually loaded:
sudo suricatasc -c ruleset-stats
You will see tens of thousands of rules loaded and zero failed. Count them on disk as well, and check when they arrived:
wc -l < /var/lib/suricata/rules/suricata.rules
stat -c '%y' /var/lib/suricata/rules/suricata.rules
The timestamp is the first boot of your machine. That is the point: the threat intelligence is as fresh as your deployment, not as old as the image.

A timer refreshes the ruleset daily and reloads the engine without dropping it:
systemctl list-timers suricata-update.timer --no-pager
5. Prove the sensor actually detects something
A service reporting active proves very little about an IDS. What matters is whether the whole chain works: capture off the interface, evaluation against the ruleset, and an alert written to the event log. Prove it end to end.
Ask the engine whether it is genuinely reading packets off the wire:
sudo suricatasc -c dump-counters | python3 -c 'import sys,json; print("packets captured:", json.load(sys.stdin)["message"]["capture"]["kernel_packets"])'
A number greater than zero means the engine is reading live frames, not merely running.
Now trigger a real signature. The following emits a single packet whose payload matches a well known rule, the classic check for a command response revealing a root shell. It is addressed to 192.0.2.1, an address reserved by RFC 5737 for documentation and examples, so the packet is never routed anywhere and nothing outside your machine is contacted. Suricata sees it on the way out:
python3 -c 'import socket; s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM); s.sendto(b"uid=0(root) gid=0(root) groups=0(root)\n", ("192.0.2.1", 9)); s.close()'
sleep 8
sudo grep '"signature_id":2100498' /var/log/suricata/eve.json | tail -1 | python3 -m json.tool | head -20
You get a real alert record: the signature that matched, its severity and category, the addresses and ports involved, and a timestamp. That is the full pipeline working on your machine.

Every alert, and a great deal of protocol metadata besides, is written to /var/log/suricata/eve.json as one JSON object per line. Follow it live:
sudo tail -f /var/log/suricata/eve.json | python3 -c 'import sys,json
for line in sys.stdin:
e = json.loads(line)
if e.get("event_type") == "alert":
print(e["timestamp"], e["alert"]["signature"])'
Press Ctrl+C to stop.
6. Analyse a packet capture offline
Suricata does not need live traffic. Point it at a capture taken anywhere, including from a machine that is not in Azure at all, and it will evaluate the same ruleset against it. This is the fastest way to triage an incident.
sudo mkdir -p /tmp/offline
sudo timeout 20 tcpdump -i any -c 200 -w /tmp/offline/sample.pcap 2>/dev/null || true
sudo suricata -r /tmp/offline/sample.pcap -l /tmp/offline
sudo head -3 /tmp/offline/eve.json
The results land in /tmp/offline, entirely separate from the live sensor's own log.
7. Deploy inline to inspect other machines
This is the only way to see traffic that is not your own. You route a subnet's traffic through this virtual machine, which is a supported Azure pattern for a network virtual appliance.
There are three parts. First, allow the machine's network interface to forward traffic that is not addressed to it:
az network nic update --resource-group my-resource-group \
--name my-suricata-vmVMNic --ip-forwarding true
Second, enable forwarding in the guest and make it survive reboot:
sudo sysctl -w net.ipv4.ip_forward=1
echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-suricata-forward.conf
Third, create a route table that sends the protected subnet's traffic to this machine as the next hop, and associate it with that subnet:
az network route-table create --resource-group my-resource-group --name suricata-rt
az network route-table route create --resource-group my-resource-group \
--route-table-name suricata-rt --name via-suricata \
--address-prefix 0.0.0.0/0 --next-hop-type VirtualAppliance \
--next-hop-ip-address <suricata-private-ip>
Traffic from that subnet now traverses this machine, and Suricata inspects it. Widen the home network to match what you are protecting by editing vars.address-groups.HOME_NET in /etc/suricata/suricata.yaml, then reload:
sudo systemctl reload suricata
Size the machine for the throughput you are routing. Standard_B2s is right for a host sensor; an inline appliance carrying a subnet's traffic wants more cores and accelerated networking.
To move from detection to prevention (IPS), route the forwarded traffic through NFQUEUE and run Suricata in inline mode. Do this only once detection is behaving as you expect on your traffic: in IPS mode a false positive drops real packets.
8. Scanning scope and authorisation
Monitor only networks you own or are explicitly authorised to monitor. Traffic inspection captures the content of communications, and in an inline deployment it inspects the traffic of every machine whose route you have redirected. Make sure that is intended, that you have authority over those machines, and that it is consistent with your obligations to the people whose traffic they carry. Alerts and metadata in /var/log/suricata/eve.json may themselves contain sensitive material and should be treated as such.
9. Security posture
The appliance ships with no credentials, because Suricata has none: there is no login, no web interface and no listening management port. Administration is over SSH with your own key.
The engine cannot start on build time values. The configuration shipped in the image is a template holding placeholders that the engine itself rejects, and two independent mechanisms enforce that it is replaced with your machine's facts first: the service requires the first boot unit to have succeeded, and a preflight check re-runs on every start, refusing to launch if any placeholder survives, if the first boot marker is missing, or if no ruleset is present. An IDS with no signatures reporting healthy is precisely the failure this prevents.
Confirm that nothing from the build survived onto your machine:
sudo test ! -e /usr/share/doc/cloudimg/build-residue && echo "no build residue"
stat -c '%y' /var/log/suricata/eve.json
The event log's timestamp is from your machine's first boot. There is no build time alert history, no packet capture and no stale ruleset in the image.

10. Logs and troubleshooting
The engine's own log, distinct from the event log:
sudo tail -20 /var/log/suricata/suricata.log
If the engine will not start, the preflight check explains why in the journal:
sudo journalctl -u suricata -n 30 --no-pager
sudo journalctl -u suricata-firstboot -n 30 --no-pager
The most common cause is a first boot that could not reach the ruleset provider. First boot needs outbound HTTPS to fetch a current ruleset; a machine deployed with no outbound internet access will report that plainly rather than starting with no signatures.
Validate a configuration change before applying it:
sudo suricata -T -c /etc/suricata/suricata.yaml
11. Licence
Suricata is distributed under the GNU General Public License, version 2. The licence as published by the Suricata project is on the image:
sudo head -20 /usr/share/doc/suricata/copyright
cloudimg installs Suricata unmodified from the Suricata project's own apt repository and has made no change to the program. The complete corresponding source for the exact package installed here is published by that same repository, and a written offer for it, valid three years, ships on the image:
sudo cat /usr/share/doc/cloudimg/SURICATA-GPL-2-WRITTEN-OFFER.txt
The signature ruleset is not distributed by cloudimg. It is fetched by your machine at first boot directly from Emerging Threats and is covered by that provider's own licence terms, which are published with the ruleset.
Support
For help with this image, contact support@cloudimg.co.uk. For questions about Suricata itself, see the Suricata documentation.