openSUSE Leap 16 Arm64 on Azure User Guide
Overview
This guide covers the deployment and configuration of openSUSE Leap 16.0 on 64-bit Arm (AArch64/arm64) on Microsoft Azure using cloudimg's pre configured virtual machine image from the Azure Marketplace.
openSUSE Leap is a community distribution produced by the openSUSE Project, sharing its core codebase with SUSE Linux Enterprise 16. This is the native Arm build of openSUSE Leap 16.0, running the 6.12 kernel. It runs on Azure's Arm virtual machine sizes, which are powered by the Azure Cobalt 100 processor (the Dpsv6 and Dplsv6 families), where many workloads deliver the same performance at a lower cost than on x86.
What's included:
- openSUSE Leap 16.0, native 64-bit Arm (arm64 / AArch64) with the standard 4k page size kernel
- Every available patch applied at build time, and again immediately before capture
- Automatic security patching installed, armed and enabled, so the machine keeps patching itself
- Azure Linux Agent (waagent) and cloud-init for Azure integration, with a first boot fix that cuts five minutes off every launch
- Chrony for NTP time synchronisation against the Azure host clock
- SELinux in enforcing mode, the Leap 16 default
- The
repo-ossupdate path enabled and GPG checked, so your patch path is intact - SSH as the only network listener, with no swap on the operating system disk
- Gen2 Hyper V virtual machine support
- 24/7 cloudimg support
Platform: Microsoft Azure (Gen2 Hyper V, Arm64, Azure Cobalt 100)
Default user: azureuser
This is openSUSE Leap 16.0, on Arm
This listing tracks openSUSE Leap 16.0. openSUSE Leap 16.0 reached general availability on 1 October 2025 and is supported until 31 October 2027. That is a shorter support window than the Leap 15.x series offered, so plan your upgrade to the next Leap release before that date. The image is built from the current Leap 16.0 maintenance stream and brought fully up to date; your own zypper patch then rolls the machine forward within Leap 16.0 in the normal way.
Because this is the Arm build, it is a genuinely separate product from the x86 openSUSE Leap 16 image: it carries aarch64 packages and an aarch64 kernel, and it only runs on Arm virtual machine sizes. It uses a flat partition layout — a plain EFI system partition plus a root partition, with no LVM — and the standard 4k page size kernel.
A note on where this image comes from, because it matters for licensing: it is built from the official openSUSE Azure disk image published by the openSUSE Project, not from a third party Marketplace image. It therefore carries no Marketplace purchase plan of its own, and you do not need to accept any vendor terms beyond cloudimg's own to launch it.
What this image changes from the stock openSUSE Leap 16 Arm image
Everything below was measured on the stock vendor image before it was changed, and every change is reversible in one command. Nothing is removed.
- The five minute first boot stall is fixed. This is the big one. On the stock image, cloud-init's Azure data source asks
dhcpcdfor a temporary DHCP lease.dhcpcdgets the lease in about two seconds, but because cloud-init runs it with--persistentit never exits, so cloud-init sits and waits for its full 300 second timeout, logsFailed to obtain DHCP leaseand an Azure data source failure, and only then reads the lease it already had. Boot succeeds, but every machine wastes five minutes doing it andcloud-init statusreportsdegradedforever afterwards. This image installs the ISCdhclient, which exits once it has the lease, and tells cloud-init to prefer it. Measured on the build machine: boot time fell from 5 minutes 19 seconds to 10.2 seconds, and cloud-init reportsdoneinstead ofdegraded. - Automatic security patching is installed and armed. The stock image has no automatic update mechanism at all. openSUSE has no
dnf-automaticand nounattended-upgrades, so this image ships a systemd timer,cloudimg-zypper-patch.timer, that runszypper patchdaily. - SSH is hardened by a drop in file that sorts ahead of every other SSH configuration file, so a later package update cannot quietly loosen it.
rpcbindis confirmed switched off, so nothing listens on port 111. Re-enable it withsudo systemctl enable --now rpcbind.socketif you need NFSv3.
The first boot change is recorded on the machine itself, at /var/lib/cloudimg/cloud-init-dhcp-client, together with the command that reverts it.
For the avoidance of doubt, two changes that cloudimg's Rocky Linux Arm images need are deliberately not made here, because the problems do not exist on this base: openSUSE Leap 16 ships no Cockpit web console (so nothing listens on port 9090) and no rng-tools (so nothing fails at boot for want of a hardware random number generator). The port check in Step 5 proves the result either way.
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.
- No account on the image has a usable password at all.
PasswordAuthenticationand keyboard interactive authentication are disabled in the SSH daemon, so every login is by key.PermitRootLoginis set toprohibit-password, so root can never log in with a password. No root key ships in the image, so in practice root has no SSH login at all until you add one deliberately. Usesudofromazureuserinstead.- SSH host keys are removed before capture and regenerated on each machine at first boot, so no two machines you launch share a host identity.
/etc/machine-idis cleared before capture and regenerated per machine.- The build account is deleted before capture, and the image is checked to confirm no account with a user ID of 1000 or above survives.
- 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.
- SELinux is left in enforcing mode, the openSUSE Leap 16 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_D2ps_v6 (2 vCPU, 8 GB RAM, Azure Cobalt 100) or larger. This is an Arm64 image, so it must be launched on an Arm virtual machine size, such as the Dpsv6 or Dplsv6 families. An x86 size such as Standard_B2s will not accept this image.
Step 1: Deploy the Virtual Machine
Option A: Azure Portal
- Navigate to the Azure Marketplace and search for "openSUSE Leap 16 Arm64 cloudimg"
- Select the image and click Create
- Choose your subscription, resource group and region
- Pick an Arm64 size such as
Standard_D2ps_v6 - Set the administrator username and paste your SSH public key
- Allow inbound port 22 (SSH) and create the machine
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:opensuse-leap-16-arm64:default:latest
az vm create \
--resource-group myResourceGroup \
--name my-opensuse-leap-16-arm64-vm \
--image cloudimg1647283583153:opensuse-leap-16-arm64:default:latest \
--size Standard_D2ps_v6 \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
The --size must be an Arm64 family (Standard_D2ps_v6 above). Azure rejects an x86 size for an Arm image at create time.
Step 2: Connect via SSH
ssh azureuser@<your-vm-public-ip>
Only the key you supplied at create time will be accepted. There is no password login.
Step 3: Confirm the release and the architecture
Confirm you have genuine openSUSE Leap 16.0, built for Arm:
cat /etc/os-release
NAME="openSUSE Leap"
VERSION="16.0"
ID="opensuse-leap"
ID_LIKE="suse opensuse"
VERSION_ID="16.0"
PRETTY_NAME="openSUSE Leap 16.0"
ANSI_COLOR="0;32"
CPE_NAME="cpe:/o:opensuse:leap:16.0"
BUG_REPORT_URL="https://bugs.opensuse.org"
HOME_URL="https://www.opensuse.org/"
DOCUMENTATION_URL="https://en.opensuse.org/Portal:Leap"
LOGO="distributor-logo-Leap"
Confirm the architecture and the processor. aarch64 is the Arm 64-bit architecture, and Neoverse-N2 is the core used by Azure Cobalt 100:
uname -m && lscpu | grep -E 'Architecture|Model name|BIOS Model'
aarch64
Architecture: aarch64
Model name: Neoverse-N2
BIOS Model name: Cobalt 100 None CPU @ 3.4GHz
Check the kernel and its page size. This image uses the standard 4k page kernel:
uname -r && getconf PAGESIZE
6.12.0-160000.37-default
4096

The kernel is a packaged, managed kernel, so it receives patches through the normal update path:
rpm -q kernel-default
kernel-default-6.12.0-160000.37.1.aarch64
The disk layout
The image uses a flat GPT layout: an EFI system partition and a root partition, with no LVM. The root filesystem is btrfs, which is openSUSE's standard choice, with separate subvolumes for the directories that benefit from them:
lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT && findmnt -no SOURCE,FSTYPE /
NAME SIZE FSTYPE MOUNTPOINT
sda 30G
├─sda1 512M vfat /boot/efi
└─sda2 29.5G btrfs /var
sr0 1024M
/dev/sda2[/@/.snapshots/1/snapshot] btrfs
The root filesystem being reported as a subvolume path is normal for openSUSE and is not a fault. To see the subvolumes:
sudo btrfs subvolume list /
ID 256 gen 11 top level 5 path @
ID 257 gen 16 top level 256 path @/.snapshots
ID 258 gen 63 top level 257 path @/.snapshots/1/snapshot
ID 259 gen 46 top level 256 path @/home
ID 260 gen 16 top level 256 path @/opt
ID 261 gen 55 top level 256 path @/root
ID 262 gen 16 top level 256 path @/srv
ID 263 gen 66 top level 256 path @/var
ID 264 gen 16 top level 256 path @/boot/writable
ID 265 gen 55 top level 256 path @/usr/local
ID 266 gen 16 top level 256 path @/boot/grub2/arm64-efi
ID 267 gen 16 top level 256 path @/boot/grub2/i386-pc
The operating system disk is 30 GB and carries no swap:
df -hT / /boot/efi && swapon --show
Filesystem Type Size Used Avail Use% Mounted on
/dev/sda2 btrfs 30G 1.8G 28G 7% /
/dev/sda1 vfat 512M 4.3M 508M 1% /boot/efi
swapon --show prints nothing, which means no swap is configured. Azure image certification requires that, and you can add swap yourself if a workload needs it.
Step 4: Check the patch level and automatic updates
openSUSE uses zypper, not dnf or apt. The image was fully patched immediately before capture, so a freshly launched machine should report no pending patches:
sudo zypper patch-check
Loading repository data...
Reading installed packages...
0 patches needed (0 security patches)
zypper patch-check exits 0 when nothing is pending, 100 when ordinary patches are available and 101 when security patches are available, which makes it convenient in scripts.
Your update path is the repo-oss repository, with GPG checking enabled:
sudo zypper lr -E
# | Alias | Name | Enabled | GPG Check | Refresh
--+------------------------+----------------------+---------+-----------+--------
3 | openSUSE:repo-openh264 | repo-openh264 (16.0) | Yes | (r ) Yes | Yes
4 | openSUSE:repo-oss | repo-oss (16.0) | Yes | (r ) Yes | Yes
If you are used to Leap 15, note that Leap 16 does not have a separate repo-update. Maintenance patches are delivered through repo-oss itself, so the two repositories above are the whole update path.
Apply patches yourself at any time with:
sudo zypper refresh && sudo zypper patch
Automatic updates
openSUSE has no dnf-automatic and no unattended-upgrades, so this image ships a cloudimg systemd timer that runs zypper patch daily with a randomised delay of up to an hour:
systemctl is-enabled cloudimg-zypper-patch.timer && systemctl list-timers cloudimg-zypper-patch.timer --no-pager
enabled
NEXT LEFT LAST PASSED UNIT ACTIVATES
Tue 2026-09-15 00:06:31 UTC 1h 31min - - cloudimg-zypper-patch.timer cloudimg-zypper-patch.service
1 timers listed.
To see what it will run, or to run it immediately:
systemctl cat cloudimg-zypper-patch.service
sudo systemctl start cloudimg-zypper-patch.service
To turn automatic patching off, if your change control requires it:
sudo systemctl disable --now cloudimg-zypper-patch.timer
Some patches need a reboot to take effect. Check with:
sudo zypper needs-rebooting

