Oracle Linux 10 Minimal on Azure User Guide
Overview
This guide covers deploying and operating Oracle Linux 10 Minimal on Microsoft Azure using cloudimg's pre configured virtual machine image from the Azure Marketplace.
Oracle Linux is a free, enterprise grade Linux distribution built by Oracle to be binary compatible with Red Hat Enterprise Linux 10. Oracle provides the binaries, updates and errata at no cost and permits redistribution, so there is no subscription and no licence key needed to use, patch or resell it.
Oracle Linux 10 Minimal is the minimal package profile variant. No application is preinstalled: the operating system itself is the product. The image keeps Oracle's own @core package group, plus what an Azure virtual machine needs to be provisioned, networked, patched and managed, and removes everything else. On the image this guide was written against that took the package count from 597 in the standard image to 429.
What's included:
- Oracle Linux 10, binary compatible with RHEL 10, on the rolling Oracle Linux 10 repositories
- Both Oracle kernel lines: the Unbreakable Enterprise Kernel Release 8 (booted by default) and the Red Hat Compatible Kernel
- A minimal package profile: Oracle's
@coregroup plus the Azure provisioning path, with a package profile file on the image that lists everything removed - Every available update applied at build time, and again immediately before capture
dnf-automaticinstalled and armed, so the machine keeps applying updates on its own- Azure Linux Agent (waagent), cloud-init and the Hyper-V key value pair daemon for Azure integration
- Chronyd time synchronisation against the Azure host clock
- SELinux in enforcing mode,
firewalldactive, SSH as the only network listener - Gen2 Hyper V virtual machine support
- 24/7 cloudimg support
Platform: Microsoft Azure (Gen2 Hyper V, x64)
Default user: the administrator account you name when you create the VM (azureuser in the examples below)
What "minimal" means on this image
Oracle defines a @core package group, described in its own metadata as a "minimal host installation". Oracle's installer "Minimal Install" environment is actually @core plus @standard, which is larger than a cloud image, so this image uses @core itself as the contract:
- Kept: every Mandatory and Default package in Oracle's
@coregroup, with the packages they depend on or recommend; the Azure provisioning path (cloud-init, WALinuxAgent, azure-vm-utils, the Hyper-V KVP daemon, growpart, LVM tools); chrony; both kernel lines and their firmware; anddnf-automatic. - Removed, because they sit outside
@core: Perl, the LLVM libraries pulled in bybpftool, binutils, fonts, spell checking dictionaries and language packs,man-pages,bind-utils,wget, the GeoIP databases,sos,tuned, the NFS client andrpcbind, the iSCSI initiator,policycoreutils-python-utilsand a handful of small utilities. - Removed, because an Azure VM has no hardware for them: CPU microcode (the Azure host owns it), Bluetooth, the flash chip programmer, the
udisks2desktop disk manager stack, the exFAT tools, the TPM command line tools, X11 keyboard layouts, themdadmsoftware RAID daemon and the legacyinitscripts-rename-devicehelper, plus the few libraries only those packages used.
Everything that was removed is one sudo dnf install <package> away, from the same Oracle repositories that are enabled on the image. Kdump, firewalld, SELinux tooling, fwupd and linux-firmware (which the UEK kernel modules require) all stay.
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, and no account on the image has a usable password.
PasswordAuthenticationand keyboard interactive authentication are disabled in the SSH daemon, so every login is by key.PermitRootLoginisprohibit-password, so root can never be reached with a password.- The only key that works is the public key you supply when you create the virtual machine. Azure injects it into the administrator account you name at first boot.
- SSH host keys,
/etc/machine-idand the cloud-init network profile are removed before capture and regenerated per machine, so no two machines you launch share a host identity. - SELinux is left in enforcing mode, the Oracle Linux default.
rpcbindis not installed, so port 111 is closed. SSH on port 22 is the only service reachable from the network.
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. Oracle Linux 10 requires an x86-64-v3 capable processor, which every current Azure x64 size provides.
Step 1: Deploy the Virtual Machine
Option A: Azure Portal
- Navigate to the Azure Marketplace and search for "Oracle Linux 10 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
Run this on your own workstation, substituting your resource group, VM name and preferred region. Accept the Marketplace terms once per subscription, then create the machine:
az vm image terms accept --urn cloudimg1647283583153:oel-10-minimal:default:latest
az vm create \
--resource-group myResourceGroup \
--name my-oracle-linux-10-minimal-vm \
--image cloudimg1647283583153:oel-10-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-oracle-linux-10-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 and the patch level
Check that the machine is Oracle Linux 10:
cat /etc/oracle-release
grep -E '^(NAME|VERSION|ID|VERSION_ID|PLATFORM_ID)=' /etc/os-release
uname -rm
Expected output (your kernel version may be newer):
Oracle Linux Server release 10.2
NAME="Oracle Linux Server"
VERSION="10.2"
ID="ol"
VERSION_ID="10.2"
PLATFORM_ID="platform:el10"
6.12.0-206.104.3.3.el10uek.x86_64 x86_64
This listing tracks the Oracle Linux 10 major release, not a frozen minor. The image was patched to the point release that was current when it was built, and your own updates roll it forward within Oracle Linux 10, so you keep receiving security fixes. The el10uek tag on the kernel shows the machine is running the Unbreakable Enterprise Kernel.
Every available update was applied when this image was built. dnf check-update exits 100 when updates are pending and 0 when none are:
dnf -q check-update >/dev/null 2>&1; echo "exit=$?"
dnf needs-restarting -r
exit=0
No core libraries or services have been updated since boot-up.
Reboot should not be necessary.
Both Oracle kernel lines are installed, one current version of each. Superseded kernels are removed before capture:
rpm -q kernel-uek-core kernel-core
kernel-uek-core-6.12.0-206.104.3.3.el10uek.x86_64
kernel-core-6.12.0-211.53.1.el10_2.x86_64
The UEK line is the default. The Red Hat Compatible Kernel (the el10_2 kernel) is there if you need strict RHEL kernel compatibility; select it at boot with grubby. Both receive updates.
Your update path is the rolling Oracle Linux 10 repositories, with no per minor repository pinned:
dnf repolist --enabled
repo id repo name
ol10_UEKR8 Oracle Linux 10 UEK Release 8 (x86_64)
ol10_addons Oracle Linux 10 Addons (x86_64)
ol10_appstream Oracle Linux 10 Application Stream Packages (x86_64)
ol10_baseos_latest Oracle Linux 10 BaseOS Latest (x86_64)

