AlmaLinux

Things to Do After Installing Rocky Linux 10 / AlmaLinux 10

Rocky Linux 10 and AlmaLinux 10 don’t boot into the same server, and the gap decides what you should fix first. Our older Rocky Linux 10 post install guide says the opposite: “Everything works on AlmaLinux 10 and RHEL 10 as well since all three share the same package set.” The packages are close. The defaults around them aren’t: AlmaLinux ships CRB enabled, Rocky’s cloud image answers on port 9090 with no firewall in front of it, and only one of the two keeps its logs across a reboot.

Original content from computingforgeeks.com - post 176693

This list covers the things to do after installing Rocky Linux 10 or AlmaLinux 10, and it says which distro needs each step. You’ll fix the repository order, patch, add a firewall and decide on Cockpit, then handle the SELinux change that makes /var/opt behave like /opt, root SSH login, the journal, tuned and security updates. Everything below was run on Rocky Linux 10.2 and AlmaLinux 10.2 GenericCloud images in October 2026, with SELinux enforcing on both.

Rocky Linux 10 and AlmaLinux 10 ship different defaults

Both images come up with SELinux enforcing, password SSH disabled and chronyd syncing the clock, so the basics match. Almost everything else in the first hour differs. We booted each vendor’s official cloud image, logged in as the cloud-init user, and recorded what was installed and enabled before touching anything:

Fresh cloud imageRocky Linux 10AlmaLinux 10
CRB repositorydisabledenabled
firewalldnot installednot installed
Cockpitcockpit-ws installed, socket enabled, 9090 listeningnot installed
tunednot installedinstalled, virtual-guest profile active
semanage (policycoreutils-python-utils)installednot installed
Persistent journal (/var/log/journal)yesno, logs live in /run
Root SSH loginkey only (without-password)key only (without-password)
epel-release in the extras repo10-7.el10_110-6.el10

Read the table as a to-do list split by distro, because each image is missing different things:

  • Rocky: enable CRB, deal with the Cockpit socket, add tuned
  • AlmaLinux: persist the journal, install semanage
  • Both: install firewalld, block root SSH login

An ISO install with a different package group will not match this table line for line. Run the same checks on your own machine before you follow any step that assumes a default.

dnf repolist --all | grep -E '^(crb|epel) '
rpm -q firewalld cockpit-ws tuned policycoreutils-python-utils
systemctl is-enabled firewalld cockpit.socket tuned
ls -d /var/log/journal

A line that says not installed or not-found is a step you can’t skip below. If cockpit.socket prints enabled, you’re on a box that already serves a login page on 9090, and the Cockpit section further down matters more to you than the rest.

The hostname and timezone go first

Cloud images name the host after the VM template or leave it as localhost, which is what our AlmaLinux image did. Every log line, shell prompt and Cockpit title uses that name, so set it before anything starts writing logs. Both machines also booted in UTC. Change the zone if your logs need to line up with local time.

sudo hostnamectl set-hostname rocky01
sudo timedatectl set-timezone Africa/Nairobi

Confirm both settings. hostnamectl also prints the release and running kernel, which you’ll want before the update step:

hostnamectl | grep -E "Static hostname|Operating System|Kernel"
timedatectl | grep "Time zone"

On the Rocky box this printed the new name and the stock image kernel. Note that kernel string, because the update step replaces it:

     Static hostname: rocky01
    Operating System: Rocky Linux 10.2 (Red Quartz)
              Kernel: Linux 6.12.0-211.16.1.el10_2.0.1.x86_64
                Time zone: Africa/Nairobi (EAT, +0300)

Use alma01 or your own name on the AlmaLinux machine. The commands are identical on both, and the Alma image printed localhost before the change, which is the name you’d otherwise see in every log it ships.

Updates end with a reboot check

A cloud image is a snapshot, so it’s always behind. The AlmaLinux image we pulled was published on 12 October and still had 21 upgrades plus a new kernel to install, glibc among them. Refresh the metadata and upgrade everything in one pass:

