Ubuntu 26.04 LTS Networking Tools on Azure User Guide
Overview
This guide covers the deployment and configuration of Ubuntu Server 26.04 LTS Networking Tools on Microsoft Azure using cloudimg's pre configured virtual machine image from the Azure Marketplace.
Ubuntu is a widely used Linux distribution produced by Canonical. Version 26.04 is a long term support (LTS) release, with standard security maintenance to 2031. What makes this image different from the standard Ubuntu Server 26.04 LTS image is the package profile: a named, version pinned set of 61 networking packages, every one of them from Ubuntu's own archive, installed and ready. 33 come from main, which carries Canonical's full five year security commitment; 28 come from universe.
Be clear about what this is and what it is not. It is not a router, a firewall appliance, or a security product. It is the standard Ubuntu Server image with a documented toolbox already on it, saving you the apt install list you would otherwise type on every jump host, bastion or diagnostic VM. There is no third party software, no vendor repository, and nothing on the image that Canonical does not publish.
Every daemon the profile carries is installed but disabled — nftables, OpenVPN, FRR, BIRD, lldpd, vnstat, conntrackd and iperf3 are all present and all switched off. A freshly deployed machine listens on port 22 and nothing else. Turning a service on is a deliberate act you take, not a default you have to undo.
The image describes itself: a manifest generated from its own package database ships at /usr/share/cloudimg/ubuntu-26-04-pkg-networking.manifest, naming every package, its version, its component, and what was deliberately left out and why.
What's included:
- Ubuntu Server 26.04 LTS with 61 networking packages preinstalled — 33 from
main, 28 fromuniverse, every one from the Ubuntu archive - Capture and analysis:
tcpdump,tshark,ngrep,tcpflow,ssldump - Reachability and paths:
ping,tracepath,traceroute,tcptraceroute,mtr,fping,httping,ndisc6 - Interfaces, links and bonding:
iproute2,net-tools,ethtool,bridge-utils,vlan,ifenslave,ethstatus - Filtering and connection tracking:
nftables,iptables,ipset,ebtables,arptables,conntrack,conntrackd,ufw - Tunnels and routing:
wireguard-tools,openvpn,frr,bird2 - Naming and discovery:
bind9-dnsutils(dig),bind9-host,dnstracer,whois,ldap-utils,lldpd,snmp - Throughput and live monitoring:
iperf3,iftop,nload,bmon,nethogs,ifstat,vnstat,iptraf-ng - Addressing maths:
ipcalc,ipcalc-ng,sipcalc,ipv6calc - Sockets and transfer:
netcat-openbsd,socat,curl,wget,openssh-client,inetutils-telnet - A shipped manifest derived from the image's own package database, so the description cannot drift from what is installed
- Every available security update applied at build time, with
unattended-upgradesarmed so the machine keeps patching itself - AppArmor in enforcing mode, Gen2 Hyper V support, and 24/7 cloudimg support
What's deliberately NOT included:
- Offensive and dual use tooling.
nmap,hping3,masscan,zmap,ettercap,aircrack-ng,sqlmap,hydraand their relatives are excluded by design. They are yours to install if your work needs them; they are not something a general purpose image should ship by default, and they are a recurring source of antivirus false positives on cloud marketplaces. ldnsutils. Its only fix for one open CVE on Ubuntu 26.04 (CVE-2026-10846) is published to Ubuntu Pro ESM, which means a machine without a Pro subscription could never patch it. Every package on this image can be patched for free.iptables-persistentandnetfilter-persistent. Ubuntu'sufwpackage, which ships on the base image, declares a hard incompatibility with both. Keepingufw— the tool inmain, with the longer support commitment — was the better trade. Useufw, or save and restore rules yourself withnft -f.arping(the standalone package). It conflicts withiputils-arping, which is inmain. You havearpingthe command, from themainpackage.
Platform: Microsoft Azure (Gen2 Hyper V, x64)
Default user: azureuser
Security posture
This image ships with no known credential. There is no default password and no baked in SSH key:
- The root account password is locked, so no one can log in as root with a password.
PermitRootLoginis set tono, so root has no SSH login path at all.PasswordAuthenticationis disabled, so every login is by key.- The only key that works is the public key you supply when you create the virtual machine. Azure injects it into
azureuserat first boot, so no two machines you launch ever share a secret. - The machine identity and the SSH host keys are regenerated uniquely on every instance.
- Every daemon the profile carries ships disabled and stopped. The off box listening set is exactly
{22}. - AppArmor is left enabled and enforcing, the Ubuntu default.
- No package on the image depends on Ubuntu Pro to receive its security fixes.
Prerequisites
Before deploying this image, ensure you have:
- An active Microsoft Azure subscription
- Access to the Azure Portal or Azure CLI
- An SSH key pair for Linux VM access
- Familiarity with Azure VM management
Recommended VM Size: Standard_B2s (2 vCPU, 4 GB RAM) or larger.
Disk size: the image ships as a 30 GiB OS disk. The profile itself adds roughly 270 MB, so a stock deployment uses about 3 GB and leaves around 25 GB free.
Step 1: Deploy the Virtual Machine
Option A: Azure Portal
- Sign in to the Azure Portal
- Search the Marketplace for Ubuntu 26.04 LTS Networking Tools and select the cloudimg offering
- Click Create
- Choose your subscription, resource group and region
- Set the VM size to
Standard_B2sor larger - Under Administrator account, choose SSH public key, leave the username as
azureuser, and paste your public key - Under Inbound port rules, allow SSH (22) only, and restrict the source to your own management address range
- Review and create
Option B: Azure CLI
az vm create \
--resource-group my-resource-group \
--name ubuntu-nettools \
--image cloudimg:ubuntu-26-04-pkg-networking:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_rsa.pub \
--public-ip-sku Standard
Step 2: Connect via SSH
ssh azureuser@<vm-ip>
Replace <vm-ip> with your virtual machine's public IP address.
Step 3: Confirm the release and the profile
Check you have the release you expect:
grep -E '^(PRETTY_NAME|VERSION|VERSION_ID|ID)=' /etc/os-release
uname -srm
Expected output:
PRETTY_NAME="Ubuntu 26.04.1 LTS"
VERSION_ID="26.04"
VERSION="26.04.1 LTS (Resolute Raccoon)"
ID=ubuntu
Linux 7.0.0-1012-azure x86_64