Step 4: Inspect the minimal package profile
Count the installed packages:
rpm -qa --qf '%{NAME}\n' | grep -vx gpg-pubkey | sort -u | wc -l
429
The image carries a package profile file that records the contract, the standard image's package count and every package that was removed:
grep -E '^(standard|minimal)_image_packages=' /var/lib/cloudimg/minimal-profile.txt
standard_image_packages=597
minimal_image_packages=429
To see the full removed lists, read the file itself with cat /var/lib/cloudimg/minimal-profile.txt. Spot check a few of the removed packages:
rpm -q perl-interpreter llvm-libs tuned sos nfs-utils rpcbind bluez udisks2 geolite2-city || true
package perl-interpreter is not installed
package llvm-libs is not installed
package tuned is not installed
package sos is not installed
package nfs-utils is not installed
package rpcbind is not installed
package bluez is not installed
package udisks2 is not installed
package geolite2-city is not installed
And confirm the platform essentials are all still there:
rpm -q systemd NetworkManager openssh-server cloud-init WALinuxAgent firewalld lvm2 chrony dnf-automatic
systemd-257-23.0.1.el10_2.2.x86_64
NetworkManager-1.56.0-2.0.1.el10_2.x86_64
openssh-server-9.9p1-25.0.1.el10_2.x86_64
cloud-init-24.4-7.0.1.el10_2.1.noarch
WALinuxAgent-2.14.0.1-3.0.1.el10.noarch
firewalld-2.4.3-4.0.1.el10_2.noarch
lvm2-2.03.36-2.el10.x86_64
chrony-4.8-2.0.1.el10.x86_64
dnf-automatic-4.20.0-22.0.1.el10_2.noarch
You can read Oracle's own definition of the group the image is built around:
dnf -q group info core | head -5
Group: Core
Description: Minimal host installation
Mandatory Packages:
audit
basesystem