sudo dnf upgrade --refresh -y

Don’t guess whether that needs a reboot. The needs-restarting plugin is already installed on both distros as part of dnf-plugins-core. Its exit code is scriptable, and 1 means reboot.

sudo dnf needs-restarting -r

On AlmaLinux it named the three packages that forced it. glibc alone is enough, since every running process still has the old library mapped:

Core libraries or services have been updated since boot-up:
  * glibc
  * kernel
  * kernel-core

Reboot is required to fully utilize these updates.
More information: https://access.redhat.com/solutions/27943

Then close the loop in this order, because each check only means something after the one before it. You’re done when all three agree:

  1. Reboot with sudo systemctl reboot
  2. Compare uname -r with the newest entry in rpm -q kernel-core
  3. Run sudo dnf needs-restarting -r again and expect exit 0

If step 2 shows an older kernel than the one dnf installed, the boot entry is the problem, not the update. That is exactly what happened on our Rocky VM.

The Rocky VM taught us why that comparison matters. Proxmox’s cloud-init runs a package upgrade on first boot, and we powered the VM off about a minute in to add an SSH key. The new kernel package was registered, but its boot entry never got written, so after the reboot the machine was still on the old kernel and grubby still pointed there:

sudo grubby --default-kernel
rpm -q kernel-core

If grubby names an older kernel than the newest one rpm lists, reinstalling that newest package rewrites the boot entry. Substitute the version from your own rpm -q output:

sudo dnf reinstall -y kernel-core-6.12.0-211.67.1.el10_2
sudo grubby --default-kernel

After that and one more reboot, both machines ran 6.12.0-211.67.1.el10_2. The lesson is simple: don’t hard-stop a cloud VM while its first boot is still installing packages.

CRB must come before EPEL

EPEL is where tools like htop, fail2ban and many monitoring agents come from, and a lot of its packages build against the CodeReady Builder (CRB) repo. On version 10 a wrong order also costs you SELinux policy, and three facts combine to cause it:

  • /usr/bin/crb ships inside epel-release, not in the base OS
  • epel-release recommends selinux-policy-extra, which lives in CRB
  • dnf silently drops a recommended package it can’t find

Red Hat moved the SELinux modules for EPEL-only software into selinux-policy-targeted-extra in the CRB repo, so that enabling EPEL can pull them in automatically (Considerations in adopting RHEL 10, SELinux chapter). That only happens when CRB is already on at the moment you install epel-release. On Rocky, enable CRB first with config-manager, which needs nothing beyond the dnf-plugins-core both images already have.

sudo dnf config-manager --set-enabled crb
sudo dnf install -y epel-release

With CRB enabled, the transaction pulls the extra policy in as a dependency and its metapackage as a weak dependency. Both come from crb, which is why the order matters:

Installing:
 epel-release                    noarch   10-7.el10_1            extras    19 k
Installing dependencies:
 selinux-policy-targeted-extra   noarch   42.1.18-4.el10_2.4     crb      719 k
Installing weak dependencies:
 selinux-policy-extra            noarch   42.1.18-4.el10_2.4     crb       35 k

On AlmaLinux, skip the first line, because CRB is already enabled. sudo dnf install -y epel-release alone produced the same three packages there. Alma’s extras repo carries the older 10-6.el10 build of epel-release, and the next upgrade replaces it from EPEL itself on both distros. The whole Rocky sequence, including the old order failing, looked like this:

Rocky Linux 10 CRB enabled before EPEL pulls selinux-policy-targeted-extra

Our dedicated CRB repository guide covers RHEL subscriptions too, and the EPEL install guide for RHEL 10 lists the repo layout.

Error: “sudo: /usr/bin/crb: command not found”

That’s what sudo /usr/bin/crb enable prints on a fresh Rocky Linux 10 machine, because the script arrives with epel-release. If you followed the older order and installed epel-release first, it installed alone, printed a hint to enable CRB, and skipped the extra policy. We checked: rpm -q selinux-policy-targeted-extra returned “not installed”. Enabling CRB afterwards does not fix that retroactively. Install the two packages by hand.