Now confirm the profile. The split between main and universe is the thing that decides how long each package is supported:
awk -F'\t' 'NF>=3{print $3}' /usr/share/cloudimg/ubuntu-26-04-pkg-networking.manifest | sort | uniq -c
Expected output:
33 main
28 universe

Step 4: Read the shipped manifest
The manifest is generated from the image's own package database at build time, so it cannot drift from what is actually installed:
head -8 /usr/share/cloudimg/ubuntu-26-04-pkg-networking.manifest
Expected output (the generation timestamp will differ):
# cloudimg ubuntu-26-04-pkg-networking — shipped package profile
# Derived from the dpkg database at build time. Do not hand-edit.
# generated: 2026-09-18T19:09:05Z
# series: resolute (Ubuntu 26.04 LTS)
#
# [main] — Canonical five-year security commitment
iproute2 6.19.0-1ubuntu1.1 main
net-tools 2.10-2ubuntu1 main
List the main half, with the versions you actually have:
awk -F'\t' 'NF>=3 && $3=="main"{printf "%-22s %s\n",$1,$2}' /usr/share/cloudimg/ubuntu-26-04-pkg-networking.manifest | head -8
Expected output:
iproute2 6.19.0-1ubuntu1.1
net-tools 2.10-2ubuntu1
tcpdump 4.99.6-1
mtr-tiny 0.95-1.1ubuntu2
ethtool 1:6.19-1
iputils-ping 3:20250605-1ubuntu1
iputils-tracepath 3:20250605-1ubuntu1
iputils-arping 3:20250605-1ubuntu1
Every package resolves to the Ubuntu archive. There is no third party repository on this image:
apt-cache policy tcpdump
Expected output:
tcpdump:
Installed: 4.99.6-1
Candidate: 4.99.6-1
Version table:
*** 4.99.6-1 500
500 http://azure.archive.ubuntu.com/ubuntu resolute/main amd64v3 Packages
100 /var/lib/dpkg/status
The only source offering this package is resolute/main on Ubuntu's own archive. Every package on the image answers the same way.
Step 5: Confirm nothing is listening
This is the property that makes the image safe to deploy as it stands. Every service is present and switched off:
systemctl list-unit-files nftables.service frr.service lldpd.service openvpn.service vnstat.service bird.service conntrackd.service iperf3.service
Expected output:
UNIT FILE STATE PRESET
bird.service disabled enabled
conntrackd.service disabled enabled
frr.service disabled enabled
iperf3.service disabled enabled
lldpd.service disabled enabled
nftables.service disabled enabled
openvpn.service disabled enabled
vnstat.service disabled enabled
8 unit files listed.
Note the two columns. PRESET is what Ubuntu would normally do with each unit — enable it. STATE is what this image actually ships — disabled. That gap is the deliberate choice this product makes.
And the listening set:
ss -tln | awk '$1=="LISTEN"{print $1, $4}' | sort -u
Expected output:
LISTEN 0.0.0.0:22
LISTEN 127.0.0.53%lo:53
LISTEN 127.0.0.54:53
LISTEN [::]:22
The only socket reachable from the network is SSH on port 22. The two entries on 127.0.0.53 and 127.0.0.54 are systemd-resolved, Ubuntu's stock local DNS stub; they are bound to loopback and cannot be reached from outside the machine.