Step 5: Verify the security posture
Confirm the effective SSH configuration. This reads the parsed, effective settings rather than the file, so it accounts for every drop in:
sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication|permitemptypasswords)'
permitrootlogin without-password
passwordauthentication no
kbdinteractiveauthentication no
permitemptypasswords no
without-password is the older spelling of prohibit-password and means the same thing: root may not log in with a password.
Confirm the root account has no usable password:
sudo passwd -S root
root L 2009-12-22 -1 -1 -1 -1
The L means locked.
Confirm SELinux is enforcing:
getenforce
Enforcing
Confirm SSH is the only thing listening off the machine. This is worth checking on any image you run, not just this one:
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 [::]:*

Port 22 is the only port reachable from outside the machine. The two UDP sockets on port 323 are chrony's control interface, bound to the loopback address only, so they are not reachable from the network.
Step 6: Verify Azure integration
Confirm the Azure Linux Agent is present and running:
waagent --version
WALinuxAgent-2.14.0.1 running on opensuse 16.0
Python: 3.13.14
Goal state agent: 2.14.0.1
Confirm cloud-init completed cleanly. This is where the first boot fix shows up — on the stock image this reports degraded:
cloud-init status --long
status: done
extended_status: done
boot_status_code: enabled-by-generator
detail: DataSourceAzure [seed=/var/lib/waagent]
errors: []
recoverable_errors: {}
Check how long the machine took to boot:
systemd-analyze
Startup finished in 949ms (kernel) + 4.016s (initrd) + 5.244s (userspace) = 10.211s
For comparison, the stock vendor image reaches the same point after 5 minutes and 19 seconds, because of the DHCP stall described earlier.
Confirm time synchronisation against the Azure host clock. PHC0 is the hypervisor clock, and stratum 1 means the machine is synchronised directly to it:
chronyc tracking
Reference ID : 50484330 (PHC0)
Stratum : 1
System time : 0.000002129 seconds slow of NTP time
Confirm nothing failed during boot:
systemctl list-units --state=failed
An empty list is the expected result.
The Azure serial console works through the Arm PL011 UART, which is ttyAMA0 rather than the ttyS0 you would see on an x86 machine:
cat /proc/cmdline | tr ' ' '\n' | grep console=
console=tty1
console=ttyAMA0