sudo dnf config-manager --set-enabled crb
sudo dnf install -y selinux-policy-targeted-extra
sudo dnf install -y selinux-policy-extra

Without them, an EPEL daemon that relies on one of those modules runs in the wrong domain or gets denied, and the AVC log is the only place that tells you why.

Several version 9 habits stop working

If you’re coming from Rocky or AlmaLinux 9, some of your muscle memory is now wrong. These are the changes from the RHEL 10 adoption guide that matter for this setup. We saw the first three on both machines; the rest come from the guide:

Change since 9What you’ll notice
dnf skips filelists metadataThe first file-path lookup downloads it on demand
Modularity deprecated, no modular contentdnf module list prints a deprecation warning
ifcfg files removedNo /etc/sysconfig/network-scripts; connections are NetworkManager keyfiles
firewalld lockdown removedThe lockdown option and its allow list are gone
cgroups v1 removedsystemd boots in cgroups v2 only
nscd removedName caching moves to systemd-resolved and sssd
x86-64-v3 baselineCPUs without AVX2 can’t run the default build

The filelists change is the one you’ll feel. On the Rocky VM, the cache held no filelists before this lookup:

time (sudo dnf provides /usr/sbin/semanage)

The first run took 55 seconds because dnf fetched filelists for every enabled repo, EPEL included. The second took half a second. That trade is fine on a server you configure once. If you run dnf provides constantly, Red Hat documents adding optional_metadata_types=filelists under [main] in /etc/dnf/dnf.conf; the option is empty on both distros. Network connections tell the same story about ifcfg, since both images keep theirs as keyfiles.

nmcli -g NAME,FILENAME connection show

The connection file sits under NetworkManager, not under the old network-scripts directory:

cloud-init eth0:/etc/NetworkManager/system-connections/cloud-init-eth0.nmconnection
lo:/run/NetworkManager/system-connections/lo.nmconnection

Edit connections with nmcli or nmtui. NetworkManager no longer reads ifcfg files, so one copied from a version 9 box won’t configure anything.

Neither cloud image runs a firewall

Both GenericCloud images leave firewalld out, on the assumption that a cloud security group does the filtering. That does not hold on Proxmox, a home lab or a VPS with a public address, so install it and start it on boot.

sudo dnf install -y firewalld
sudo systemctl enable --now firewalld

Now list what the default zone lets in. Nothing in either image customises firewalld, so this is the stock policy:

sudo firewall-cmd --list-all

Both distros came up with the same public zone on eth0:

public (default, active)
  target: default
  ingress-priority: 0
  egress-priority: 0
  icmp-block-inversion: no
  interfaces: eth0
  sources:
  services: cockpit dhcpv6-client ssh
  ports:
  protocols:
  forward: yes
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules: 

Look at the services line, because it is the whole policy for that interface. Anything you don’t see there is rejected:

  • ssh: TCP 22
  • dhcpv6-client: UDP 546, for IPv6 address leases
  • cockpit: TCP 9090

The default zone allows Cockpit, so firewalld on its own does not close port 9090 on Rocky. It only stops other ports from opening by accident, and the next section decides what happens to 9090. For zones, rich rules and per-interface policy, see our firewalld walkthrough.

Rocky’s image leaves Cockpit listening

The Rocky cloud image installs four Cockpit packages (cockpit-ws, cockpit-system, cockpit-bridge and cockpit-ws-selinux) and enables cockpit.socket. Before we added firewalld, curl from a second machine on the LAN got an HTTP 200 login page from port 9090. The cloud user has no password, so nobody could log in with it, but any local account with a password could, and you didn’t ask for that listener. The AlmaLinux image has no Cockpit at all.

Decide whether you want the web console, and make the listener and the firewall agree with that decision:

  • No console: disable the socket, drop the zone service
  • Console wanted: install cockpit, keep the zone service

The first case, run on Rocky, turns the socket off and removes the service from the zone in one go.

