Migrating Off CentOS to AlmaLinux, Rocky Linux, Oracle Linux or RHEL

Migrating Off CentOS to AlmaLinux, Rocky Linux, Oracle Linux or RHEL

Reading time1 min
#linux#centos#almalinux#rocky-linux#oracle-linux#rhel#migration

Migrating Off CentOS to AlmaLinux, Rocky Linux, Oracle Linux or RHEL

CentOS Linux is finished. CentOS 8 reached end of life on December 31, 2021, CentOS Stream 8 on May 31, 2024, and CentOS 7 on June 30, 2024. The mirrors moved to vault.centos.org, so a CentOS server today gets no security fixes and often cannot even run yum install until its repos are repointed.

There are two ways out: convert the server in place, or build a new one and move the workload. This post covers both, with the tools that still work and their current limits.

Pick a target

  • AlmaLinux and Rocky Linux: free, RHEL compatible, community run. For most CentOS users either one is the natural replacement.
  • Oracle Linux: free to download and update, paid support optional. Boots Oracle's UEK kernel by default; the Red Hat compatible kernel (RHCK) is available on x86_64.
  • RHEL: needs a subscription. Worth it when a vendor certifies only on RHEL or you want Red Hat support.

Rebuild or convert in place

A fresh install of the current major release (9 or 10) plus a cutover gives the cleanest result. You can test before switching, and rollback means pointing traffic back at the old host. It costs a second machine and some config work.

In-place conversion is faster across many servers and keeps everything installed. Know what kind of change it is:

  • CentOS 8 to another EL8 distro swaps packages and repos within the same release. Low risk.
  • CentOS 7 to anything supported is a major upgrade (7 to 8) done by Leapp. It replaces almost every package, and old PHP, Python 2 code or custom kernel modules may break. EL8 is supported only until 2029, so plan the next hop to 9 as well.

Tool status

FromToTool
CentOS 7.9AlmaLinux 8ELevate (Leapp with AlmaLinux data)
CentOS 7.9Rocky Linux 8No direct tool: ELevate to AlmaLinux 8, then migrate2rocky
CentOS 7.9Oracle Linux 7, then 8migrate-to-oracle-linux.sh, then Oracle Leapp
CentOS 7.9RHEL 7, then 8convert2rhel, then Red Hat Leapp
CentOS 8, Stream 8/9/10AlmaLinuxalmalinux-deploy
CentOS 8, Stream 8/9Rocky Linuxmigrate2rocky, migrate2rocky9
CentOS 8.4+, Stream 8/9/10Oracle Linux, same majormigrate-to-oracle-linux.sh
CentOS 8.5RHEL 8convert2rhel

What changed since most guides were written:

  • ELevate dropped Rocky Linux as a target in November 2025. Instructions that install leapp-data-rocky no longer apply.
  • Oracle's centos2ol.sh is now migrate-to-oracle-linux.sh in the oracle/migrate-to-ol repository. CentOS 6 is no longer supported.
  • migrate2rocky and almalinux-deploy never supported CentOS 7.
  • convert2rhel does not support CentOS Stream. CentOS 8.5 converts to RHEL 8.5, and you update to the latest RHEL 8 afterwards.

Before any in-place migration

  1. Take a snapshot or a full backup, and know how to restore it. None of these tools has an undo.
  2. Get console access (cloud serial console, IPMI, hypervisor console). If the server does not come back after the reboot, SSH will not help.
  3. Run everything inside tmux or screen, so a dropped connection does not kill the tool halfway.
  4. Record the current state:
    rpm -qa | sort > /root/packages-before.txt
    systemctl list-units --type=service --state=running > /root/services-before.txt
    
  5. Disable third-party repos that have no build for the target release. Re-enable the matching versions afterwards.
  6. Update to the last minor release and reboot, so the newest kernel is running.

On CentOS 7 the stock repos point at dead mirrors. AlmaLinux hosts a CentOS 7 mirror for exactly this:

sudo curl -o /etc/yum.repos.d/CentOS-Base.repo https://el7.repo.almalinux.org/centos/CentOS-Base.repo
sudo yum -y update && sudo reboot

On CentOS 8, switch the repos to the vault:

sudo sed -i -e 's|^mirrorlist=|#mirrorlist=|' \
  -e 's|^#baseurl=http://mirror.centos.org|baseurl=https://vault.centos.org|' \
  /etc/yum.repos.d/CentOS-*.repo
sudo dnf -y update && sudo reboot

CentOS 7 to AlmaLinux 8 with ELevate

sudo yum install -y http://repo.almalinux.org/elevate/elevate-release-latest-el$(rpm --eval %rhel).noarch.rpm
sudo yum install -y leapp-upgrade leapp-data-almalinux
sudo leapp preupgrade

preupgrade changes nothing. It writes /var/log/leapp/leapp-report.txt with inhibitors (blockers) and warnings. Fix every inhibitor and rerun until none are left. Common ones on CentOS 7:

sudo rmmod pata_acpi
sudo leapp answer --section remove_pam_pkcs11_module_check.confirm=True