Adding back something you need
Anything that was removed installs straight from the enabled Oracle repositories. For example, to mount an NFS share, add the NFS client (and, only if you need NFS version 3, enable rpcbind afterwards):
sudo dnf install -y nfs-utils
Other common additions are bind-utils for dig and nslookup, policycoreutils-python-utils for semanage, tuned for tuning profiles, sos for Oracle support reports, iscsi-initiator-utils for iSCSI disks and mdadm for software RAID across data disks.
Step 5: Automatic updates
The standard Oracle Linux 10 base does not include dnf-automatic. This image installs it and enables its timer, so the machine applies updates on its own schedule:
systemctl is-enabled dnf-automatic.timer
systemctl cat dnf-automatic.timer | grep -E 'OnCalendar|RandomizedDelaySec'
grep -E '^(apply_updates|upgrade_type|download_updates|reboot) ' /etc/dnf/automatic.conf
enabled
OnCalendar=*-*-* 6:00
RandomizedDelaySec=60m
upgrade_type = default
download_updates = yes
apply_updates = yes
reboot = never
The policy applies all available updates, not only those tagged as security errata, and never reboots automatically, so a kernel update waits for a window you choose. upgrade_type is deliberately default rather than security: a security only policy depends on errata metadata being present for every update, and where it is not, it silently applies nothing. Check periodically whether a restart is owed with dnf needs-restarting -r. To opt out, run sudo systemctl disable --now dnf-automatic.timer.
You can still update on your own schedule at any time:
sudo dnf upgrade -y
Step 6: Verify the security posture
Confirm SELinux is enforcing and root is locked. The L in the second field means locked:
getenforce
sudo passwd -S root
Enforcing
root L 2009-12-22 -1 -1 -1 -1
Confirm no account on the machine has a usable password. This prints nothing on a clean image:
sudo awk -F: '($2 !~ /^[!*]/) && ($2 != "") {print $1}' /etc/shadow
Read the SSH daemon's effective policy rather than the config file:
sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication|pubkeyauthentication|kbdinteractiveauthentication) '
permitrootlogin without-password
pubkeyauthentication yes
passwordauthentication no
kbdinteractiveauthentication no
without-password is how OpenSSH reports the prohibit-password setting. That policy is pinned by a drop in file that sorts ahead of every other SSH configuration file:
grep -vE '^#' /etc/ssh/sshd_config.d/00-cloudimg-hardening.conf
PermitRootLogin prohibit-password
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitEmptyPasswords no
There is no swap on the operating system disk, so this prints nothing:
swapon --show
Confirm what is listening. SSH on port 22 is the only TCP listener, and the only UDP socket is chronyd on the loopback address:
ss -tln
ss -uln
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 128 [::]:22 [::]:*
State Recv-Q Send-Q Local Address:Port Peer Address:Port
UNCONN 0 0 127.0.0.1:323 0.0.0.0:*
UNCONN 0 0 [::1]:323 [::]:*

Step 7: Verify Azure integration
The Azure Linux Agent handles extensions and the portal's recovery features, and cloud-init provisions the machine:
systemctl is-active waagent
rpm -q WALinuxAgent cloud-init chrony
cloud-init status
active
WALinuxAgent-2.14.0.1-3.0.1.el10.noarch
cloud-init-24.4-7.0.1.el10_2.1.noarch
chrony-4.8-2.0.1.el10.x86_64
status: done
The kernel puts a console on ttyS0, which is what makes boot diagnostics and the portal's serial console work when you cannot reach the machine over SSH:
grep -o 'console=ttyS0[^ ]*' /proc/cmdline
console=ttyS0,115200n8
Time synchronisation runs through chronyd, with the Hyper-V precision clock (PHC0) selected as the source. The clock and time zone are UTC, matching the Azure host clock (your offsets will differ):
chronyc -n sources | head -3
timedatectl show -p Timezone -p LocalRTC
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
#* PHC0 0 3 377 7 +9980ns[ +12us] +/- 12us
Timezone=UTC
LocalRTC=no