Step 7: Networking and the firewall
No host firewall is installed or enabled on this image. Your Azure Network Security Group is the firewall, which is the usual arrangement for an Azure Linux image: manage inbound rules there and you have one place to look.
If you prefer a host firewall as well, install one:
sudo zypper install firewalld
sudo systemctl enable --now firewalld
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload
Add that after you have confirmed SSH access, and always keep port 22 open in the rule set, or you will lock yourself out.
Step 8: Install software
Install packages with zypper:
sudo zypper refresh
sudo zypper install nginx
Search for a package:
zypper search nginx
Find which package owns a file:
zypper search --provides /usr/bin/python3
If you are coming from a Red Hat family distribution, the rough translations are dnf install to zypper install, dnf search to zypper search, dnf update to zypper update, and dnf upgrade --security to zypper patch.
Common Use Cases
- A general purpose Linux server on Arm, where the lower cost of Azure Cobalt 100 is attractive
- Build and test agents for software that ships
aarch64binaries or container images - Web and application servers, where the workload is already available for Arm
- A development environment matching a SUSE Linux Enterprise 16 production target, since Leap 16 shares its core codebase
Troubleshooting
Cannot connect via SSH
Check the Network Security Group allows inbound TCP 22 from your address, that the machine is running, and that you are using the private key matching the public key you supplied at create time. Password authentication is disabled by design, so a password prompt means the key was not offered.
The VM will not create, or will not boot
The most common cause is an x86 virtual machine size. This is an Arm64 image and only runs on Arm sizes such as Standard_D2ps_v6. Confirm with uname -m, which must print aarch64.
Azure agent not running
sudo systemctl status waagent
sudo systemctl restart waagent
Package manager issues
Refresh the repository metadata first:
sudo zypper refresh
If a repository fails to refresh, confirm the machine has outbound internet access. If zypper reports a lock held by another process, the automatic patch timer may be running; wait for it to finish or stop it with sudo systemctl stop cloudimg-zypper-patch.service.
Locked plymouth packages
sudo zypper locks
openSUSE Leap 16 ships a vendor lock covering the plymouth boot splash packages. It is part of the stock distribution, it is cosmetic, and it does not hold back security patches — zypper patch-check reporting clean is the proof of that. Leave it in place.
A service is blocked and the logs mention SELinux
sudo ausearch -m AVC -ts recent
Most denials on a fresh machine come from software installed into a non standard path. Relabel with sudo restorecon -Rv /path before considering any policy change.
The boot log mentions a dhclient timeout
One message appears at error level on every boot:
journalctl -p err -b --no-pager
dhclient[...]: Timeout too large reducing to: 2147483646 (TIME_MAX - 1)
Azure's DHCP server hands out an unlimited lease time, and ISC dhclient logs a notice when it clamps that value to the largest number it can store. It is cosmetic, it does not affect the lease, and it is the direct consequence of the first boot fix described earlier — one harmless log line in exchange for five minutes off every boot. It is safe to ignore.
Important Notes
openSUSE Leap is free and open source. It is not covered by a single licence: the distribution is a collection of independently licensed packages. On this image, 550 installed packages carry 86 distinct licence strings, most commonly GPL-2.0-or-later, MIT, LGPL-2.1-or-later, GPL-3.0-or-later, BSD-3-Clause and Apache-2.0. You can read any package's terms with rpm -qi <package>. No subscription, entitlement or licence key is required, and no per seat cost applies. No SUSE entitlement is involved.
openSUSE is a trademark of SUSE. cloudimg is not affiliated with or endorsed by SUSE or the openSUSE Project, and uses the name only to identify the distribution this image contains.
openSUSE Leap 16.0 reached general availability on 1 October 2025 and is supported until 31 October 2027. Check the openSUSE Leap roadmap for the dates that apply to your deployment, and plan your upgrade to the next Leap release before support ends.
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