Rocky Linux 8 Minimal on Azure User Guide
Overview
This guide covers the deployment and configuration of Rocky Linux 8 Minimal on Microsoft Azure using cloudimg's pre configured virtual machine image from the Azure Marketplace.
Rocky Linux is a community driven enterprise Linux distribution, built by the Rocky Enterprise Software Foundation to be binary compatible with Red Hat Enterprise Linux 8. This is the Minimal edition: the desktop era web console, the tuning daemon, the support report collector, the boot splash and the firmware bundle for physical hardware an Azure guest never has are all removed, leaving a smaller installed package set and a smaller surface to patch and audit. Unlike the cloudimg Rocky Linux 8.10 image, which is pinned to a single point release, this listing tracks whichever 8.x point release is current at build time, so it always reports the latest Rocky 8 stream. Rocky Linux 8.10 is the final minor release in the 8 series and remains on the RHEL 8 maintenance support stream until May 2029, so this listing continues to receive security backports even though no further point release will follow it.
What's included:
- Rocky Linux 8, binary compatible with RHEL 8, Minimal edition
- 425 installed packages on a fresh build, roughly 1.3 GB on disk — cockpit, tuned, sos, plymouth, linux-firmware and the GeoIP data files removed, with everything the platform needs to boot, network, authenticate and update itself kept intact
- Every available update applied at build time, verified with a zero pending check
- Unattended updates already armed, so the machine keeps patching itself
- Azure Linux Agent (waagent) and cloud-init for Azure integration
- Chronyd for NTP time synchronisation
- SELinux in enforcing mode, both at runtime and persisted for the next boot, with the policy package verified present
- BaseOS, AppStream and Extras repositories enabled, with signature checking on
- Exactly one externally reachable port: SSH on 22
- Gen2 Hyper V virtual machine support
- 24/7 cloudimg support
Platform: Microsoft Azure (Gen2 Hyper V)
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.
PasswordAuthenticationis disabled in the SSH daemon, so every login is by key.KbdInteractiveAuthenticationis also disabled, closing the other password path.PermitRootLoginis set toprohibit-password, so root cannot be reached with a password even if one were later set.- 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. - No SSH host keys are baked into the image. Each machine generates its own at first boot, so two machines built from this image never share a host identity.
/etc/machine-idships empty and is regenerated per machine.- SELinux is left in enforcing mode with the targeted policy loaded, the Rocky Linux default.
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.
Step 1: Deploy the Virtual Machine
Option A: Azure Portal
- Navigate to the Azure Marketplace and search for "Rocky Linux 8 Minimal cloudimg"
- Select the image and click Create
- Configure the basics:
- Subscription: Select your Azure subscription
- Resource Group: Create new or select existing
- Virtual Machine Name: Enter a name for your VM
- Region: Select your preferred Azure region
- Size:
Standard_B2srecommended - Under Administrator Account, select SSH public key and enter your key
- Under Inbound Port Rules, allow SSH (port 22)
- Click Review + Create, then Create
Option B: Azure CLI
az vm create \
--resource-group myResourceGroup \
--name my-rocky-8-minimal-vm \
--image cloudimg:rocky-8-minimal:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
Step 2: Connect via SSH
Run these on your own workstation, not on the VM. Find the public IP, then connect:
az vm show --resource-group myResourceGroup --name my-rocky-8-minimal-vm --show-details --query publicIps -o tsv
ssh azureuser@<vm-ip>
There is no password to enter. If SSH asks you for one, the key you supplied at create time is not the key your client is offering.
Step 3: Confirm the release
Check the Rocky Linux release and package count:
cat /etc/rocky-release
grep -E '^(NAME|VERSION|ID|PLATFORM_ID)=' /etc/os-release
uname -rm
rpm -qa | wc -l
Expected output:
Rocky Linux release 8.10 (Green Obsidian)
NAME="Rocky Linux"
VERSION="8.10 (Green Obsidian)"
ID="rocky"
PLATFORM_ID="platform:el8"
4.18.0-553.153.1.el8_10.x86_64 x86_64
425

This listing floats forward with the Rocky 8 stream: it always ships whichever 8.x point release is current when the image is built, rather than being pinned to a single minor like the cloudimg Rocky Linux 8.10 image. In practice 8.10 is the terminal minor of the RHEL 8 lifecycle, so this listing and the pinned 8.10 image report the same release string today, but this one keeps floating if that ever changes.
Step 4: Check the patch level
The image is fully updated at build time. dnf check-update returns exit code 100 when updates are pending and 0 when none are:
sudo dnf check-update
echo "check-update exit code: $?"
Confirm no reboot is outstanding. needs-restarting -r returns 0 when nothing requires a restart:
sudo dnf needs-restarting -r
echo "needs-restarting exit code: $?"
List the enabled repositories to confirm your update path is intact:
dnf repolist --enabled
Expected output:
repo id repo name
appstream Rocky Linux 8 - AppStream
baseos Rocky Linux 8 - BaseOS
extras Rocky Linux 8 - Extras

