Deployment guide

Rocky 8 ARM64

Overview

Rocky Linux is a community enterprise operating system from the Rocky Enterprise Software Foundation, built to be binary-compatible with Red Hat Enterprise Linux. This image is the native 64-bit Arm (AArch64/arm64) build of Rocky Linux 8, running the 4.18 kernel and following the RHEL 8 lifecycle. It is a pre-configured virtual machine for Microsoft Azure.

The image runs on Azure's Arm virtual machine sizes, which are powered by the Azure Cobalt 100 processor (the Dpsv6 and Dplsv6 families). On these sizes, many workloads deliver the same performance at a lower cost than on x86.

What you get:

  • Rocky Linux 8.10, native 64-bit Arm (arm64 / AArch64), binary-compatible with RHEL 8
  • A 64k page size kernel, as RHEL 8 ships on aarch64 (see the page size section below, because it affects tuning)
  • Every available update applied at build time, and again immediately before capture
  • Automatic updates installed, armed and enabled, so the machine keeps patching itself
  • Azure Linux Agent (waagent) and cloud-init for Azure integration
  • chronyd for NTP time synchronization against the Azure host clock
  • SELinux in enforcing mode
  • BaseOS, AppStream and Extras repositories enabled, so your update 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 SecureAnyCloud support

Platform: Microsoft Azure (Gen2 Hyper-V, Arm64, Azure Cobalt 100). Default user: azureuser

Rocky Linux 8.10 is the final Rocky Linux 8 release, and it is still supported

Rocky Linux 8 ends at 8.10. There will be no 8.11. Unlike the Rocky Linux 9 and 10 listings, which track a moving minor release, this image is pinned to the release that the 8 series terminates on.

That does not make it a frozen, archived image. Rocky Linux 8 is in security maintenance until 31 May 2029, and 8.10 is the live stream that receives those errata. The image therefore stays on the rolling Rocky Linux 8 repositories (BaseOS, AppStream and Extras, with no vault.rocky.org pin). Your own dnf update keeps pulling security fixes for the life of the release. You get a supported platform, not an archived one.

This Arm build is a separate product from the x86 Rocky Linux 8 images. It carries aarch64 packages and an aarch64 kernel, and it runs only on Arm virtual machine sizes. It uses the flat partition layout, not the LVM variant.

The page size is 64k: know this before you tune

RHEL 8 builds its aarch64 kernel with a 64 KiB page size. RHEL 9 moved the aarch64 kernel to 4 KiB. If you are moving a workload here from a Rocky Linux 9 or 10 Arm machine, this is the platform difference most likely to surprise you.

Check the page size:

getconf PAGESIZE
65536

The most visible consequence is huge pages. On a 4k kernel the default huge page is 2 MiB. On this kernel it is 512 MiB:

grep -E '^Hugepagesize' /proc/meminfo; ls /sys/kernel/mm/hugepages/
Hugepagesize: 524288 kB hugepages-16777216kB hugepages-2048kB hugepages-524288kB

Practical implications:

  • Databases that reserve huge pages (PostgreSQL huge_pages, MySQL large-pages, Oracle) allocate in 512 MiB units here. Round your shared buffer or SGA sizing to that granularity instead of copying a 2 MiB-based figure from an x86 or EL9 host.
  • JVM workloads that use -XX:+UseLargePages inherit the same 512 MiB granularity. -XX:LargePageSizeInBytes values carried over from a 4k host will not apply cleanly.
  • Memory accounting looks coarser. Small allocations round up to 64 KiB, so a process with many small mappings reports a larger resident set than the same process on a 4k kernel. This is expected and is not a leak.
  • Anything that assumes PAGE_SIZE == 4096 at compile time needs rebuilding. Everything in the Rocky Linux repositories is already built correctly for this kernel.