Step 6: Check the patch level and the Ubuntu Pro position
The image is fully patched at build time, including Ubuntu's phased updates, which a plain dist-upgrade silently holds back:
apt-mark showhold
sudo apt-get update -qq
sudo apt-get -s -o APT::Get::Always-Include-Phased-Updates=true dist-upgrade | grep -c '^Inst ' || true
apt-mark showhold prints nothing when no package is held. The count is the number of updates still pending, and will grow over time as Canonical publishes new ones — unattended-upgrades applies them for you.
More importantly, nothing on this image needs an Ubuntu Pro subscription to be patched. The image ships unattached, and every package was checked at build time:
sudo pro security-status --format=json | python3 -c "import json,sys;d=json.load(sys.stdin);s=d['summary'];print('esm-infra updates:',s.get('num_esm_infra_updates'));print('esm-apps updates:',s.get('num_esm_apps_updates'));print('installed packages:',s.get('num_installed_packages'))"
Expected output:
esm-infra updates: 0
esm-apps updates: 0
installed packages: 790
Both counters are zero, which is the point. A package whose only security fix is published to Ubuntu Pro ESM would show up here — and would be unpatchable on a machine without a subscription. That is exactly why ldnsutils is not on this image.

Step 7: Use the toolbox
Everything below runs as shipped, with no service to start.
Look at your interfaces:
ip -brief address show
ip -brief link show
Expected output (your addresses will differ):
lo UNKNOWN 127.0.0.1/8 ::1/128
eth0 UP 10.0.0.12/24 metric 100 fe80::72a8:a5ff:fe43:cce/64
lo UNKNOWN 00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
eth0 UP 70:a8:a5:43:0c:ce <BROADCAST,MULTICAST,UP,LOWER_UP>
Capture live traffic:
sudo tcpdump -i any -c 3 -n -q
Expected output (the addresses and ports will differ):
17:28:18.468687 eth0 Out IP 10.0.0.12.54894 > 168.63.129.16.80: tcp 0
17:28:18.469350 eth0 In IP 168.63.129.16.80 > 10.0.0.12.54894: tcp 0
3 packets captured
34 packets received by filter
0 packets dropped by kernel
168.63.129.16 is Azure's own platform endpoint (the "wire server") — seeing it here is normal.
Query DNS:
dig +short A www.cloudimg.co.uk | head -3
dig +noall +answer NS ubuntu.com | head -2
Expected output:
d14bmdyrx9dte8.cloudfront.net.
3.167.88.45
3.167.88.56
ubuntu.com. 113 IN NS ns3.canonical.com.
ubuntu.com. 113 IN NS ns1.canonical.com.
Look up who owns an address:
whois -H 1.1.1.1 | grep -iE '^(netname|descr):' | head -3
Expected output:
netname: APNIC-LABS
descr: APNIC and Cloudflare DNS Resolver project
descr: Routed globally by AS13335/Cloudflare
Measure throughput. iperf3 normally needs a server at the far end, but you can prove the tool works against your own loopback before you point it anywhere:
(iperf3 -s -1 -p 5399 -B 127.0.0.1 >/dev/null 2>&1 &) ; sleep 1; iperf3 -c 127.0.0.1 -p 5399 -t 1 -f m | tail -4
Expected output (the rate depends on your VM size):
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-1.00 sec 2.88 GBytes 24687 Mbits/sec 0 sender
[ 5] 0.00-1.00 sec 2.88 GBytes 24684 Mbits/sec receiver
iperf Done.
The -1 flag makes the server exit after one connection, so nothing is left listening.
Inspect the packet filter:
sudo nft list tables
Expected output:
table ip security
That table is created by the iptables-nft compatibility layer and carries no filtering rules of its own. No firewall policy is applied on this image — Azure Network Security Groups are doing that job in front of the VM. Configure ufw or nft if you want a host firewall as well.
Step 8: Turn a service on when you want it
Nothing starts by itself. When you do want a daemon, enable it explicitly:
# Example only — run these when you actually want the service.
sudo systemctl enable --now nftables.service # load /etc/nftables.conf at boot
sudo systemctl enable --now vnstat.service # keep long term interface counters
sudo systemctl enable --now lldpd.service # discover neighbours over LLDP
Two things worth knowing before you enable anything:
- Open the port in your Network Security Group too. The image does not filter, but Azure does. A service that is running and still unreachable is almost always an NSG rule, not the VM.
tsharkcapture as a non-root user needs your account added to thewiresharkgroup (sudo usermod -aG wireshark azureuser, then log out and back in). Runningtsharkundersudoworks without that.
Step 9: IPsec on this image
This image applies the standard cloudimg mitigation for CVE-2026-43284 and CVE-2026-43500 by preventing the kernel's ESP and IP payload compression modules from loading:
cat /etc/modprobe.d/dirtyfrag.conf
Expected output:
install esp4 /bin/false
install esp6 /bin/false
install ipcomp /bin/false
install ipcomp4 /bin/false
install ipcomp6 /bin/false
install rxrpc /bin/false
This does not affect WireGuard or OpenVPN, which are the two tunnel implementations on this image — neither uses kernel ESP. It does mean that if you install strongswan or libreswan and try to terminate an IPsec tunnel on this machine, the kernel will refuse to load the modules it needs. If that is your use case, remove the file and reboot:
# Only if you are terminating IPsec ON this VM.
sudo rm /etc/modprobe.d/dirtyfrag.conf
sudo reboot
Traffic through an Azure VPN Gateway is unaffected — the gateway terminates IPsec, not your VM.
Common Use Cases
- Diagnostic jump host. Put one of these in a VNet and you have capture, DNS, path and throughput tools ready when something breaks, without installing packages during an incident.
- Bastion with a toolbox. The image listens only on SSH, so it is safe to place at the edge of a subnet with an NSG in front of it.
- Connectivity validation in CI. Drive
dig,fping,httping,socatandiperf3from a pipeline to assert a landing zone is wired the way the design says. - Network lab.
frrandbird2are both present for BGP and OSPF work, disabled until you configure them. - Golden base for a network appliance. Start from a known, documented package set rather than a bare image plus a long
apt installline.
Troubleshooting
Cannot connect via SSH
Check your Network Security Group allows inbound TCP 22 from your address, that you are connecting as azureuser, and that you are offering the private key matching the public key you supplied at deployment. Password login is disabled by design, and root cannot log in at all.
traceroute and mtr show ??? for every hop
This is expected on Azure, not a fault on the image. The Azure fabric does not return ICMP time exceeded messages for intermediate hops, so hop by hop tools cannot see the path inside the platform network. tracepath behaves the same way. Use tcpdump, dig, httping and iperf3 for reachability instead, and Azure's own Network Watcher for path analysis.
A service is installed but not running
That is the design — every daemon ships disabled. systemctl enable --now <service> starts it and makes it survive a reboot. Check systemctl status <service> and journalctl -u <service> if it does not come up.
nmap is not installed
It is excluded deliberately, along with the other offensive and dual use tools. Install it yourself if your work needs it: sudo apt install nmap.
Package manager issues
sudo apt-get update
sudo apt-get -f install
If apt reports held packages, apt-mark showhold will name them; there are none on a freshly deployed image.
A service is blocked and the logs mention AppArmor
AppArmor is enforcing, as on stock Ubuntu. sudo aa-status lists the loaded profiles, and journalctl -k | grep apparmor shows what was denied. Prefer fixing the profile over disabling AppArmor.
Important Notes
- This is the standard Ubuntu Server 26.04 LTS image with a documented package profile added. It is not a router, firewall or security appliance, and cloudimg makes no such claim for it.
- Every package comes from the Ubuntu archive. Nothing on the image comes from a third party repository, and nothing depends on an Ubuntu Pro subscription for its security fixes.
- Ubuntu 26.04 LTS has standard security maintenance to May 2031. Packages in
universeare community maintained; the manifest records which half each package came from so you can make that judgement yourself. - The image applies security updates automatically through
unattended-upgrades, as stock Ubuntu does. ufwis present but inactive, exactly as on the standard Ubuntu Server image. Azure Network Security Groups filter traffic in front of the VM.- Ubuntu is a trademark of Canonical Ltd. cloudimg is not affiliated with or endorsed by Canonical.
Support
cloudimg provides 24/7 support for this image. Contact support through the Azure Marketplace listing or at www.cloudimg.co.uk.