sudo systemctl disable --now cockpit.socket
sudo firewall-cmd --permanent --remove-service=cockpit
sudo firewall-cmd --reload
sudo firewall-cmd --list-services

The zone keeps only SSH and the DHCPv6 client, and ss -tln no longer shows 9090. The socket unit is disabled as well, so a reboot won’t bring the listener back:

dhcpv6-client ssh

If you do want it, install the full package and enable the socket. That’s 32 packages on the AlmaLinux image, which ended up with Cockpit 356 listening on 9090:

sudo dnf install -y cockpit
sudo systemctl enable --now cockpit.socket

Cloud images create the login user without a password, so give yours one first with sudo passwd followed by the user name. Then log in at https://10.0.1.51:9090 and accept the self-signed certificate warning, which Cockpit shows until you install a real certificate. Our Cockpit dashboard guide walks through the panels, certificates and adding more hosts.

SELinux now treats /var/opt as /opt

Leave SELinux enforcing. Both images ship that way and nothing in this list needs it off. What changed is how you label /var/opt. Starting with the 10.2 point release, the policy declares /var/opt equivalent to /opt, and equivalency beats any rule written for the /var/opt path itself. Software that keeps state there (Red Hat names logrotate and monitoring agents) inherits usr_t unless you label the matching /opt path instead.

AlmaLinux does not ship semanage, so install it there first. Rocky already has it, along with setroubleshoot-server.

sudo dnf install -y policycoreutils-python-utils

Now try the rule the way you would have written it on version 9, for a log directory under /var/opt/myapp:

sudo mkdir -p /var/opt/myapp/logs
sudo semanage fcontext -a -t var_log_t "/var/opt/myapp/logs(/.*)?"

Both distros refuse it, and the error message already names the rule you should write instead:

ValueError: File spec /var/opt/myapp/logs(/.*)? conflicts with equivalency rule '/var/opt /opt'; Try adding '/opt/myapp/logs(/.*)?' instead

Write the rule against /opt, then run restorecon on the real /var/opt directory. That is the recipe Red Hat gives, and the files never move.

sudo semanage fcontext -a -t var_log_t "/opt/myapp/logs(/.*)?"
sudo restorecon -Rv /var/opt/myapp/logs
ls -Zd /var/opt/myapp/logs

The directory moves from usr_t to var_log_t. The rule names the /opt path, yet the label lands on /var/opt, which is the equivalency doing its job:

semanage rejects a /var/opt rule on Rocky Linux 10, the /opt rule relabels it

What happens on a machine you upgraded from an earlier 10.x with its own /var/opt rules? Those rules are ignored after the upgrade, so the service that used them starts collecting denials. Red Hat’s note points at these:

  • rules you added with semanage for /var/opt paths
  • third-party packages that ship their own /var/opt contexts
  • logrotate or monitoring agents writing under /var/opt

Check with sudo ausearch -m avc -ts recent and re-create each rule on the /opt side. Our SELinux troubleshooting guide covers reading those denials.

Root can still log in by key