What this image changes from the stock Rocky Linux 8 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 packages stay installed so you can turn any of it back on.

  • rpcbind is switched off. This is the significant change. The stock image enables both rpcbind.socket and rpcbind.service, which between them bind four sockets on port 111 (IPv4 and IPv6, TCP and UDP) on every interface. That is an unadvertised network listener on every machine you launch. An operating system base image should expose one service, and that service is SSH, so both units ship disabled. NFSv4 does not need rpcbind. If you need NFSv3 or another RPC service, re-enable it with sudo systemctl enable --now rpcbind.socket.
  • bluetooth.service is switched off. Bluetooth is not part of the stock image. The bluez package arrives as a dependency of the full security patch, and its unit is enabled by RPM preset. An Azure virtual machine has no Bluetooth radio, so the unit is pointless and ships disabled. Re-enable it with sudo systemctl enable --now bluetooth.service.
  • Automatic updates are installed and armed. The stock image has no dnf-automatic at all: no package, no configuration and no timer. This image installs it and arms it with upgrade_type = default and apply_updates = yes, so the machine keeps patching itself.
  • SSH is hardened in the main configuration file. The stock image permits root login and X11 forwarding. Rocky Linux 8 ships OpenSSH 8.0p1, which predates the Include /etc/ssh/sshd_config.d/*.conf directive. There is no such directory and no such include, so the hardening is applied to /etc/ssh/sshd_config itself. This is the only file sshd actually reads on this release, and a drop-in file would be silently ignored here.
  • A pointless network interface rename is suppressed. The stock image logs Error changing net interface name 'eth1' to 'eth0': File exists at error level on every boot after the first, because Azure's Accelerated Networking virtual function shares the primary interface's MAC address. An empty /etc/udev/rules.d/60-net.rules override stops the attempt. Nothing about your networking changes: the kernel already names the interfaces eth0 and eth1 because net.ifnames=0 is on the command line.

Two things you might expect from the sibling Rocky Linux 10 Arm64 listing are not changed here. They were measured on this base and did not need changing:

  • Cockpit is already off. cockpit-ws is installed, but cockpit.socket is disabled and nothing is listening on 9090. On the Rocky Linux 10 Arm image the socket is enabled. On this one it is not. To use the web console, enable it with sudo systemctl enable --now cockpit.socket and open 9090 in your network security group.
  • rngd is left running. On the Rocky Linux 10 Arm image, the entropy daemon has no usable source and leaves the machine degraded. On Rocky Linux 8, the vendor's /etc/sysconfig/rngd leaves the jitter entropy source available, so rngd starts cleanly and the machine reports running with no failed units. It is left exactly as the distribution ships it.

The two changes that close a listener are recorded on the machine itself, at /var/lib/sac/data/rpcbind-disabled and /var/lib/sac/data/bluetooth-disabled, together with the command that restores each one.

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.
  • PasswordAuthentication and keyboard-interactive authentication are disabled in the SSH daemon, so every login is by key.
  • PermitRootLogin is set to no, so root cannot log in over SSH at all. Use sudo from the administrator account you named at create time.
  • 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-id is cleared before capture and regenerated per machine.
  • 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 Rocky Linux default.
  • SSH on port 22 is the only off-box listener. chrony's port 323 is bound to the loopback address only.

Prerequisites

Before you deploy this image, make sure 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 you must launch it 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.

1

Deploy the Virtual Machine

Option A: Azure Portal

  • Open the Azure Marketplace and search for "Rocky Linux 8 Arm64 SecureAnyCloud"
  • Select the image and click Create
  • On the basics tab, configure the following:
  • Subscription: select your Azure subscription
  • Resource Group: create a new one or select an existing one
  • Virtual Machine Name: enter a name for your VM
  • Region: select a region that offers Arm sizes
  • Size: Standard_D2ps_v6 is recommended (an Arm64 size)
  • 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. Substitute 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 sac1647283583153:rocky-8-arm64:default:latest
az vm create \
  --resource-group myResourceGroup \
  --name my-rocky-8-arm64-vm \
  --image sac1647283583153:rocky-8-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.

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-arm64-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.

3

Confirm the release and the architecture

Check that the machine is Rocky Linux 8:

cat /etc/rocky-release
Rocky Linux release 8.10 (Green Obsidian)

The os-release fields carry the same information in a machine-readable form, which is what configuration management tools read:

grep -E '^(NAME|VERSION|ID|VERSION_ID|PLATFORM_ID)=' /etc/os-release
NAME="Rocky Linux" VERSION="8.10 (Green Obsidian)" ID="rocky" VERSION_ID="8.10" PLATFORM_ID="platform:el8"

The RHEL compatibility lineage is asserted by the distribution itself:

cat /etc/redhat-release
Rocky Linux release 8.10 (Green Obsidian)

Confirm the kernel and the architecture. Both must report aarch64:

uname -srm
Linux 4.18.0-553.162.1.el8_10.aarch64 aarch64

Then check the processor. BIOS Model name is where Azure reports the host CPU, which on an Arm size is the Azure Cobalt 100:

lscpu | grep -E '^(Architecture|Vendor ID|Model name|BIOS Model name|CPU\(s\)):'
Architecture: aarch64 CPU(s): 2 Vendor ID: ARM BIOS Model name: Cobalt 100
4

Check the patch level and automatic updates

The image is fully patched at capture. dnf check-update exits 0 when nothing is pending and 100 when updates are waiting, so 0 is the answer you want:

sudo dnf -q check-update >/dev/null 2>&1; echo "exit=$?"
exit=0

Nothing is waiting on a reboot either:

sudo needs-restarting -r
No core libraries or services have been updated since boot-up. Reboot should not be necessary.

Your update path is intact. The three repositories a Rocky Linux 8 machine needs are enabled, and none of them is pinned to the vault archive:

sudo dnf repolist --enabled
repo id repo name appstream Rocky Linux 8 - AppStream baseos Rocky Linux 8 - BaseOS extras Rocky Linux 8 - Extras

The PowerTools repository (RHEL 8's developer package set, renamed crb in RHEL 9 and later) is present but disabled, as it is on a stock Rocky Linux 8 machine. Enable it with sudo dnf config-manager --set-enabled powertools if a build needs it.

Automatic updates

The stock Rocky Linux 8 Arm image has no dnf-automatic at all. This image installs it and arms it, so the machine keeps patching itself without you scheduling anything:

systemctl is-enabled dnf-automatic.timer
enabled
systemctl cat dnf-automatic.timer | grep -E 'OnCalendar|RandomizedDelaySec'
OnCalendar=*-*-* 6:00 RandomizedDelaySec=60m

The policy applies updates rather than only downloading them:

grep -E '^(apply_updates|upgrade_type|download_updates)' /etc/dnf/automatic.conf
upgrade_type = default download_updates = yes apply_updates = yes

upgrade_type is deliberately default and not security. Rocky Linux does not publish the updateinfo security metadata that a security policy filters on, so a security setting would silently apply nothing, ever. default applies the errata that are actually published.

Exactly one kernel ships in the image, so there is no superseded kernel for a vulnerability scanner to report:

rpm -q kernel
kernel-4.18.0-553.162.1.el8_10.aarch64
5

Verify the security posture

SELinux is enforcing, and persists that way across reboots:

getenforce; grep -E '^SELINUX=' /etc/selinux/config
Enforcing SELINUX=enforcing

The root account is locked. LK is the locked state:

sudo passwd -S root
root LK 2009-12-22 -1 -1 -1 -1 (Alternate authentication scheme in use.)

No account on the machine carries a usable password hash at all, so there is nothing to guess. This command prints nothing on a correct image:

sudo awk -F: '($2 !~ /^[!*]/) && ($2 != "") {print $1}' /etc/shadow

The effective SSH policy is what sshd actually computes, which is the only thing worth checking. Root login is refused outright, and password and keyboard-interactive authentication are both off:

sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication|pubkeyauthentication|kbdinteractiveauthentication|x11forwarding|gssapiauthentication|maxauthtries) '
maxauthtries 4 permitrootlogin no pubkeyauthentication yes gssapiauthentication no passwordauthentication no kbdinteractiveauthentication no x11forwarding no

The image has no swap, as Azure expects. Swap belongs on the ephemeral resource disk, managed by waagent, never on the captured operating system disk. This command prints nothing:

swapon --show

SSH is the only thing listening off-box. TCP 22 is the whole set:

ss -tln
State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess LISTEN 0 128 0.0.0.0:22 0.0.0.0:* LISTEN 0 128 [::]:22 [::]:*

And the only UDP sockets are chrony's, bound to the loopback address, so they are not reachable from the network:

ss -uln
State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess UNCONN 0 0 127.0.0.1:323 0.0.0.0:* UNCONN 0 0 [::1]:323 [::]:*

The three units that would otherwise have opened a port, or run a radio stack that does not exist on a virtual machine, are all disabled. They are disabled, not masked, so any of them is one command from working:

for u in rpcbind.socket bluetooth.service cockpit.socket; do printf '%s: %s\n' "$u" "$(systemctl is-enabled $u 2>&1 | head -1)"; done
rpcbind.socket: disabled bluetooth.service: disabled cockpit.socket: disabled
6

Verify Azure integration

The Azure Linux Agent is running and starts at boot:

systemctl is-active waagent;
systemctl is-enabled waagent
active enabled

The guest integration packages are all the aarch64 or noarch builds, as they should be on an Arm machine:

rpm -q WALinuxAgent cloud-init chrony
WALinuxAgent-2.7.0.6-8.el8_8.rocky.0.1.noarch cloud-init-23.4-7.el8_10.11.0.2.noarch chrony-4.5-2.el8_10.aarch64

cloud-init finished cleanly on this boot:

cloud-init status
status: done

The serial console is on ttyAMA0, the Arm PL011 UART, which is what Azure's Boot diagnostics and Serial console read from. On x86 this would be ttyS0:

grep -o 'console=ttyAMA0[^ ]*' /proc/cmdline
console=ttyAMA0

Nothing failed on this boot:

systemctl is-system-running;
systemctl list-units --state=failed --no-legend --plain
running

Networking comes up promptly. Azure's Accelerated Networking virtual function is left unmanaged by NetworkManager, so NetworkManager-wait-online does not wait on it:

systemd-analyze blame | grep NetworkManager-wait-online
916ms NetworkManager-wait-online.service

The clock is synchronized against the Azure host's precision clock rather than a public NTP pool, which is the correct source on a virtual machine:

systemctl is-active chronyd; chronyc -n sources | head -3
active MS Name/IP address Stratum Poll Reach LastRx Last sample =============================================================================== #* PHC0 2 3 377 4 +29us[ +37us] +/- 8564ns

The disk layout is flat: partitions sit directly on the disk with no LVM, so growing the root filesystem is a single growpart plus xfs_growfs, with nothing else to resize:

lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT
NAME SIZE TYPE FSTYPE MOUNTPOINT sda 11G disk ├─sda1 99M part vfat /boot/efi ├─sda2 1000M part xfs /boot ├─sda3 4M part ├─sda4 1M part └─sda5 9.9G part xfs /

sda3 and sda4 are small unformatted PReP and BIOS boot partitions that the vendor image carries for boot compatibility; they hold no filesystem and need no attention.

The operating system disk is 11 GiB. If you need more room, resize the disk in Azure and grow the root partition and filesystem:

sudo growpart /dev/sda 5
sudo xfs_growfs /
7

Networking and the firewall

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.

firewalld is not installed on this image:

rpm -q firewalld || echo "(firewalld absent - the Azure NSG is your only firewall)"
package firewalld is not installed (firewalld absent - the Azure NSG is your only firewall)

That matches the Rocky Linux cloud image default: with no host firewall in the way, your NSG rules take effect exactly as written, with no second layer to keep in sync. 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.

Your machine has two network interfaces, and that is normal. eth1 is the Accelerated Networking virtual function; it shares eth0's MAC address and is deliberately left unmanaged, so you configure eth0 and ignore eth1:

nmcli -t -f DEVICE,STATE,TYPE device
eth0:connected:ethernet eth1:unmanaged:ethernet lo:unmanaged:loopback
8

Install software

AppStream carries the application packages. Everything in the repositories is built for Arm, so dnf resolves aarch64 packages automatically with nothing extra to configure:

dnf -q list --available nginx 2>/dev/null | tail -2
Available Packages nginx.aarch64 1:1.14.1-9.module+el8.4.0+542+81547229 appstream

Rocky Linux 8 uses modules (AppStream module streams) for several major packages, which is a RHEL 8 concept that RHEL 9 and 10 dropped. If you want a newer stream than the default, list what is available and enable one before installing:

sudo dnf module list nginx
sudo dnf module enable -y nginx:1.22
sudo dnf install -y nginx

Then enable the service in the usual way with sudo systemctl enable --now nginx, and open the port in your Network Security Group.

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
wheel:x:10:

Common Use Cases

  • RHEL 8-compatible application hosting on cost-efficient Azure Cobalt 100 Arm virtual machines
  • Lifting an existing RHEL 8 or CentOS 8 workload onto Arm without changing the major release
  • A RHEL-compatible platform for workloads certified against RHEL 8, without a subscription
  • Arm build and CI runners that produce el8 packages, and fleets managed by Ansible, Puppet or Salt

Troubleshooting

Cannot connect via SSH

Check that the network security group allows inbound TCP 22 from your address. Confirm that the machine is running. Make sure your client offers the private key that matches the public key you supplied at create time.

Password authentication is disabled, so a password prompt means key negotiation already failed. Root cannot log in over SSH at all, so connect as the administrator you named at create time.

az vm show --resource-group myResourceGroup --name my-rocky-8-arm64-vm --show-details --query powerState -o tsv

The VM will not create or will not boot

This is an Arm64 image. It runs only on Arm virtual machine sizes (the Dpsv6 and Dplsv6 Azure Cobalt 100 families and other p sizes). If Azure rejects the size at create time, confirm that you selected an Arm size and not an x86 one such as Standard_B2s or Standard_D2s_v5.

If the machine never becomes reachable, open Boot diagnostics and the Serial console in the portal. Both read from ttyAMA0.

Azure agent not running

Check whether the agent is running and read its recent log:

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

Package manager issues

Clear the metadata cache and rebuild it:

sudo dnf clean all
sudo dnf makecache

If a repository is unreachable, confirm that the machine has outbound HTTPS and that DNS resolves. Rocky Linux's mirror system is reached over both.

A package needs a newer version than the one in AppStream

Rocky Linux 8 uses AppStream module streams. The default stream is often not the newest one packaged. Check which streams exist before you add a third-party repository:

sudo dnf module list <package>

Enabling a different stream with sudo dnf module enable -y <package>:<stream> is usually the right answer, and keeps you on distribution packages that receive Rocky Linux errata.

A service is blocked and the logs mention SELinux

SELinux is enforcing, which is the secure default and should stay that way. Look at the denial rather than disabling SELinux:

sudo ausearch -m AVC -ts recent </dev/null 2>/dev/null || echo "no recent AVC denials"

Most denials on a fresh machine come from software installed into a non-standard path. Relabel with sudo restorecon -Rv /path before you consider any policy change.

The boot log mentions a dhclient timeout being reduced

One message appears at error level on every boot:

journalctl -p err -b --no-pager | grep -c 'Timeout too large'
1

It reads dhclient: Timeout too large reducing to: 2147483646 (TIME_MAX - 1). Azure's DHCP server offers an effectively infinite lease time, and the stock Rocky Linux 8 dhclient clamps it to the largest value it can represent, logging as it does so. Your lease is fine and your networking is unaffected. It is emitted by a stock distribution component, nothing in this image introduces it, and it is safe to ignore.

A memory figure looks larger than expected

This kernel uses 64 KiB pages, so every allocation rounds up to 64 KiB rather than 4 KiB. A process with many small mappings therefore reports a larger resident set here than the identical process on a Rocky Linux 9 or 10 Arm machine. This is an accounting difference, not a leak. See the page size section above for the tuning settings it affects.

Important Notes

Rocky Linux is free and open source. It is not covered by a single license. The distribution is a collection of free and open-source licenses across its package set, predominantly GPL and LGPL, with MIT, BSD, Apache and others. No subscription, entitlement or license key is required, and no per-seat cost applies.

Rocky Linux is a trademark of the Rocky Enterprise Software Foundation. SecureAnyCloud is not affiliated with or endorsed by the Rocky Enterprise Software Foundation, and uses the name only to identify the distribution this image contains.

Rocky Linux 8 follows the RHEL 8 lifecycle. 8.10 is the final release of the 8 series, and Rocky Linux 8 is in security maintenance until 31 May 2029. Check the Rocky Linux release notes for the dates that apply to your deployment, and plan a move to Rocky Linux 9 or 10 before that date.

Support

For help with this image, contact SecureAnyCloud support:

  • Website: secureanycloud.com
  • Product catalog: secureanycloud.com/products
  • User guides: secureanycloud.com/guides
  • SLA: 24-hour response guaranteed

Deploy on Azure

Launch Rocky Linux 8 Arm64 on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure