If you ran CentOS for any length of time, you know the feeling. It was the OS you installed once, tuned once, and then largely ignored while it kept your servers running for years. It was predictable in the best possible way. Then, on December 8, 2020, Red Hat announced that CentOS Linux 8 would reach end of life at the end of 2021 -- four years ahead of schedule -- and that the CentOS project would be repositioned as CentOS Stream, an upstream development branch of RHEL rather than a downstream stable clone. CentOS 7 followed with its scheduled end of life in June 2024.
The community response was immediate. Engineers who had built their entire infrastructure on CentOS needed a replacement that matched the stability guarantee they had come to depend on. AlmaLinux was one of the first and most serious answers to that call. Understanding why it was built the way it was built is not just historical trivia -- it explains the specific choices AlmaLinux makes that distinguish it from a generic "another Linux distro" and make it the right choice for anyone migrating from CentOS.
The CentOS Collapse: What Actually Happened
Before installing anything, it is worth understanding the technical and political context. CentOS Linux was a downstream rebuild of RHEL -- it took Red Hat's source RPMs (which Red Hat is required to publish under the GPL), stripped out Red Hat's trademarks and branding, recompiled everything, and produced a free, binary-compatible distribution. For over a decade, it served as the unofficial "free RHEL" for organizations that wanted enterprise-grade stability without a support contract.
Red Hat's December 2020 announcement did not just change a support date. It changed the entire relationship between the community and the source code. CentOS Stream became a rolling preview of the next RHEL minor version, not a re-release of the current one. A bug or security issue in CentOS Stream might be fixed before it appears in RHEL, or it might not. The stability guarantee that made CentOS valuable as a production OS vanished by design.
The situation deepened in June 2023 when Red Hat announced restrictions on access to RHEL source code, limiting it to customers with active subscriptions. Wikipedia's AlmaLinux article documents the AlmaLinux Foundation's response: the board announced it would drop the aim of being 1:1 with RHEL and instead focus on maintaining application binary compatibility -- ensuring software compiled for RHEL runs on AlmaLinux, even if the underlying package builds come from a different source. This was a pragmatic adaptation that has kept AlmaLinux on a stable trajectory.
In response to Red Hat's source code restrictions, the AlmaLinux OS Foundation publicly announced it was abandoning the goal of being a 1:1 RHEL rebuild, pivoting instead to maintaining binary (ABI) compatibility. The full statement was published on almalinux.org on July 12, 2023. The post states that AlmaLinux will focus on being "ABI compatible" -- compatible at the binary interface level, ensuring that applications built for RHEL run on AlmaLinux without recompilation, even if the underlying build paths differ. This was a deliberate, publicly documented pivot, not a quiet policy change.
In the board's own words, the new goal was to be "binary compatible with RHEL" -- a deliberate, publicly documented pivot away from 1:1 rebuilding.
-- AlmaLinux OS Foundation board statement, July 12, 2023. Source: almalinux.org
What this means practically: your applications and libraries compiled for RHEL 8 or RHEL 9 will run on AlmaLinux 8 or AlmaLinux 9 without recompilation. The ABI (Application Binary Interface) is maintained even when the source path has shifted. This is the promise that makes AlmaLinux worth migrating to, rather than just picking a different Linux distribution entirely.
AlmaLinux's Governance Structure
AlmaLinux's independence from Red Hat's decisions is structurally enforced by its ownership model. AlmaLinux is governed by the AlmaLinux OS Foundation, a 501(c)(6) non-profit corporation. CloudLinux -- the company that launched the project and pledged $1 million in annual funding -- transferred ownership of the project to this foundation in March 2021. CloudLinux does not own the copyright on AlmaLinux and cannot unilaterally change its direction. The board is community-elected, and since 2022 has been chaired by Benny Vasquez, a community representative rather than a CloudLinux executive.
In 2024, CERN, Megware, Virtuozzo, Fastly, and Meta Platforms all joined as sponsor members. CERN and Fermilab had already designated AlmaLinux as their standard operating system for experimental computing in December 2022. When the organizations running the Large Hadron Collider adopt your OS for scientific computing infrastructure, that says something concrete about production readiness.
Understanding AlmaLinux Versions and Release Cadence
AlmaLinux follows RHEL's major and minor version scheme. AlmaLinux 8 corresponds to RHEL 8, AlmaLinux 9 to RHEL 9, and AlmaLinux 10 (released May 27, 2025, codenamed "Purple Lion") to RHEL 10. The version numbering is intentional -- when you see an AlmaLinux package version tagged el8, el9, or el10, those packages are compatible with the corresponding RHEL version's ecosystem.
Minor version releases (9.3, 9.4, 9.5, 9.6, and so on) are released within approximately six days of the corresponding RHEL minor version. According to the AlmaLinux 2024 recap blog post, the team's goal is to be tested and ready by Thursday following a RHEL Tuesday release, with the extra days absorbed by the additional verification the AlmaLinux Build System (ALBS) performs before shipping. Security and package updates often arrive faster -- sometimes within 24 hours. The minor-version lag is deliberate; it is the cost of the additional testing that gives you confidence in what you are installing.
One critical lifecycle detail: minor versions of AlmaLinux reach end-of-life when the next minor version releases. AlmaLinux 9.6 reached end of life when 9.7 released on November 17, 2025. This is different from the major version lifecycle, which provides ten full years of support (five active, five security). AlmaLinux 9 has active support until May 31, 2027 and security support until May 31, 2032. AlmaLinux 10 has active support until May 31, 2030 and security support until May 31, 2035. AlmaLinux 8's active support ended May 2024 -- it still receives security patches until 2029, but if you are still on AlmaLinux 8, migration to AlmaLinux 9 or 10 should be on your roadmap. Always run the latest minor version of your chosen major series. There is no reason to remain on an older minor version -- they receive no patches after the next point release ships.
Choosing the Right ISO
AlmaLinux offers several ISO variants, and picking the wrong one for your use case creates unnecessary work. The download page at almalinux.org/get-almalinux lists them all, but the choice comes down to three primary options for most use cases.
The Minimal ISO is the right choice for servers. It contains only the packages needed to boot and run a base system. Everything else gets installed after the fact via DNF. This approach minimizes the attack surface from day one, keeps the initial install small (typically under 1 GB), and forces you to be deliberate about what software runs on the system. This is the production-server default.
The DVD ISO contains the full package repository and can install any software selection without internet access during installation. At roughly 9-10 GB, it is the right choice for air-gapped environments or when you know you need the full development toolchain, GUI, or a large set of packages during installation itself.
The Boot ISO is the smallest -- just enough to boot into the Anaconda installer and then pull all packages from the network. This is ideal for fleet deployments where network access is guaranteed and you want every installed package to be the latest available version at install time, rather than the version baked into a DVD image months ago.
Always verify the SHA256 checksum of the downloaded ISO before creating boot media. AlmaLinux publishes checksums alongside the ISO files. A corrupted ISO produces silent errors that can look like hardware failures or installer bugs. Run sha256sum AlmaLinux-9.7-x86_64-minimal.iso and compare the output against the published CHECKSUM file. For environments where supply-chain integrity matters, go one step further: AlmaLinux signs its CHECKSUM files with a GPG key. Download the appropriate key from https://repo.almalinux.org/almalinux/RPM-GPG-KEY-AlmaLinux-9, import it with gpg --import, then run gpg --verify CHECKSUM. You are looking for "Good signature from 'AlmaLinux OS 9'" in the output -- this confirms the CHECKSUM file itself was not tampered with after AlmaLinux signed it.
To download and verify from the command line:
# Download the minimal ISO (replace 9.7 with your target version) $ wget https://repo.almalinux.org/almalinux/9.7/isos/x86_64/AlmaLinux-9.7-x86_64-minimal.iso $ wget https://repo.almalinux.org/almalinux/9.7/isos/x86_64/CHECKSUM # Verify the checksum $ sha256sum -c CHECKSUM --ignore-missing # Should output: AlmaLinux-9-latest-x86_64-minimal.iso: OK # Write to USB (replace /dev/sdX with your USB device from lsblk) $ sudo dd if=AlmaLinux-9.7-x86_64-minimal.iso of=/dev/sdX bs=4M status=progress oflag=direct $ sync
Inside the Anaconda Installer
AlmaLinux uses the Anaconda installer, the same tool used by RHEL and Fedora. If you have installed CentOS, you already know Anaconda. If you have not, the mental model is important: Anaconda uses a hub-and-spoke design where a central Installation Summary screen shows all configuration categories, and you navigate into each spoke, configure it, and return to the hub. Items marked in red are required before installation can begin.
After booting from your installation media, you will be presented with a GRUB menu. Select "Test this media & install AlmaLinux" to first verify the integrity of your installation media -- this takes a couple of minutes but will save you from an interrupted installation caused by a write error during ISO burning. If you have already verified the checksum as shown above, you can skip to "Install AlmaLinux" directly.
The three mandatory spokes you must configure are: Installation Destination (disk partitioning), Root Password, and on minimal installs, network configuration is not mandatory but should be considered required for any production system. Choose your language first -- this controls the locale settings baked into the installation.
Disk Partitioning and LVM: Do It Right the First Time
This is the section where many installations go wrong. The default automatic partitioning will create a workable system, but it will eventually create problems on production servers -- a runaway log file filling /var/log can cause the root partition to run out of space and crash everything if they share the same logical volume. Separate partitioning is not optional for production; it is how professional servers are built.
The key concept is LVM -- Logical Volume Manager. LVM introduces an abstraction layer between physical storage devices and the filesystems mounted on them. A Physical Volume (PV) is a raw disk or partition. A Volume Group (VG) pools one or more Physical Volumes into a single storage namespace. Logical Volumes (LVs) are carved out of the Volume Group and each gets its own filesystem. The power of LVM comes from flexibility: you can extend a Logical Volume online without unmounting it, add a new Physical Volume to grow the pool, take point-in-time snapshots for backups, and thin-provision storage.
If your system supports UEFI (any hardware from approximately 2012 onward does), use a GPT partition table, not MBR. GPT supports more than 4 primary partitions, handles disks larger than 2 TB, stores partition table redundancy at both ends of the disk, and is required for UEFI Secure Boot. The Anaconda installer will default to GPT on UEFI systems. If you are installing to a VM or older hardware in legacy BIOS mode, you will get an MBR table and no /boot/efi partition -- that is expected in that scenario.
For a production AlmaLinux server, the recommended partition layout looks like this:
# Standard partitions (outside LVM -- must be standard) /boot 1 GB ext4 # Kernel, initramfs -- cannot be LVM /boot/efi 512 MB EFI # Required on UEFI systems # LVM: one Physical Volume, one Volume Group # vg_almalinux: remaining disk space lv_root 20 GB xfs / # OS files, binaries lv_home 10 GB xfs /home # User data, isolated lv_var 15 GB xfs /var # Package cache, databases lv_varlog 8 GB xfs /var/log # Log files isolated from /var lv_tmp 5 GB xfs /tmp # Temporary files lv_swap = RAM swap # 1x RAM for servers under 16 GB
The separation of /var/log from /var is particularly important. Log files can grow to fill their partition in the event of an application bug, a verbose audit trail, or a log injection attack. If /var/log fills up inside a shared /var partition, package installations fail because DNF writes to /var/cache. If /var/log is isolated, a runaway log only fills that specific volume, and everything else keeps running.
XFS is the default filesystem for AlmaLinux (and RHEL). It is a mature, high-performance journaling filesystem that supports online expansion with xfs_growfs -- meaning you can extend an XFS volume while it is mounted and in use. This is how you expand production systems without downtime: add storage, extend the LV, then extend the filesystem. The only caveat is that XFS cannot shrink in place; plan your initial allocations conservatively and leave free space in the VG to grow into.
After installation, add mount options to /etc/fstab for security partitioning. The /tmp and /var/tmp entries should include noexec (prevents binary execution from temporary directories), nosuid (prevents setuid bits from taking effect), and nodev (prevents character/block device files). These three options block a large class of privilege escalation attacks that stage malicious binaries in world-writable directories.
Software Selection and Base Environments
The Software Selection spoke in Anaconda presents base environments and optional add-ons. For a server, there are two meaningful choices: Minimal Install and Server. The distinction is not just philosophical -- it is technical.
Minimal Install produces the smallest possible working system. No NetworkManager GUI, no Cockpit web interface, no development tools. You get the kernel, systemd, bash, and the core utilities. Everything else you install deliberately. This is the correct choice for production servers where you know exactly what workload the machine will run.
Server includes Cockpit (the web-based administration panel), more network tooling, and performance analysis tools. It is reasonable for servers that will be administered by teams less comfortable with the CLI, or where the Cockpit interface provides operational value.
What you absolutely should not do for a production server is install "Server with GUI." A graphical environment adds hundreds of packages, creates a larger attack surface, consumes memory, and provides no operational benefit for a headless server. If you need a GUI for administration, use the web-based Cockpit interface instead.
Cockpit: The Web Console CentOS Never Had
CentOS had no first-party web administration interface. AlmaLinux inherits Cockpit from the RHEL lineage, and it is worth knowing even if you live entirely in the terminal. Cockpit gives you a browser-based view of system metrics, service status, storage, networking, and software updates -- useful for delegating routine administration to team members who are not comfortable with the CLI, or for a quick visual health check when you are not at your usual workstation.
Cockpit is not installed by the Minimal Install environment, which is correct -- you should not run it on servers that do not need it. Install it deliberately on machines where it provides value:
# Install Cockpit $ sudo dnf install cockpit -y # Enable and start the cockpit socket (uses socket activation -- only starts on demand) $ sudo systemctl enable --now cockpit.socket # Open port 9090 in firewalld $ sudo firewall-cmd --permanent --add-service=cockpit $ sudo firewall-cmd --reload # Access via browser: https://your-server-ip:9090 # Log in with your Linux username and password (wheel group members can run sudo) # Extend Cockpit with optional modules $ sudo dnf install cockpit-storaged -y # LVM/storage management UI $ sudo dnf install cockpit-podman -y # Container management $ sudo dnf install cockpit-packagekit -y # Package update UI
The first time you access Cockpit, your browser will warn about an untrusted certificate. This is expected -- Cockpit generates a self-signed certificate on install. For internal administration access, you can accept the exception. For a production environment accessible beyond your local network, place a trusted TLS certificate in /etc/cockpit/ws-certs.d/ and restart the cockpit service. Cockpit also integrates with Let's Encrypt certificates if you are using Certbot on the same machine.
Post-Installation: The First Commands
The system boots. You log in. What happens next is what separates a hardened production system from a default install that will eventually cause you trouble. These are the commands to run immediately after first login.
Confirm the System Identity
# Verify AlmaLinux version and kernel $ cat /etc/almalinux-release # AlmaLinux release 9.7 (Moss Jungle Cat) $ uname -r # 5.14.0-611.5.1.el9_7.x86_64 $ cat /etc/os-release # NAME="AlmaLinux" # ID="almalinux" # ID_LIKE="rhel centos fedora" # Confirm architecture and platform $ arch $ hostnamectl
Full System Update
Before doing anything else, bring the system fully current. Even a freshly installed system from an ISO that is two months old may have critical security patches outstanding.
# Update all installed packages $ sudo dnf update -y # Check for security-only updates (without installing) $ sudo dnf check-update --security # Install security updates only $ sudo dnf update --security -y # Reboot to load a new kernel if one was installed $ sudo reboot
systemd: The Init System CentOS Veterans Need to Know
If your CentOS experience predates CentOS 7, you used SysV init: service httpd start, chkconfig httpd on, hand-edited scripts in /etc/init.d/. CentOS 7 introduced systemd, and AlmaLinux 8, 9, and 10 continue that lineage. The commands are different but the mental model maps cleanly. This section covers the operations you will run on almost every server, every day.
systemd manages services (called units) and their dependencies. When you install a package like nginx or postgresql-server, it ships with a unit file in /usr/lib/systemd/system/. That file defines how the service starts, what it depends on, and when it should run relative to other services. You do not edit those files -- they belong to the package. If you need to override settings, drop a file in /etc/systemd/system/ as described below. For a full reference on systemd unit files, targets, and the journal, see the dedicated guide.
# The CentOS-to-AlmaLinux command mapping # Old: service httpd start New: $ sudo systemctl start httpd # Old: service httpd stop $ sudo systemctl stop httpd # Old: service httpd restart $ sudo systemctl restart httpd # Reload config without full restart (if the service supports it) $ sudo systemctl reload httpd # Old: chkconfig httpd on $ sudo systemctl enable httpd # Enable AND start in one command (most common for new installs) $ sudo systemctl enable --now httpd # Old: chkconfig httpd off $ sudo systemctl disable httpd # Old: service httpd status $ sudo systemctl status httpd # See the last 50 log lines for a service (no more /var/log/httpd/error_log fishing) $ sudo journalctl -u httpd -n 50 # Follow logs in real time (like tail -f, but for any service) $ sudo journalctl -u httpd -f # Show logs since last boot only $ sudo journalctl -u httpd -b # List all failed services (your morning health check) $ systemctl list-units --state=failed # List all enabled services $ systemctl list-unit-files --state=enabled # Check what caused the last boot failure $ sudo journalctl -b -1 -p err # -b -1 = previous boot, -p err = error and above
The journalctl command replaces hunting through log files in /var/log/. Every service that writes to systemd's journal -- which is almost all of them -- gets queried the same way regardless of whether the service wrote to syslog, stdout, or a custom log socket. This is the single biggest quality-of-life improvement for anyone coming from SysV init systems.
Overriding a Unit File Without Editing It
A common situation: you install a service and need to adjust its startup options or resource limits, but you do not want to edit the package-owned unit file in /usr/lib/systemd/system/ because the next package update will overwrite it. The correct pattern is a drop-in override:
# Open the override editor for a service (creates the right directory automatically) $ sudo systemctl edit httpd # This opens an editor for /etc/systemd/system/httpd.service.d/override.conf # Add only the stanzas you want to change, e.g.: # [Service] # LimitNOFILE=65536 # MemoryMax=2G # After saving, reload the daemon so systemd reads the new file $ sudo systemctl daemon-reload $ sudo systemctl restart httpd # Verify the override took effect $ systemctl show httpd | grep LimitNOFILE $ systemctl cat httpd # shows the full merged unit: base file + your overrides, with source paths
When systemctl start returns an error, the first move is sudo systemctl status servicename -- it shows the last few log lines inline. If that is not enough, sudo journalctl -u servicename -n 100 --no-pager gives you the full recent history. For services that fail during boot before the network or filesystem is ready, sudo journalctl -b -u servicename scopes the search to the current boot session only, which avoids noise from previous failed attempts.
DNF: Understanding the Package Manager Under the Hood
DNF (Dandified YUM) is AlmaLinux's package manager. It replaced YUM in the RHEL 8 generation, though yum still works as an alias. The name "Dandified" is a joke -- DNF is a complete rewrite of YUM using modern Python, with significantly better dependency resolution, proper transaction history, and module stream support.
The dependency resolver is the part worth understanding. When you install a package, DNF builds a dependency graph -- it must satisfy every dependency of the package you want, and every dependency of those dependencies, without creating version conflicts. DNF uses a SAT (Boolean satisfiability) solver to find a valid package set. This is computationally expensive for large transactions, which is why complex dnf install commands take a moment to calculate before they show you the package list.
On a fresh AlmaLinux install, you may see a message like This system is not registered with an entitlement server or subscription-manager is not installed when running dnf commands. This is harmless and expected. AlmaLinux does not use Red Hat's subscription management system -- it has its own free repositories. The warning often appears because dnf checks for a subscription management plugin, does not find an active subscription, and logs a notice. You can safely ignore it, or suppress it by running sudo dnf config-manager --set-disabled subscription-manager if the plugin is installed, or by setting enabled=0 in /etc/rhsm/pluginconf.d/subscription-manager.dnfplugin.conf. You do not need a Red Hat subscription to use AlmaLinux.
AlmaLinux's repositories are structured into specific channels. Understanding which repo provides what is essential for managing a production system:
# Show all enabled repositories $ dnf repolist # repo id repo name # appstream AlmaLinux 9 - AppStream # baseos AlmaLinux 9 - BaseOS # extras AlmaLinux 9 - Extras # crb AlmaLinux 9 - CRB (optional source packages) # Enable EPEL (Extra Packages for Enterprise Linux) -- highly recommended $ sudo dnf install epel-release -y # Enable CRB (CodeReady Builder) -- needed for some dev packages $ sudo dnf config-manager --set-enabled crb # Inspect a repo's configuration file $ cat /etc/yum.repos.d/almalinux-baseos.repo # Search for a package by name or description $ dnf search nginx # Show what package provides a specific file $ dnf provides /usr/bin/python3 # List packages installed from a specific repo $ dnf list installed --disablerepo="*" --enablerepo="epel" # View transaction history $ dnf history $ dnf history info 5 # Details of transaction 5 # Roll back a specific transaction (undo install #5) $ sudo dnf history undo 5
The BaseOS repository contains the core OS packages -- the kernel, glibc, systemd, and other foundational components. AppStream is where most application packages live, including web servers, databases, and development runtimes. AppStream introduced the concept of module streams, which allow multiple versions of the same software to coexist (for example, Python 3.9 and Python 3.11, or MariaDB 10.5 and MariaDB 10.6) with a mechanism to switch between them:
# List available module streams $ dnf module list # Show available streams for a specific module $ dnf module list postgresql # Enable a specific stream (e.g., PostgreSQL 15) $ sudo dnf module enable postgresql:15 -y $ sudo dnf install postgresql-server -y # Check which stream is active $ dnf module info postgresql
SELinux: Leave It On and Learn It
SELinux is the single most controversial component of RHEL-derived Linux distributions, and the advice to disable it is among the most damaging things you will find on the internet. AlmaLinux ships with SELinux in enforcing mode and the targeted policy by default. Both of these defaults are correct. Do not change them.
SELinux implements Mandatory Access Control (MAC). Traditional Linux permissions implement Discretionary Access Control (DAC) -- the file owner controls who can read, write, or execute. MAC operates at a different layer: even if the file permissions say a process can access a resource, SELinux can still deny the access based on the process's security context. A compromised Apache process running as apache_t cannot read your SSH private keys even if the file permissions would technically allow it -- SELinux denies the access at the kernel level.
The targeted policy confines only specific services (httpd, sshd, named, postgresql, and others), leaving unconfined processes -- like most user processes -- to run normally. This is the practical middle ground that protects the high-value attack targets without forcing you to write custom policy for every application.
# Check current SELinux status $ sestatus # SELinux status: enabled # SELinuxfs mount: /sys/fs/selinux # Current mode: enforcing # Loaded policy name: targeted # Temporarily switch to permissive mode (logs denials but doesn't block) $ sudo setenforce 0 # Return to enforcing mode $ sudo setenforce 1 # Check what SELinux context a file has $ ls -Z /var/www/html/ # system_u:object_r:httpd_sys_content_t:s0 # Restore default SELinux context on a file/directory $ sudo restorecon -Rv /var/www/html/ # View recent SELinux denials (AVC = Access Vector Cache) $ sudo ausearch -m avc -ts recent # Install setroubleshoot for human-readable denial explanations $ sudo dnf install setroubleshoot-server -y $ sudo sealert -a /var/log/audit/audit.log # Allow Apache to connect to the network (common boolean) $ sudo setsebool -P httpd_can_network_connect on # List all SELinux booleans and their current state $ getsebool -a | grep httpd
The workflow when SELinux blocks something you need: first, switch to permissive mode temporarily so the operation can complete while denials are logged. Then use sealert to read the denial logs and get suggested fixes. In many cases the fix is setting a boolean (setsebool -P) or restoring the correct context (restorecon). Only as a last resort should you write a custom policy module -- and never disable SELinux entirely just because something does not work.
A common SELinux trap: you copy a configuration file from a CentOS or RHEL system to your AlmaLinux system, and the service that reads it starts throwing SELinux denials. The problem is that the copy operation preserved the source file's SELinux context rather than inheriting the correct context for the destination directory. Run sudo restorecon -Rv /etc/servicename/ after copying configuration files to fix their security contexts.
firewalld: Zone-Based Firewall Management
AlmaLinux uses firewalld, a dynamic firewall manager that sits in front of the underlying iptables or nftables backend. The key concept in firewalld is zones -- predefined trust levels assigned to network interfaces or source IP ranges. An interface assigned to the public zone gets public-facing firewall rules. An interface assigned to the trusted zone allows all traffic. The dmz zone provides selective access for servers in a demilitarized zone.
# Check firewalld status $ sudo firewall-cmd --state # List all active zones and their interfaces $ sudo firewall-cmd --get-active-zones # List everything allowed in the default zone $ sudo firewall-cmd --list-all # Allow SSH (permanent -- survives reboot) $ sudo firewall-cmd --permanent --add-service=ssh # Allow HTTP and HTTPS $ sudo firewall-cmd --permanent --add-service=http $ sudo firewall-cmd --permanent --add-service=https # Open a specific port (e.g., custom application on port 8443) $ sudo firewall-cmd --permanent --add-port=8443/tcp # Reload to apply permanent changes $ sudo firewall-cmd --reload # Restrict SSH to a specific source subnet $ sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="10.0.0.0/8" service name="ssh" accept' $ sudo firewall-cmd --permanent --zone=public --remove-service=ssh $ sudo firewall-cmd --reload
The --permanent flag writes the rule to disk but does not activate it in the running firewall. Rules without --permanent apply immediately but vanish on reboot. The correct pattern for most changes: use --permanent to write the rule, then either --reload to apply all permanent rules, or omit --permanent first to test the rule live and then add it permanently once confirmed working.
ELevate: Migrating from CentOS Without a Reinstall
For administrators managing existing CentOS infrastructure, the prospect of reinstalling every server is daunting. ELevate, AlmaLinux's in-place migration tool, was built specifically for this scenario. According to the AlmaLinux ELevate page, it has been used to migrate over 500,000 devices. The tool is built on the Leapp upgrade framework, originally developed by Red Hat for in-place RHEL upgrades. As of December 18, 2025, AlmaLinux's ELevate support was merged into upstream Leapp with the release of leapp-repository 0.23.0, which means ongoing maintenance is now shared with the broader enterprise Linux community rather than maintained solely by AlmaLinux. One important consequence of this change: Rocky Linux migration support was removed from ELevate, as the required migration data for Rocky was not contributed upstream. If you are migrating to Rocky Linux, ELevate no longer supports that path as of leapp-repository 0.23.0.
The migration path ELevate supports: CentOS 6.x or 7.x to AlmaLinux 8, AlmaLinux 8 to AlmaLinux 9, and AlmaLinux 9 to AlmaLinux 10. To go from CentOS 7 all the way to AlmaLinux 10, you perform the migration in three hops: CentOS 7 to AlmaLinux 8, reboot and confirm, AlmaLinux 8 to AlmaLinux 9, reboot and confirm, then AlmaLinux 9 to AlmaLinux 10. Important: the original CentOS 7 repositories are now offline. Before running ELevate on a CentOS 7 machine, you must first point it at AlmaLinux's maintained CentOS 7 mirror. Also note that as of this writing, upgrades to AlmaLinux 10 do not support x86-64-v2 hardware -- if your server does not meet the x86-64-v3 baseline, you cannot currently ELevate to AlmaLinux 10. Check the AlmaLinux Wiki's ELevate guide for the current status of x86-64-v2 upgrade path support.
The ELevate/Leapp process works by building a special upgrade initramfs image. The system reboots into this image, which performs the actual package replacements at a level that would be impossible to do on a live running system. During this phase -- visible in the console as a second-stage boot process -- thousands of RPMs are swapped out and configuration files are migrated. The system then reboots twice more to complete the transition.
Take a full snapshot or backup of your system before running ELevate on any production machine. The AlmaLinux project strongly recommends testing the upgrade in a VM sandbox that mirrors your production environment before running it on live systems. Every environment has unique configurations, third-party packages, and kernel modules that may require pre-upgrade remediation.
ELevate failures generally fall into two categories. The first is a pre-upgrade inhibitor -- leapp preupgrade reports a blocking condition and refuses to proceed. This is the intended behavior: read /var/log/leapp/leapp-report.txt, resolve every item marked as an inhibitor, and re-run leapp preupgrade until the report is clean. Common inhibitors include multiple installed kernels, unsupported kernel modules, and legacy ifcfg-* network scripts. The second and more serious category is a failure during the upgrade initramfs phase -- the system has rebooted into the ELevate environment and something went wrong. If the system boots back into the original OS, the migration was rolled back automatically; check the upgrade log and fix the cause before retrying. If the system is stuck or cannot boot, use the installation media in rescue mode to access the filesystem at /mnt/sysimage and review /var/log/leapp/leapp-upgrade.log for the point of failure. Your snapshot or backup is your recovery path if the state is unrecoverable. Never migrate a system that does not have a tested, restorable backup.
# CRITICAL: CentOS 7 repos are offline -- swap to AlmaLinux's vault mirror first $ sudo curl -o /etc/yum.repos.d/CentOS-Base.repo https://el7.repo.almalinux.org/centos/CentOS-Base.repo # Step 1: Ensure CentOS 7 is fully updated on the vault repos $ sudo yum update -y $ sudo reboot # Step 2: Install the ELevate release package $ sudo yum install -y http://repo.almalinux.org/elevate/elevate-release-latest-el$(rpm --eval %rhel).noarch.rpm # Step 3: Install Leapp and AlmaLinux migration data $ sudo yum install -y leapp-upgrade leapp-data-almalinux # Step 4: Run the pre-upgrade check -- READ THIS OUTPUT CAREFULLY $ sudo leapp preupgrade # Step 5: Review the generated report for inhibitors $ sudo cat /var/log/leapp/leapp-report.txt # Common pre-upgrade fixes: # Remove pata_acpi kernel module (often flagged) $ sudo rmmod pata_acpi # Allow root SSH temporarily (required for Leapp process) $ echo PermitRootLogin yes | sudo tee -a /etc/ssh/sshd_config # Confirm PAM module removal $ sudo leapp answer --section remove_pam_pkcs11_module_check.confirm=True # Step 6: Run the actual upgrade (triggers reboot) $ sudo leapp upgrade # System reboots into ELevate-Upgrade-Initramfs # Upgrade takes 30-90 minutes depending on system size # System will reboot 2-3 more times automatically # After final reboot: verify the migration $ cat /etc/almalinux-release $ cat /etc/os-release $ rpm -qa | grep el7 # Any leftover CentOS 7 packages to clean up $ sudo cat /var/log/leapp/leapp-upgrade.log # To continue to AlmaLinux 9, repeat leapp steps on the new AlmaLinux 8 system # Then repeat again on AlmaLinux 9 to reach AlmaLinux 10
The leapp preupgrade step is the one to take seriously. It produces a comprehensive report of everything on your system that will cause problems during migration. Items marked as inhibitors will halt the upgrade -- these must be resolved before leapp upgrade will proceed. Items marked as high severity warnings will not stop the upgrade but may cause post-migration problems. Read every item in the report and understand what it is telling you before proceeding.
Common inhibitors in CentOS 7 to AlmaLinux 8 migrations include: multiple kernels installed (remove all but one), legacy network configuration scripts using ifcfg-* format instead of NetworkManager, EPEL packages that conflict with EL8 packages, and third-party kernel modules that do not exist in the EL8 kernel.
After the Migration: Verifying a Clean ELevate
ELevate gets the vast majority of systems to a clean post-migration state, but the first boot into the new major version warrants a systematic verification pass rather than assuming everything worked.
# Confirm the migration completed and you are on the right major version $ cat /etc/almalinux-release $ uname -r # Check for any packages still tagged el7 (el8 if you just migrated 7->8) # These are orphaned packages not replaced by the new release $ rpm -qa | grep el7 # Check for packages with no known repo (installed outside DNF, or from dead repos) $ dnf list extras # Look for any services that failed to start after migration $ systemctl list-units --state=failed # Check the leapp upgrade log for post-migration warnings $ sudo cat /var/log/leapp/leapp-upgrade.log | grep -E "WARNING|ERROR|CRITICAL" # Verify RPM database integrity $ sudo rpm -Va --nofiles 2>/dev/null | grep -E "^..5" # Lines starting with "5" indicate an MD5/checksum mismatch -- investigate each one # Check SELinux is still in enforcing mode (ELevate should preserve it) $ sestatus | grep mode # Check firewalld survived the migration $ sudo firewall-cmd --state $ sudo firewall-cmd --list-all # Revert the PermitRootLogin change if you set it for Leapp $ sudo grep PermitRootLogin /etc/ssh/sshd_config # If it reads "yes", change it back to "no" and restart sshd
The ELevate procedure above sets PermitRootLogin yes temporarily so the Leapp process can manage the system during the upgrade initramfs phase. After your post-migration verification is complete, make sure you have set it back to no and restarted sshd. Check /etc/ssh/sshd_config and any drop-in files in /etc/ssh/sshd_config.d/ -- Leapp may have added its configuration as a drop-in rather than modifying the main file.
AlmaLinux vs the Alternatives: An Honest Assessment
If you are migrating from CentOS, you are almost certainly aware that AlmaLinux is not the only option. Rocky Linux was created by Gregory Kurtzer, one of the original founders of CentOS, with the explicit goal of preserving what CentOS was. Oracle Linux is Red Hat's original downstream competitor. RHEL itself is available for developers and small production use under the developer program.
In terms of technical compatibility and package availability, AlmaLinux and Rocky Linux are nearly identical. Both maintain ABI compatibility with RHEL. Both use DNF, SELinux in targeted mode, firewalld, and the same base package set. The differences are governance, tooling, and philosophy. AlmaLinux has ELevate for in-place migration, the ALBS build system with publicly reproducible builds, and ALESCo (AlmaLinux Engineering Steering Committee) which can -- and does -- ship security patches independently ahead of RHEL. Rocky Linux has a different governance model under the Rocky Enterprise Software Foundation and historically tracked closer to RHEL source.
One differentiator that matters concretely in 2026: AlmaLinux 10 supports x86-64-v2 hardware, which RHEL 10 dropped. RHEL 10 raised the baseline to x86-64-v3, which requires AVX and related instruction sets introduced around Intel Sandy Bridge and AMD Excavator. AlmaLinux 10 follows the v3 default for performance-optimized binaries but also maintains an x86-64-v2 build for organizations that cannot or will not retire older hardware. For anyone running infrastructure on hardware from the 2012--2018 era, this is not a minor footnote.
Another concrete differentiator: frame pointers enabled by default. RHEL does not enable frame pointers system-wide; AlmaLinux 10 does. This means every process on the system can be profiled in real-time using tools like perf and BPF-based tracers without recompiling anything. For performance-sensitive workloads, this is the difference between guessing where your bottleneck is and measuring it precisely.
The ALESCo independent patching track is also a real differentiator. When the regreSSHion vulnerability (CVE-2024-6387) was disclosed by Qualys on July 1, 2024, AlmaLinux's ALESCo published a patch the same day, independently of CentOS Stream or RHEL. According to a March 2025 ALESCo update, the committee assembled on the day the advisory was published and decided to ship the patch without waiting for upstream RHEL or CentOS Stream to move first. Rocky Linux was not able to patch independently on that same timeline because it does not have an equivalent engineering steering committee with authority to ship independent fixes.
AlmaLinux 10 also re-enables technologies RHEL deprecated: SPICE (Simple Protocol for Independent Computing Environments, deprecated since RHEL 9.0) is fully restored for both server and client applications. KVM for IBM POWER hardware was a tech preview in AlmaLinux 10.0 and was more fully enabled in AlmaLinux 10.1. AlmaLinux 10.1 also enables the CRB (CodeReady Builder) repository by default for new installations -- something you previously had to enable manually. These are deliberate departures from upstream where the AlmaLinux community determined that the upstream decision did not serve its users.
In the official AlmaLinux 10.1 announcement, Foundation chair benny Vasquez credited community contributions and called ALESCo "one of the top driving forces" for giving users a voice in the project's direction.
-- benny Vasquez, chair, AlmaLinux OS Foundation. Official press release for AlmaLinux 10.1, November 24, 2025. Source: almalinux.org
For CentOS refugees specifically, AlmaLinux's ELevate is a concrete differentiator: it provides a tested, supported path to migrate existing CentOS 7 machines in-place, which is far less disruptive than a full reinstall. For new deployments, either distribution is a reasonable choice. The decision often comes down to organizational familiarity -- whichever one your team chooses, stick with it and standardize.
Production Hardening: The Essentials
A freshly installed AlmaLinux server is not a hardened server. The following steps represent the minimum security posture for a machine exposed to any network. Each is grounded in the specific defaults AlmaLinux ships with. For certificate-based authentication, jump hosts, and production-grade SSH configuration that goes further, see the guide on hardening SSH beyond the basics.
# Create a non-root admin user (don't operate as root) $ sudo useradd -m -s /bin/bash -G wheel adminuser $ sudo passwd adminuser # Lock the root password entirely (use sudo for all privileged ops) $ sudo passwd -l root # Harden SSH configuration $ sudo vim /etc/ssh/sshd_config # Set: PermitRootLogin no # Set: PasswordAuthentication no (after deploying SSH keys) # Set: X11Forwarding no # Set: MaxAuthTries 4 $ sudo systemctl restart sshd # Deploy SSH public key authentication $ ssh-copy-id -i ~/.ssh/id_ed25519.pub adminuser@serverip # Set the system hostname properly $ sudo hostnamectl set-hostname production-web-01.example.com # Configure NTP time synchronization (critical for log integrity) $ sudo timedatectl set-timezone America/Chicago $ sudo timedatectl set-ntp true $ timedatectl status # Enable automatic security updates (recommended for servers -- see note below) $ sudo dnf install dnf-automatic -y $ sudo sed -i 's/apply_updates = no/apply_updates = yes/' /etc/dnf/automatic.conf # For security-only updates (safer for production), also set: # upgrade_type = security $ sudo sed -i 's/upgrade_type = default/upgrade_type = security/' /etc/dnf/automatic.conf $ sudo systemctl enable --now dnf-automatic.timer # Install and enable the auditd security audit framework $ sudo dnf install audit -y $ sudo systemctl enable --now auditd # Install AIDE for file integrity monitoring $ sudo dnf install aide -y $ sudo aide --init $ sudo mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz # Schedule daily AIDE checks via cron $ echo "0 4 * * * root /usr/sbin/aide --check" | sudo tee /etc/cron.d/aide-check
The hardening example uses id_ed25519.pub rather than the older id_rsa.pub. If your CentOS SSH keys were RSA, they will work -- AlmaLinux's OpenSSH still accepts RSA keys. But ed25519 is worth switching to on new systems. Ed25519 keys are shorter (68 characters versus 372+ for RSA-2048), generate faster, and are based on elliptic curve cryptography that is not vulnerable to the factoring attacks that motivate RSA key sizes. To generate an Ed25519 SSH key pair with a passphrase, run ssh-keygen -t ed25519 -C "your-server-description" and follow the prompts. If you have existing RSA keys that are at least 3072 bits, they remain acceptable; RSA-1024 and RSA-2048 should be retired. You can check your existing key size with ssh-keygen -l -f ~/.ssh/id_rsa.pub.
Enabling dnf-automatic with apply_updates = yes is appropriate for many servers, but understand the trade-off: a security update that replaces the running kernel will not take effect until the next reboot, and dnf-automatic does not reboot the system for you. You are responsible for rebooting after kernel updates. More critically, some security patches -- particularly to glibc or OpenSSL -- require a service restart to take effect even without a full reboot. For systems where uptime guarantees require change-window-controlled updates, consider setting apply_updates = no and emit_via = email to receive daily notifications of available security updates that you then apply manually on schedule. Run sudo needs-restarting -r after applying updates to check whether a reboot is required.
The AIDE (Advanced Intrusion Detection Environment) installation at the end is worth noting. AIDE builds a database of checksums, permissions, and metadata for system files. Running aide --check daily compares the current state of the filesystem against this baseline and reports any changes -- files that should not have changed but did, new files that did not exist in the baseline, deleted files. For a production server, this is your early warning system for post-exploitation file modification.
CIS Benchmark Hardening with SCAP
The commands above represent a solid manual baseline. For environments where "documented and reproducible" matters -- compliance audits, regulated industries, or just teams that want a systematic approach -- the scap-security-guide package provides machine-readable hardening profiles that can audit and remediate your system automatically.
# Install OpenSCAP and the AlmaLinux SCAP security guide $ sudo dnf install scap-security-guide openscap-scanner -y # List available profiles for AlmaLinux 9 $ oscap info /usr/share/xml/scap/ssg/content/ssg-almalinux9-ds.xml | grep "Id:" # Audit the system against the CIS Level 1 Server profile (no changes made) $ sudo oscap xccdf eval \ --profile xccdf_org.ssgproject.content_profile_cis \ --results /tmp/cis-results.xml \ --report /tmp/cis-report.html \ /usr/share/xml/scap/ssg/content/ssg-almalinux9-ds.xml # Review the HTML report in a browser to see what passed, failed, and needs attention # Then apply remediations (review the report before running --remediate in production) $ sudo oscap xccdf eval \ --remediate \ --profile xccdf_org.ssgproject.content_profile_cis \ --results /tmp/cis-remediation-results.xml \ /usr/share/xml/scap/ssg/content/ssg-almalinux9-ds.xml # For DISA STIG compliance instead of CIS, use this profile: # --profile xccdf_org.ssgproject.content_profile_stig
The Kickstart %post section can run oscap remediation as part of the install process, before the system ever serves its first request. Add the scap-security-guide and openscap-scanner packages to your %packages block and include the oscap xccdf eval --remediate command in %post. Systems provisioned this way enter production already hardened to benchmark, with a documented baseline stored alongside the Kickstart file.
FIPS 140-3 Mode
For environments where cryptographic compliance is not optional -- federal agencies, healthcare, defense contractors, or any organization that will face an auditor asking to see a NIST certificate number -- FIPS mode is the requirement that neither the CIS benchmark nor the SSH hardening steps above satisfy on their own.
AlmaLinux ships the fips-mode-setup utility, and you can enable FIPS mode with it. But there is a precise distinction that compliance auditors draw: enabling FIPS mode (configuring the OS to use FIPS-approved algorithms via update-crypto-policies) is not the same as running formally validated FIPS 140-3 modules that appear on NIST's CMVP validated modules list.
AlmaLinux 9.2 became the first EL9 distribution to receive a FIPS 140-3 certificate for its kernel -- validated by atsec, a NIST-accredited laboratory, with the validation process sponsored by CloudLinux. The cost of the FIPS 140-3 validation ran to nearly $400,000 in fees, not counting the engineering time, which is why community Linux distributions historically relied on Red Hat's validated modules rather than pursuing independent certification. The validated packages are available through TuxCare, with AlmaLinux 9.6 currently in the validation pipeline.
# Check current crypto policy $ update-crypto-policies --show # Enable FIPS mode via the setup utility (requires reboot) $ sudo fips-mode-setup --enable $ sudo reboot # After reboot -- verify FIPS mode is active $ fips-mode-setup --check $ cat /proc/sys/crypto/fips_enabled # Should output: 1 # Check the active crypto policy (should now show FIPS) $ update-crypto-policies --show # AlmaLinux 10: apply the PQ (post-quantum) subpolicy on top of FIPS $ sudo update-crypto-policies --set FIPS:PQ
Running fips-mode-setup --enable configures AlmaLinux to use FIPS-approved algorithms. It is the right baseline for most organizations and appropriate for many compliance frameworks. However, formal FIPS 140-3 validation -- the kind that satisfies FedRAMP, DoD, and strict federal procurement requirements -- requires running the specific kernel and cryptographic packages that have been tested by a NIST-accredited lab and listed on the CMVP validated modules list. As of March 2026, TuxCare provides validated packages for AlmaLinux 9.2 (certificate issued) and has AlmaLinux 9.6 in the validation pipeline. If your compliance framework requires a certificate number, contact TuxCare for their Extended Security Updates program. If your framework requires FIPS-approved algorithms without a formal certificate, fips-mode-setup --enable with standard AlmaLinux packages is sufficient.
Planning for AlmaLinux 10: What Changes
If you are installing AlmaLinux 9.x today, you are installing a distribution with active support until May 2027 and security support until 2032. That is a long runway. But AlmaLinux 10 exists now, and understanding what it changes -- and what it breaks -- determines whether you should be deploying it today or planning to migrate in 12-18 months.
The x86-64-v2 Question
RHEL 10 raised its x86_64 baseline to x86-64-v3, which requires instruction sets including AVX, AVX2, BMI1, and BMI2. Hardware from before approximately 2013 (Intel Ivy Bridge era and earlier, AMD Bulldozer and earlier) does not support v3. AlmaLinux 10 ships v3-optimized binaries by default but maintains a separate x86-64-v2 build for older hardware, and additionally builds EPEL packages for x86-64-v2 (since EPEL follows RHEL's v3 baseline). If you have servers that predate RHEL 10's microarchitecture requirement, check before upgrading.
As of this writing, ELevate upgrades from AlmaLinux 9 to AlmaLinux 10 do not support x86-64-v2 hardware. If your servers do not meet the x86-64-v3 CPU baseline, in-place migration via ELevate is currently blocked. Check the ELevate wiki for the latest status on x86-64-v2 upgrade path support, as this may change with future ELevate updates.
# Check which x86-64 microarchitecture level your CPU supports $ /lib64/ld-linux-x86-64.so.2 --help | grep "Supported" # Look for: x86-64-v2, x86-64-v3 -- your CPU supports all listed levels # Alternative: check directly from /proc $ grep -o 'avx[0-9]*\|bmi[0-9]*' /proc/cpuinfo | sort -u # If avx, avx2, bmi1, bmi2 all appear, you can run x86-64-v3
Post-Quantum Cryptography in AlmaLinux 9.7 and 10
AlmaLinux 9.7 ships OpenSSL 3.5, which introduces support for ML-KEM, ML-DSA, and SLH-DSA -- the NIST-standardized post-quantum cryptographic algorithms. This is not yet relevant for most production workloads, but it is significant for environments with long data sensitivity windows. If you are encrypting data today that must remain confidential through 2035, the argument for post-quantum cryptography now rather than in a future migration is real. AlmaLinux 10 adds this same post-quantum support to its system-wide cryptographic policies via the new PQ subpolicy.
This matters for compliance-sensitive environments: if your organization is planning for NIST PQC compliance under emerging regulatory frameworks (CISA's PQC guidance, NSA CNSA 2.0), AlmaLinux 9.7 and 10 are already positioned to support those requirements at the OS layer.
Btrfs Support in AlmaLinux 10.1
AlmaLinux 10.1 (November 2025) added Btrfs filesystem support -- something RHEL 10 does not offer. This is one of the clearest examples of AlmaLinux acting as an opinionated distribution rather than a passive RHEL rebuild. Btrfs offers native snapshot support, transparent compression, subvolume management, and online rebalancing, which are features that typically required LVM + a separate snapshot mechanism on earlier RHEL-family systems. For workloads that benefit from filesystem-level snapshots (pre-patch snapshots, containerized development environments, or build servers), Btrfs on AlmaLinux 10.1 is worth evaluating -- see the practical walkthrough on Btrfs snapshots and rollbacks for snapshot management and recovery strategies. The XFS-based LVM partition scheme covered in this guide remains the right choice for traditional server workloads, but Btrfs is now a supported alternative for those who need it.
Kickstart: Automating Installs for Fleets
Everything covered in the Anaconda section is useful for installing one server. For ten servers, it becomes tedious. For a hundred, it is untenable. Kickstart is the answer: a text file that answers every Anaconda question automatically, so the installer runs without human input from boot to first login.
Kickstart files use a simple declarative syntax. After a successful manual installation, Anaconda writes a complete Kickstart file of that installation to /root/anaconda-ks.cfg. That file is your starting point -- it captures every choice you made during the manual install and can be replayed exactly on new hardware. Read it. It is more legible than it looks.
# Installation method and source install url --mirrorlist=https://mirrors.almalinux.org/mirrorlist/9/baseos # Language and keyboard lang en_US.UTF-8 keyboard us # Timezone timezone UTC --isUtc # Network -- static IP example network --bootproto=static --ip=10.0.1.20 --netmask=255.255.255.0 --gateway=10.0.1.1 --nameserver=10.0.1.1 --hostname=srv01.example.com # Root password (hashed -- generate with: openssl passwd -6 'yourpassword') rootpw --iscrypted $6$rounds=...your-hash-here... # Disk partitioning -- wipe disk, use LVM zerombr clearpart --all --initlabel autopart --type=lvm # Or explicit LVM layout: # part /boot --fstype="xfs" --size=1024 # part /boot/efi --fstype="efi" --size=512 # part pv.01 --size=1 --grow # volgroup vg_alma pv.01 # logvol / --fstype=xfs --vgname=vg_alma --size=20480 --name=lv_root # logvol /var --fstype=xfs --vgname=vg_alma --size=15360 --name=lv_var # logvol /var/log --fstype=xfs --vgname=vg_alma --size=8192 --name=lv_varlog # logvol swap --vgname=vg_alma --size=4096 --name=lv_swap # Software selection %packages @^minimal-environment aide audit dnf-automatic firewalld openssh-server %end # Post-install script -- runs in chroot %post # Enable automatic security updates sed -i 's/upgrade_type = default/upgrade_type = security/' /etc/dnf/automatic.conf sed -i 's/apply_updates = no/apply_updates = yes/' /etc/dnf/automatic.conf systemctl enable dnf-automatic.timer # Initialize AIDE database aide --init mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz # Disable root SSH login sed -i 's/^#PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config %end # Reboot automatically when done reboot
To use a Kickstart file, pass it to the installer at boot time. In the GRUB menu, press e to edit the boot command line and append inst.ks=http://your-server/ks.cfg (for network-hosted Kickstart) or inst.ks=hd:sdb1:/ks.cfg (for a file on a USB drive). The installer will read the file and proceed without user interaction.
For large-scale fleet deployments, Kickstart is typically combined with a PXE boot server (iPXE or PXELINUX + DHCP + TFTP) so that new machines boot from the network, receive the Kickstart file automatically, and complete their installation without anyone touching them physically. After first boot, configuration management tools (Ansible, Puppet, Salt) take over for application-level provisioning. The Kickstart layer handles OS installation; configuration management handles everything that lives above it.
Install pykickstart on your workstation and run ksvalidate ks.cfg before deploying. This catches syntax errors and deprecated directives before they cause a failed install at 2 AM. The ksverdiff command compares Kickstart syntax between versions, which is useful when moving from RHEL 8 to RHEL 9 format.
AlmaLinux Kitten: The Rolling Development Track
One question that did not exist two years ago: what is AlmaLinux OS Kitten, and do you need to care about it? The short answer for production administrators is: no, deploy stable releases. The longer answer is worth understanding because Kitten explains how AlmaLinux 10 came to exist with features that RHEL 10 does not have.
AlmaLinux OS Kitten is AlmaLinux's continuously-updated development track, announced in October 2024. It mirrors CentOS Stream in being a rolling release, but from AlmaLinux's perspective rather than Red Hat's. Kitten was the first place x86-64-v2 support for AlmaLinux 10 appeared, the first place Btrfs support was tested, and the first place new ELevate upgrade paths are validated before reaching stable. It is the proving ground where ALESCo and the community evaluate potential departures from RHEL defaults before committing them to the stable release.
The October 2024 AlmaLinux OS Foundation announcement described Kitten 10 as a preview built from CentOS Stream 10's code, calling it "AlmaLinux OS Kitten 10" -- a proving ground for what would become the stable AlmaLinux 10 series.
-- AlmaLinux OS Foundation announcement, October 2024. Source: almalinux.org. Also documented on Wikipedia's AlmaLinux article.
The practical implication for CentOS refugees: Kitten is not a replacement for stable AlmaLinux 9.x or 10.x in production. But if you are trying to understand why a feature appeared in AlmaLinux 10.1 that is not in RHEL 10, the answer is often that it was validated in Kitten first. Kitten also serves as the early-warning system for AlmaLinux 11 planning -- anything that is going to be a problem in the next major version tends to surface in Kitten first.
For container and cloud-image users, Kitten images are available and can be used for CI/CD pipelines where you want to catch compatibility issues before they arrive in the next stable minor version. For everything else, stay on stable.
AlmaLinux on Containers and Cloud Infrastructure
A substantial number of CentOS refugees are not running bare-metal servers. They are running containers and cloud instances, and the migration question is not "how do I reinstall" but "what do I pull from the registry." AlmaLinux maintains official images for all the major container runtimes and cloud platforms, and knowing what is available and how it differs from the installation-based approach is worth a dedicated section.
Container Images
AlmaLinux publishes official container images on Docker Hub (almalinux/almalinux) and Quay.io (quay.io/almalinux/almalinux). Three base variants are available for both AlmaLinux 9 and 10:
# Standard image -- minimal but includes dnf and common tooling $ docker pull almalinux:9 $ docker pull almalinux:10 # Minimal image -- stripped further, ~5% smaller, intended for production containers $ docker pull almalinux:9-minimal # Note: minimal uses microdnf, not the full dnf client # Init image -- includes systemd, for containers that need service management $ docker pull almalinux:9-init # Using Podman instead of Docker (preferred on AlmaLinux hosts) $ podman pull almalinux:9 $ podman run --rm -it almalinux:9 /bin/bash # From Quay.io (signed images, useful for supply-chain verified pipelines) $ podman pull quay.io/almalinux/almalinux:9 # Example Containerfile (Dockerfile) using AlmaLinux as a base # FROM almalinux:9 # RUN dnf install -y nginx && dnf clean all # EXPOSE 80 # CMD ["/usr/sbin/nginx", "-g", "daemon off;"]
The almalinux:9-minimal image ships microdnf rather than the full dnf. microdnf handles basic install and remove operations but does not support module streams, dnf history, or plugins. If your Containerfile depends on dnf module enable or other full-client features, use the standard image (almalinux:9) rather than minimal. For production containers where image size matters, install what you need with microdnf and then run microdnf clean all in the same RUN layer to keep the layer small.
Cloud Images
AlmaLinux maintains official cloud images for AWS, Azure, Google Cloud, and Oracle Cloud, as well as generic cloud images in qcow2 format for OpenStack, Proxmox, and similar platforms. These images are pre-configured with cloud-init for hostname assignment, SSH key injection, and user-data scripts on first boot -- the same mechanism CentOS cloud images used. The images are available via each cloud provider's marketplace and via direct download from wiki.almalinux.org/cloud/.
One practical note for AWS users migrating from CentOS 7 AMIs: the default user on AlmaLinux cloud images is ec2-user, consistent with RHEL-family conventions. The CentOS community AMIs used centos as the default user. If your automation assumes centos, update it before deploying AlmaLinux AMIs. The AlmaLinux AMI IDs are published and updated with each minor version release at the AlmaLinux AWS wiki page.
For environments running Kubernetes, AlmaLinux is a supported base for node images, and Red Hat's Universal Base Image (UBI) concept -- a freely redistributable subset of the OS intended for container layers -- has an AlmaLinux equivalent in the standard container images described above. AlmaLinux container images are freely redistributable without any subscription requirement.
Conclusion
The administrative heritage of CentOS was a specific kind of confidence: you knew what the OS would do, you knew it would not change beneath you, and you knew you could safely apply updates without worrying about regressions. That confidence came from the downstream relationship with RHEL -- all the testing had already been done by Red Hat's engineering teams before the source packages were published.
AlmaLinux reconstructs that confidence through a different path. The ABI compatibility commitment, the near-same-day release cycle behind RHEL minor versions, the publicly reproducible ALBS build system, the community governance that prevents any single company from redirecting the project, and the demonstrated willingness to ship independent security patches (as ALESCo did with regreSSHion in July 2024, patching CVE-2024-6387 on July 1st -- the same day Qualys published the advisory -- ahead of RHEL or CentOS Stream) all add up to a distribution that you can trust in the same way you trusted CentOS -- not blindly, but based on evidence.
The installation process itself is familiar to anyone who has used CentOS, RHEL, or Fedora. Anaconda, DNF, SELinux, firewalld, systemd -- all of the tooling is the same. The commands you knew still work. The configurations you had documented still apply. AlmaLinux was built specifically so that migration would not require relearning your entire environment. The work the community put into ELevate -- enabling 500,000 devices to migrate in place without reinstalling -- is the concrete expression of that commitment. Kickstart support means that the same migration automation you built for CentOS deployments translates directly. And the work ALESCo does -- shipping independent fixes, restoring dropped hardware support, maintaining x86-64-v2 for older machines that RHEL left behind, developing Kitten as a transparent proving ground for future changes -- demonstrates that AlmaLinux is now willing to be something CentOS never was: an opinionated community distribution that pushes back when upstream decisions do not serve its users. CentOS refugees do not have to start over. They just have to move.
How to Install AlmaLinux: Step-by-Step
The following steps summarize the complete installation process from ISO download through a hardened, production-ready system. Each step corresponds to a section covered in detail earlier in this guide.
Step 1: Download and verify the AlmaLinux ISO
Download the Minimal ISO from repo.almalinux.org for your target version (9.7 or 10.1). Verify the SHA256 checksum against the published CHECKSUM file using sha256sum. For supply-chain integrity, also import the AlmaLinux GPG key and verify the CHECKSUM file signature with gpg --verify before writing to USB. See the Choosing Your ISO section for the exact commands.
Step 2: Boot the Anaconda installer and configure required spokes
Boot from installation media. In the Anaconda hub-and-spoke interface, configure the three mandatory items marked in red: Installation Destination (disk partitioning), Root Password, and network. For production servers, choose Custom partitioning to set up separate LVM logical volumes for /, /var, /var/log, /home, /tmp, and swap.
Step 3: Select Minimal Install as the software environment
In the Software Selection spoke, choose Minimal Install for production servers. This installs only the kernel, systemd, bash, and core utilities. Do not install Server with GUI on headless servers -- it adds hundreds of packages and increases the attack surface with no operational benefit.
Step 4: Run the first post-installation commands
After first login, verify the installed version by running cat /etc/almalinux-release, then bring the system fully current with sudo dnf update -y and reboot to load the new kernel if one was installed.
Step 5: Enable EPEL and configure repositories
Install the EPEL repository with sudo dnf install epel-release -y to access a large collection of extra packages. Enable the CRB repository with sudo dnf config-manager --set-enabled crb if you need development headers. On AlmaLinux 10.1 and later, CRB is enabled by default for new installations.
Step 6: Harden the system after installation
Create a non-root admin user, add them to the wheel group, and lock the root password with sudo passwd -l root. Harden SSH by setting PermitRootLogin no, disabling password authentication after deploying SSH keys, and setting MaxAuthTries 4. Install and initialize AIDE for file integrity monitoring. Enable automatic security updates via dnf-automatic.
Step 7: Verify SELinux is in enforcing mode and leave it there
Run sestatus to confirm SELinux is enabled and in enforcing mode with the targeted policy loaded. Do not disable SELinux. If a service is being blocked, use sudo sealert -a /var/log/audit/audit.log to read human-readable denial explanations and apply the suggested fix -- usually a boolean or restorecon command.
Step 8: Configure firewalld zones
Verify firewalld is running with sudo firewall-cmd --state. Use sudo firewall-cmd --permanent --add-service=ssh to ensure SSH access survives reboots, then reload with sudo firewall-cmd --reload. Add only the services your server needs. To restrict SSH to a specific subnet, use a rich rule with the source address parameter and remove the default broad SSH service.
Frequently Asked Questions
Is AlmaLinux a drop-in replacement for CentOS?
AlmaLinux is ABI compatible with RHEL, meaning software compiled for RHEL runs on AlmaLinux without recompilation. Since July 2023 it is no longer a 1:1 binary clone, but for the overwhelming majority of production workloads the distinction is invisible. The AlmaLinux OS Foundation made this pivot publicly on July 12, 2023, and described it as maintaining binary compatibility at the application interface level.
Can I migrate from CentOS 7 to AlmaLinux without reinstalling?
Yes. AlmaLinux's ELevate tool, built on the Leapp framework, performs in-place migration from CentOS 7 to AlmaLinux 8, then from AlmaLinux 8 to 9, and from 9 to 10. The original CentOS 7 repositories are offline, so you must first point your system at AlmaLinux's maintained CentOS 7 vault mirror before running ELevate. ELevate has been used to migrate over 500,000 devices.
Should I install AlmaLinux 9 or AlmaLinux 10?
For new production deployments in 2026, AlmaLinux 9.7 is the conservative choice with active support until May 2027 and security support until May 2032. AlmaLinux 10.1 is production-ready and offers a longer support horizon -- active support until May 2030 and security support until May 2035 -- along with newer kernel features, Btrfs support, and post-quantum cryptography. If your hardware predates 2013 and may not meet the x86-64-v3 baseline, check whether it is supported before deploying AlmaLinux 10.
Should I disable SELinux on AlmaLinux?
No. AlmaLinux ships with SELinux in enforcing mode and the targeted policy by default, and both defaults are correct. Disabling SELinux removes a kernel-level Mandatory Access Control layer that confines compromised services. If SELinux is blocking something you need, use sealert to read the denial and either set a boolean with setsebool -P or restore the correct file context with restorecon. Write a custom policy module as a last resort.
What is the difference between AlmaLinux and Rocky Linux?
Both are ABI-compatible with RHEL and use the same core tooling -- DNF, SELinux, firewalld, systemd. The main differences are governance, tooling, and philosophy. AlmaLinux has ELevate for in-place migration, publicly reproducible builds via ALBS, and ALESCo which can ship security patches independently ahead of RHEL (as it did with CVE-2024-6387 on July 1, 2024). AlmaLinux 10 also supports x86-64-v2 hardware and Btrfs, which RHEL 10 dropped. Rocky Linux has a separate governance model under the Rocky Enterprise Software Foundation.
Are there official AlmaLinux container images?
Yes. AlmaLinux publishes official container images on Docker Hub (almalinux/almalinux) and Quay.io (quay.io/almalinux/almalinux). Three variants are available: the standard image with full DNF support, a minimal image using microdnf, and an init image with systemd included. Cloud images for AWS, Azure, Google Cloud, and Oracle Cloud are also available via each provider's marketplace. The default SSH user on AlmaLinux cloud images is ec2-user, not centos -- update any automation that assumes the CentOS AMI default.
Do I need a Red Hat subscription to run AlmaLinux?
No. AlmaLinux has its own free repositories and does not use Red Hat's subscription management system. If you see messages referencing subscription-manager after installation, they are harmless -- AlmaLinux does not require a subscription, and the notices can be suppressed by disabling the subscription-manager DNF plugin if it is present.
What replaces service and chkconfig on AlmaLinux?
systemd. The equivalents are sudo systemctl start servicename (replaces service servicename start), sudo systemctl enable servicename (replaces chkconfig servicename on), and sudo systemctl enable --now servicename to both enable and start in one command. Logs are centralized in the journal -- use sudo journalctl -u servicename -f to follow a service's log output in real time.
Does AlmaLinux support FIPS 140-3 mode?
Yes, with an important distinction. AlmaLinux ships fips-mode-setup, and enabling FIPS mode configures the system to use FIPS-approved cryptographic algorithms. For environments that require formally validated modules -- those listed on NIST's CMVP validated modules list, which is what federal agencies, DoD contractors, and FedRAMP audits require -- AlmaLinux 9.2 became the first EL9 distribution to receive a FIPS 140-3 certificate for its kernel. The validated packages are available through TuxCare, with AlmaLinux 9.6 validation in the pipeline as of early 2026. If your compliance framework asks for a certificate number, you need the TuxCare-provided validated packages. If it requires FIPS-approved algorithms without a formal certificate, fips-mode-setup --enable is sufficient.
What should I do if ELevate fails during migration?
If leapp preupgrade reports inhibitors, resolve them and re-run -- the system has not been modified yet. If the upgrade initramfs phase fails and the system boots back into the original OS, the migration was automatically rolled back; check /var/log/leapp/leapp-upgrade.log for the failure reason, fix the cause, and retry. If the system cannot boot after a failed upgrade, boot from the installation media in rescue mode and access the filesystem at /mnt/sysimage to review logs. Your pre-migration backup or snapshot is your recovery path if the system cannot be recovered from the failed state. This is why the backup requirement exists -- it is not a precaution, it is the rollback mechanism.
Does AlmaLinux run on ARM and other architectures?
Yes. AlmaLinux officially supports four architectures: x86_64, aarch64 (ARM 64-bit), ppc64le (IBM POWER, little-endian), and s390x (IBM Z). All four are built through the AlmaLinux Build System with the same release timeline. The aarch64 build is the most commonly deployed in cloud environments -- AWS Graviton, Azure Ampere, and Google Tau T2A instances all run official AlmaLinux cloud images. For ARM deployments, download the aarch64 ISO from repo.almalinux.org rather than the default x86_64 ISO.
Sources and Verification
Every factual claim in this article is traceable to a primary source. The following references are provided so you can verify any statement independently. Where a claim references a specific CVE, release blog post, or wiki page, that source is linked directly in the article body above. The consolidated list is here for completeness.
- AlmaLinux ABI Compatibility pivot (July 12, 2023): almalinux.org/blog/2023-07-12-almalinux-is-now-abi-compatible/
- AlmaLinux 9.7 "Moss Jungle Cat" release announcement (Nov 17, 2025): almalinux.org/blog/2025-11-17-almalinux_97_release/
- AlmaLinux 9.7 release notes (kernel 5.14.0-611.5.1.el9_7): wiki.almalinux.org/release-notes/9.7.html
- AlmaLinux 10.0 "Purple Lion" release announcement (May 27, 2025): almalinux.org/blog/2025-05-27-welcoming-almalinux-10/
- AlmaLinux 10.0 release notes (kernel 6.12): wiki.almalinux.org/release-notes/10.0.html
- AlmaLinux 10.1 "Heliotrope Lion" release announcement (Nov 24, 2025): almalinux.org/blog/2025-11-24-almalinux_101_release/
- AlmaLinux 10.1 release notes (kernel 6.12.0-124.8.1.el10_1): wiki.almalinux.org/release-notes/10.1.html
- AlmaLinux 2024 recap blog (release cadence, ALBS details): almalinux.org/blog/2025-04-09-2024-recap/
- ALESCo regreSSHion (CVE-2024-6387) independent patch, July 1, 2024: almalinux.org/blog/2024-07-01-almalinux-9-cve-2024-6387/
- ALESCo update, March 2025: almalinux.org/blog/2025-03-05-update-from-alesco/
- ELevate project page (500,000+ migrations): almalinux.org/elevate/
- ELevate migration guide (CentOS 7 to AlmaLinux 10): wiki.almalinux.org/elevate/ELevating-CentOS7-to-AlmaLinux-10.html
- AlmaLinux OS release lifecycle dates: wiki.almalinux.org/release-notes/
- AlmaLinux Wikipedia article (governance, history, foundation structure): en.wikipedia.org/wiki/AlmaLinux
- AlmaLinux ELevate wiki (CentOS 7 vault mirror, x86-64-v2 upgrade limitations): wiki.almalinux.org/elevate/
- Leapp upstream repository (leapp-repository 0.23.0 merge): github.com/oamg/leapp