Before you change anything here, confirm you’re logged in as a non-root user with sudo and a working key, because this step removes root as a way back in. Password logins are already off on both images, because cloud-init writes PasswordAuthentication no into /etc/ssh/sshd_config.d/50-cloud-init.conf. Root login is not off. The effective setting is without-password, so a key in /root/.ssh/authorized_keys logs you straight in as root. sshd_config pulls in sshd_config.d/*.conf near its top, and sshd keeps the first value it reads for each option. Drop-ins load in name order, so a file you name to sort before 50-cloud-init.conf wins:

echo "PermitRootLogin no" | sudo tee /etc/ssh/sshd_config.d/10-root-login.conf
sudo sshd -t && sudo systemctl reload sshd

Keep your current session open and confirm the running values from a second terminal before you log out. If the reload broke something, the open session is how you fix it.

sudo sshd -T | grep -E "^(permitrootlogin|passwordauthentication) "

Both should read no. If permitrootlogin still shows without-password, another drop-in sorts ahead of yours and sets it first:

permitrootlogin no
passwordauthentication no

Moving SSH off port 22 needs an SELinux port label as well as a firewall rule, which our SSH port change guide covers.

AlmaLinux keeps the journal in memory

With the Storage=auto default of the systemd build these releases ship, journald stores logs on disk only when /var/log/journal exists. The Rocky image has that directory. The AlmaLinux image does not, so its journal lives in /run and is gone after every reboot. We noticed because journalctl --list-boots on Alma showed one boot after two, while Rocky kept all four of its boots. A kernel panic you can’t read afterwards is the classic cost. Create the directory with the right ownership, restart journald, then ask it to move what’s already in /run to disk:

sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald
sudo journalctl --flush

Check the label and the size on disk. The tmpfiles step matters because it gives the directory the systemd-journal group and setgid bit that a bare mkdir leaves out:

ls -Zd /var/log/journal
sudo journalctl --disk-usage

The directory carries var_log_t, and after the flush the boot’s system.journal sat under /var/log/journal:

system_u:object_r:var_log_t:s0 /var/log/journal
Archived and active journals take up 16M in the file system.

There’s nothing to do on Rocky here, which is one of the few places it’s ahead of Alma. Leave the default size limits alone unless the disk is small, since journald caps itself at a share of the filesystem.

tuned ships only on AlmaLinux

AlmaLinux’s image runs tuned with the virtual-guest profile from the first boot. Rocky’s does not include it, and installing it pulled 70 packages on our VM, most of them Perl modules dragged in by its helper tools. That’s still worth it on a VM, because virtual-guest tunes dirty-page writeback and swappiness for a guest:

sudo dnf install -y tuned
sudo systemctl enable --now tuned
sudo tuned-adm recommend
sudo tuned-adm profile virtual-guest
tuned-adm active

recommend picked virtual-guest on the Proxmox VM, and active confirmed it. The profile builds on throughput-performance, then sets vm.swappiness to 30 and dirty memory to 30%:

Current active profile: virtual-guest

On bare metal, use whatever tuned-adm recommend prints rather than copying the VM profile.

Security updates install on a timer

dnf-automatic installs with every timer disabled on both distros, and its stock config downloads updates without ever applying them. Three lines in /etc/dnf/automatic.conf decide what it does:

  • upgrade_type = default, meaning every update
  • download_updates = yes with apply_updates = no
  • reboot = never

Limit it to security errata, then enable the timer variant that installs. dnf-automatic-install.timer passes --installupdates, which applies updates whatever apply_updates says, so you don’t need to edit that line.

sudo dnf install -y dnf-automatic
sudo sed -i "s/^upgrade_type = default/upgrade_type = security/" /etc/dnf/automatic.conf
sudo systemctl enable --now dnf-automatic-install.timer
systemctl list-timers dnf-automatic-install.timer --no-pager

The timer fires at 06:00 with up to an hour of random delay, so a fleet doesn’t hit the mirrors at once:

NEXT                        LEFT LAST PASSED UNIT                        ACTIVATES
Fri 2026-10-23 06:44:46 EAT  19h -         - dnf-automatic-install.timer dnf-automatic-install.service

Don’t wait a day to find out whether it works. Start the service once by hand with sudo systemctl start dnf-automatic-install.service, then read journalctl -u dnf-automatic-install.service. Ours finished in under a second of CPU because the box was already patched. reboot = never stays as it is, so pair the timer with dnf needs-restarting -r in your monitoring.

Where Rocky and AlmaLinux actually differ

So is the older claim wrong? Partly. Both rebuild the same RHEL sources, our two machines ran the same kernel and SELinux policy builds after updates, and every command above worked on both. The difference is in the defaults each project picks and in what AlmaLinux adds on top of RHEL. The AlmaLinux 10.2 release notes list those deviations, and the last two rows come from our own images.

ItemRocky Linux 10AlmaLinux 10
CRB repositoryDisabled until you enable itEnabled by default
CPU baselinex86-64-v3 onlyx86-64-v3, plus a separate x86-64-v2 build for older hardware
EPEL for x86-64-v2Not applicableRebuilt by AlmaLinux
32-bit userspaceNoi686 userspace, no i686 kernel or installer
BtrfsNoSupported, including booting from Btrfs
Cloud image extrasCockpit socket on, semanage, persistent journaltuned on, volatile journal
Kernel release tag6.12.0-211.16.1.el10_2.0.1 in the image6.12.0-211.64.1.el10_2 in the image

The CPU row is the one that can stop an install, so check what your hardware supports before you pick. The dynamic loader reports it without installing anything.

/usr/lib64/ld-linux-x86-64.so.2 --help | grep -A4 Subdirectories

Our Proxmox host, an 11th-gen Intel Core i7 passed through with cpu=host, supports every level up to v4:

Subdirectories of glibc-hwcaps directories, in priority order:
  x86-64-v4 (supported, searched)
  x86-64-v3 (supported, searched)
  x86-64-v2 (supported, searched)

The loader lists every level whether or not the CPU has it, so read the suffix, not the name. If the x86-64-v3 line does not end in (supported, searched), the default builds of both distros won’t run, and AlmaLinux’s v2 build is the only one of the two that will. Run this check from whatever OS is already on the machine (any glibc 2.33 or newer prints the list), because a v3 build can’t boot there to run it. On a VM, check the CPU type first: a generic model hides features the host has, so set it to host before you blame the hardware. On anything newer, the choice comes down to defaults you’ve now changed anyway. Our Rocky vs AlmaLinux vs RHEL comparison covers governance, support terms and release timing.

Prove it from outside

Every check so far ran on the server itself, which only tells you what the server believes. A scan from another machine tells you what an attacker on your network sees. We ran nmap from a third VM against the Rocky box (Cockpit removed) at 10.0.1.50 and the Alma box (Cockpit kept) at 10.0.1.51:

sudo nmap -Pn -p 22,80,443,9090 10.0.1.50 10.0.1.51

Each host shows exactly the ports you chose to open, and nothing else answers. Ports 80 and 443 read filtered on both because firewalld rejects them with an ICMP admin-prohibited reply, which nmap --reason prints as admin-prohibited:

nmap from a probe host shows Rocky Linux 10 with only SSH and AlmaLinux 10 with SSH and Cockpit 9090

On Rocky, 9090 now reads filtered. Before this setup the same port returned a Cockpit login page to any machine on the LAN. On Alma, 9090 is open because you chose Cockpit there. Each state means something different for your firewall:

  • open: a service listens and the zone lets you in
  • filtered: firewalld rejected or dropped the probe
  • closed: the probe got through, nothing listens

If a port you closed shows open, check firewall-cmd --list-all for the zone the interface is actually in. A closed result where you expected filtered means the firewall rule is the missing part, even though nothing answered this time.

Keep reading

Patch PHP2Shell on RHEL, Rocky Linux and AlmaLinux 10 / 9 / 8 AlmaLinux Patch PHP2Shell on RHEL, Rocky Linux and AlmaLinux 10 / 9 / 8 Customize KDE Plasma Desktop with Themes|Modules|Extensions AlmaLinux Customize KDE Plasma Desktop with Themes|Modules|Extensions Create and Configure Bridge Networking For KVM in Linux Virtualization Create and Configure Bridge Networking For KVM in Linux Linux Terminal Shortcuts Cheat Sheet (Bash and zsh) Cheat Sheets Linux Terminal Shortcuts Cheat Sheet (Bash and zsh) Upgrade Zabbix 7.0 to 8.0 LTS on Ubuntu 26.04 and Rocky Linux 10 Monitoring Upgrade Zabbix 7.0 to 8.0 LTS on Ubuntu 26.04 and Rocky Linux 10 Set up MicroK8s Kubernetes on Rocky / AlmaLinux AlmaLinux Set up MicroK8s Kubernetes on Rocky / AlmaLinux

Leave a Comment

Press ESC to close