Another frequent inhibitor is SSH root login: EL8 changes the default of PermitRootLogin, so Leapp wants it set explicitly in /etc/ssh/sshd_config. Set the value you actually want (no or prohibit-password), not yes just to silence the check.

Then upgrade:

sudo leapp upgrade
sudo reboot

The reboot goes into a temporary upgrade environment and can take a while. Watch it on the console. Afterwards check:

cat /etc/os-release
rpm -qa | grep el7      # leftover packages to review
systemctl --failed

The same four commands take AlmaLinux 8 to 9 and 9 to 10, since $(rpm --eval %rhel) picks the right release package. EL9 needs x86-64-v2 CPUs and EL10 x86-64-v3, and preupgrade reports unsupported hardware as an inhibitor (AlmaLinux's v2 build of 10 is reachable only with ELevate NG).

CentOS 7 to Rocky Linux

Rocky Linux does not support in-place major upgrades, and ELevate no longer targets it. Either reinstall on Rocky 9 or 10, or go in two steps: ELevate to AlmaLinux 8 as above, then convert with migrate2rocky, which accepts AlmaLinux 8 as a source.

CentOS 8 or Stream to AlmaLinux or Rocky

# AlmaLinux; add -d on CentOS Stream to allow package downgrades
curl -O https://raw.githubusercontent.com/AlmaLinux/almalinux-deploy/master/almalinux-deploy.sh
sudo bash almalinux-deploy.sh

# Rocky Linux 8; on EL9 use migrate2rocky9 from the same repository
curl -O https://raw.githubusercontent.com/rocky-linux/rocky-tools/main/migrate2rocky/migrate2rocky.sh
chmod u+x migrate2rocky.sh
sudo ./migrate2rocky.sh -r

Reboot when either script finishes. Stream to a stable release is technically a downgrade, because Stream runs ahead of the point releases. migrate2rocky logs to /var/log/migrate2rocky.log and needs the original CentOS repo files present and enabled. Do not run it from the Cockpit web terminal: if that session drops, the system can be left half converted.

CentOS to Oracle Linux

curl -O https://raw.githubusercontent.com/oracle/migrate-to-ol/main/migrate-to-oracle-linux.sh
chmod +x migrate-to-oracle-linux.sh
sudo ./migrate-to-oracle-linux.sh --dry-run
sudo ./migrate-to-oracle-linux.sh -y
sudo reboot

The script stays within the major version: CentOS 7.9 becomes Oracle Linux 7, CentOS 8 becomes Oracle Linux 8. It installs UEK and makes it the default kernel; pass --kernel rhck to keep the Red Hat compatible kernel. From Oracle Linux 7, continue with Oracle's Leapp:

sudo yum install -y leapp-upgrade --enablerepo=ol7_leapp,ol7_latest
sudo leapp preupgrade --oraclelinux
sudo leapp upgrade --oraclelinux

CentOS to RHEL with convert2rhel

You need an activation key and organization ID from the Red Hat console. Keep them in /etc/convert2rhel.ini instead of on the command line:

[subscription_manager]
org = 1234567
activation_key = my-activation-key

On CentOS 7 (on CentOS 8 use the rhel-8 repo file):

sudo curl -o /etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release https://security.access.redhat.com/data/fd431d51.txt
sudo curl -o /etc/yum.repos.d/convert2rhel.repo https://cdn-public.redhat.com/content/public/repofiles/convert2rhel-for-rhel-7-x86_64.repo
sudo yum -y install convert2rhel
sudo convert2rhel analyze
sudo convert2rhel
sudo reboot

RHEL 7 is past its maintenance phase. Staying on it needs the Extended Life Cycle Support add-on (add --els to both commands). Without ELS, treat RHEL 7 as a stop on the way and upgrade to RHEL 8 with Leapp right away. Packages that did not come from CentOS stay untouched, so review them after the conversion.

Rebuild and cut over

  1. Install the target release (9 or 10) on a new host and recreate the configuration, ideally with Ansible so the next move is cheaper.
  2. Move databases with their own dump tools (mysqldump, pg_dump) instead of copying data files between major versions.
  3. Copy files, then fix SELinux labels on the new host:
    rsync -aH --delete /var/www/ root@203.0.113.20:/var/www/
    ssh root@203.0.113.20 restorecon -R /var/www
    
  4. Lower the DNS TTL a day ahead, or put both hosts behind a load balancer.
  5. Do a final sync during a short write freeze, switch traffic, and keep the old server stopped but intact until you are sure.

Short version

  • Snapshot, console access, tmux, third-party repos disabled, latest minor release installed.
  • Always run the dry run first: leapp preupgrade, convert2rhel analyze, migrate-to-oracle-linux.sh --dry-run.
  • CentOS 7: ELevate to AlmaLinux 8, Oracle's script plus Leapp, or convert2rhel plus Leapp. Rocky only via AlmaLinux 8 or a reinstall.
  • CentOS 8 and Stream: almalinux-deploy, migrate2rocky, migrate-to-oracle-linux.sh or convert2rhel (not Stream).
  • After the reboot: /etc/os-release, leftover old packages, systemctl --failed, then test the application itself.