Step 8: Storage layout and growing the root filesystem
The operating system disk uses Oracle's Azure layout: an EFI system partition, /boot on XFS, and an LVM volume group rootvg holding the root filesystem and a dedicated volume for kernel crash dumps:
df -h /
findmnt -no SOURCE,FSTYPE,TARGET /boot/efi
findmnt -no SOURCE,FSTYPE,TARGET /boot
findmnt -no SOURCE,FSTYPE,TARGET /var/crash
sudo pvs
sudo lvs
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/rootvg-rootlv 27G 2.9G 24G 11% /
/dev/sda1 vfat /boot/efi
/dev/sda3 xfs /boot
/dev/mapper/rootvg-crashlv xfs /var/crash
PV VG Fmt Attr PSize PFree
/dev/sda4 rootvg lvm2 a-- <46.90g 0
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
crashlv rootvg -wi-ao---- 20.00g
rootlv rootvg -wi-ao---- <26.90g
The volume group is fully allocated (PFree 0), so growing the root filesystem starts with a bigger OS disk.
Kdump is active and writes crash dumps to /var/crash, the same crash dump posture as Oracle's own image:
systemctl is-active kdump
grep -o 'crashkernel=[^ ]*' /proc/cmdline
active
crashkernel=1G-64G:448M,64G-:512M
To make the root filesystem bigger, first increase the OS disk size in the Azure portal or with az disk update while the VM is deallocated, start the VM, then grow the partition, the physical volume and the logical volume. The -r flag grows the XFS filesystem in the same step:
sudo growpart /dev/sda 4
sudo pvresize /dev/sda4
sudo lvextend -r -l +100%FREE /dev/rootvg/rootlv
Standard_B2s also has a local temporary disk mounted at /mnt. Treat anything on it as disposable, since it is erased whenever the machine is deallocated or moved.
Step 9: Networking and the firewall
The Azure Network Security Group is the outer control for inbound traffic, and it is the first place you open a port. This image also runs Oracle Linux's host firewall, firewalld, with the public zone allowing only SSH and the DHCPv6 client:
sudo firewall-cmd --state
sudo firewall-cmd --list-services
running
dhcpv6-client ssh
To expose another service, open it in both the Azure NSG and firewalld. For example, to allow HTTPS:
sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --reload
Always keep the ssh service allowed so a firewall change does not lock you out.
Step 10: Install software
The BaseOS repository carries the core operating system and the Application Stream carries the application packages, so most software installs directly with dnf:
dnf -q list --available nginx 2>/dev/null | tail -2
nginx.src 2:1.26.3-6.0.1.el10_2.6 ol10_appstream
nginx.x86_64 2:1.26.3-6.0.1.el10_2.6 ol10_appstream
Install and enable a package in the usual way, for example sudo dnf install -y nginx followed by sudo systemctl enable --now nginx, then open the port in your Network Security Group and in firewalld.
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 the administrator you named at create time is the only login until you add one:
getent group wheel
Common Use Cases
- A lean RHEL 10 compatible base for building your own services and container hosts
- Workloads that want a smaller package, patch and CVE footprint than the standard Oracle Linux image
- Golden image pipelines that start from Oracle's core group and add only what each workload needs
- A base for software certified on the Oracle Linux 10 platform
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 administrator name you chose at create time
- 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 journalctl -u waagent -n 20 --no-pager
If it reports anything other than active, start it:
sudo systemctl enable --now waagent
A command is missing
This is a minimal image, so a tool you expect may have been removed. Find which package provides it, then install it:
dnf -q provides '*/bin/dig' 2>/dev/null | head -2
Then install the package it names, for example sudo dnf install -y bind-utils.
Package manager issues
Clear the metadata cache and rebuild it:
sudo dnf clean all
sudo dnf makecache
If repositories are unreachable, check DNS resolution. getent is always present and resolves through the system resolver:
getent hosts yum.oracle.com
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:
sudo ausearch -m AVC -ts recent </dev/null 2>/dev/null || echo "no recent AVC denials"
To change SELinux port or file context policy with semanage, install policycoreutils-python-utils first.
Important Notes
Oracle Linux is free and open source, and Oracle explicitly permits its redistribution. It is not covered by a single licence: it is a distribution assembled from independently packaged components, each carrying its own terms, including the GPL, LGPL, MIT, BSD, Apache 2.0 and MPL. Every package's terms are readable with rpm -qi <package> and under /usr/share/licenses/. No subscription, licence key or Red Hat entitlement is required. A paid Oracle Linux Support subscription is optional and is not needed to use, patch or resell the operating system.
Oracle Linux 10 was released in June 2025. Oracle's lifetime support policy lists Premier Support until June 2030 and Extended Support until June 2035. Plan a move to a newer Oracle Linux image before then for workloads that need to outlive it.
Oracle and Oracle Linux are trademarks of Oracle Corporation. The names are used here nominatively, only to identify the distribution this image contains. cloudimg is not affiliated with, endorsed by or sponsored by Oracle Corporation.
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