PowerTools (powertools) is not enabled on this image. It carries developer and build time packages that most server workloads do not need. Enable it yourself if you need it:
echo "powertools state: $(dnf repolist --all 2>/dev/null | grep -c '^powertools ')"
To turn it on, run sudo dnf config-manager --set-enabled powertools. RHEL 9 renamed this repository to crb — on this RHEL 8 compatible image the name is still powertools.
Package signatures are verified on every install: no repository on this image sets gpgcheck=0.
Step 5: Unattended updates are already armed
This image does not just ship patched, it keeps patching itself. dnf-automatic is installed and configured to apply updates, and its timer is enabled so systemd starts it automatically on every boot:
systemctl is-enabled dnf-automatic.timer
systemctl is-active dnf-automatic.timer
grep -E '^(upgrade_type|download_updates|apply_updates)' /etc/dnf/automatic.conf
Expected output:
enabled
active
upgrade_type = default
download_updates = yes
apply_updates = yes
upgrade_type is deliberately set to default rather than security. The security only mode resolves against errata metadata, and where that metadata is not published a security only policy silently resolves to nothing and applies no updates at all. Setting default means every available update is applied, which cannot quietly do nothing.
If you would rather control the schedule yourself, disable the timer and patch on your own cadence:
echo "to take manual control: sudo systemctl disable --now dnf-automatic.timer"
To patch by hand at any time, run sudo dnf upgrade -y, then reboot with sudo systemctl reboot if a new kernel was installed.
Step 6: Verify the security posture
Confirm SELinux is enforcing with its policy loaded, root is locked, SSH is key only, and there is no swap:
getenforce
sestatus | grep -E '^(SELinux status|Loaded policy name|Current mode)'
grep -E '^[[:space:]]*SELINUX=' /etc/selinux/config
sudo passwd -S root
sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication)'
swapon --show
Expected output:
Enforcing
SELinux status: enabled
Loaded policy name: targeted
Current mode: enforcing
SELINUX=enforcing
root LK 2009-12-22 -1 -1 -1 -1 (Alternate authentication scheme in use.)
permitrootlogin without-password
passwordauthentication no
kbdinteractiveauthentication no
(swapon --show returns nothing — that is expected, see Step 7.)

without-password is how OpenSSH reports the prohibit-password setting. Both names mean the same thing: root may not authenticate with a password.
Both the runtime SELinux mode and the persisted /etc/selinux/config value are checked, because a runtime setting that is not persisted would silently revert on your next reboot. The sestatus policy name check confirms the policy is genuinely loaded, not merely that the runtime mode string reads Enforcing.
Step 7: Verify Azure integration and resources
Confirm the Azure Linux Agent, cloud-init and time synchronisation are healthy, and check your resources:
systemctl is-active waagent
systemctl is-enabled waagent
cloud-init --version
systemctl is-active chronyd
df -h /
free -h
Note that free -h reports 0B of swap. That is deliberate. Azure manages swap on the ephemeral resource disk through waagent rather than on the OS disk, and a swap file baked into a Marketplace image fails certification. Configure swap yourself through waagent if your workload needs it.
Step 8: Networking and open ports
The Azure Network Security Group is the control plane for inbound and outbound traffic, and it is the first and usually the only place you need to open a port.
This image is a Minimal build, so firewalld is not installed. That is deliberate: with no host firewall in the way, your NSG rules take effect exactly as written, with no second layer to keep in sync. Confirm what is listening before you open anything:
sudo ss -tlnu
On a fresh machine SSH on port 22 is the only externally bound listener. Chrony appears on 127.0.0.1:323 and [::1]:323, both loopback only and not reachable from the network.
rpcbind is disabled on this image. The stock Rocky cloud image pulls it in because nfs-utils depends on it, which leaves TCP and UDP port 111 open on every interface. NFSv4, the default in Rocky Linux 8, does not use rpcbind at all, so this image disables it and closes the port while keeping nfs-utils installed and fully working for NFSv4 mounts:
echo "rpcbind.socket: $(systemctl is-enabled rpcbind.socket 2>/dev/null || echo disabled)"
rpm -q nfs-utils
If you specifically need NFSv3, which does require the portmapper, turn it back on with one command:
echo "to re-enable NFSv3 support: sudo systemctl enable --now rpcbind.socket"
It is disabled rather than masked precisely so that command works without further steps.
If your policy requires a host firewall as well, install and enable it yourself:
sudo dnf install -y firewalld
sudo systemctl enable --now firewalld
sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --reload
Once firewalld is running, a port must be open in both the Azure NSG and firewalld before traffic reaches your service.
Step 9: What the Minimal edition trims, and what it never touches
This is the same Rocky Linux 8 base as the standard cloudimg images, with packages a headless Azure guest never uses removed. Confirm the trim for yourself:
rpm -qa cockpit-ws cockpit-bridge tuned sos plymouth linux-firmware
echo "(no output above = every trimmed package is genuinely absent)"

| Removed | Why it is safe to remove on Azure |
|---|---|
linux-firmware |
Firmware blobs for physical NICs, GPUs, wireless and storage controllers. An Azure guest's storage and network are the in-kernel Hyper-V synthetic drivers, which load no firmware at all. This is the single largest reduction. |
cockpit-ws, cockpit-bridge |
The web admin console. This is a headless server image with no web UI. |
tuned |
The tuning-profile daemon. Azure images use the platform defaults. |
sos |
The Red Hat support-report collector. Install it yourself if you need it for a support case. |
plymouth |
The graphical boot splash. There is no console to splash to on a cloud VM. |
| GeoIP data files | A bundled dataset unused on a base OS image. |
Nothing the platform needs is touched: systemd, NetworkManager, openssh-server, cloud-init, WALinuxAgent, dnf, sudo, chrony and dnf-automatic all ship exactly as on the standard image, and every removal above is verified on the image before it is captured, not merely intended. SELinux and its policy package are asserted present at every stage of the build, precisely because a package trim that touches the wrong dependency chain is the kind of mistake that would otherwise ship silently.
Step 10: Install software
AppStream carries the application packages. Search it, then install what you need:
dnf search nginx
The 8 series still ships modules for some packages: AppStream can carry several versions of the same language or database as separate streams, so you can pick a version rather than take the default.
dnf module list nginx
Expected output:
Rocky Linux 8 - AppStream
Name Stream Profiles Summary
nginx 1.14 [d] common [d] nginx webserver
nginx 1.16 common [d] nginx webserver
nginx 1.18 common [d] nginx webserver
nginx 1.20 common [d] nginx webserver
nginx 1.22 common [d] nginx webserver
nginx 1.24 common [d] nginx webserver
Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled
Install a package and enable it in the usual way, for example sudo dnf install -y nginx followed by sudo systemctl enable --now nginx.
To add another administrator, create the account with sudo adduser <name>, add it to the wheel group with sudo usermod -aG wheel <name>, then copy your public key into /home/<name>/.ssh/authorized_keys with mode 600 and the .ssh directory mode 700, owned by that user. The image ships with no human accounts at all, so azureuser is the only login until you add one:
getent group wheel
Common Use Cases
- A stripped down, RHEL compatible base for production servers where a smaller package set matters
- A lean foundation for your own applications and container hosts
- Migrating older RHEL 8 compatible workloads without licence cost, minimal footprint edition
Troubleshooting
Cannot connect via SSH
- Verify the VM is in Running state in the Azure Portal
- Check that port 22 is allowed in the Network Security Group
- Ensure you are using the correct username:
azureuser - Verify your SSH key matches the one you supplied at create time. Password login is disabled by design, so a wrong key cannot fall back to a password prompt.
To see which key your client is actually offering, run ssh -v azureuser@<vm-ip> from your workstation and look for the Offering public key lines.
Azure agent not running
systemctl is-active waagent
sudo systemctl enable --now waagent
Package manager issues
Refresh the metadata cache first:
sudo dnf clean all
sudo dnf makecache
If repositories are unreachable, check DNS resolution. This image is minimal, so nslookup and dig are not installed; getent is always present and resolves through the same system resolver:
getent hosts download.rockylinux.org
Install bind-utils if you want dig and nslookup available.
A service is blocked and the logs mention SELinux
SELinux is enforcing on this image. Rather than disabling it, look at what was denied. On a healthy machine there are no recent denials, so the command reports none:
sudo ausearch -m AVC -ts recent 2>/dev/null || echo "no recent AVC denials"
If a denial is genuine, prefer setting the correct file context with semanage fcontext and restorecon, or enabling the relevant boolean with setsebool -P, over turning SELinux off.
Checking for failed services
A healthy machine reports running with nothing failed:
systemctl is-system-running
systemctl list-units --state=failed --no-legend
I need something the Minimal trim removed
Nothing is blocked, only absent by default. cockpit-ws, tuned, sos, plymouth and firewalld all install cleanly from the enabled repositories with a normal sudo dnf install -y <package> if your workload needs them.
Important Notes
Rocky Linux is free and open source, and it is a collection of licences rather than a single one. This image carries 425 installed packages between them declaring 88 distinct licence strings, most commonly LGPLv2+, GPLv2+, MIT, BSD, GPLv3+, GPLv2 and LGPLv3+. Each package's own terms are readable on the machine:
rpm -qa --qf '%{LICENSE}\n' | sort | uniq -c | sort -rn | awk 'NR<=8'
No subscription, licence key or support contract is required for any of it.
Rocky Linux 8.10 is the final minor release of the RHEL 8 family and remains on the maintenance support stream until May 2029. This image tracks the current 8.x point release rather than being pinned to one; if you need a specific, named point release instead, use the cloudimg Rocky Linux 8.10 image.
Support
For assistance with this image, contact cloudimg support:
- Website: www.cloudimg.co.uk
- Product Catalogue: www.cloudimg.co.uk/products
- User Guides: www.cloudimg.co.uk/guides
- SLA: 24 hour response guaranteed