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
| From | To | Tool |
|---|---|---|
| CentOS 7.9 | AlmaLinux 8 | ELevate (Leapp with AlmaLinux data) |
| CentOS 7.9 | Rocky Linux 8 | No direct tool: ELevate to AlmaLinux 8, then migrate2rocky |
| CentOS 7.9 | Oracle Linux 7, then 8 | migrate-to-oracle-linux.sh, then Oracle Leapp |
| CentOS 7.9 | RHEL 7, then 8 | convert2rhel, then Red Hat Leapp |
| CentOS 8, Stream 8/9/10 | AlmaLinux | almalinux-deploy |
| CentOS 8, Stream 8/9 | Rocky Linux | migrate2rocky, migrate2rocky9 |
| CentOS 8.4+, Stream 8/9/10 | Oracle Linux, same major | migrate-to-oracle-linux.sh |
| CentOS 8.5 | RHEL 8 | convert2rhel |
What changed since most guides were written:
- ELevate dropped Rocky Linux as a target in November 2025. Instructions that install
leapp-data-rockyno longer apply. - Oracle's
centos2ol.shis nowmigrate-to-oracle-linux.shin theoracle/migrate-to-olrepository. CentOS 6 is no longer supported. migrate2rockyandalmalinux-deploynever 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
- Take a snapshot or a full backup, and know how to restore it. None of these tools has an undo.
- Get console access (cloud serial console, IPMI, hypervisor console). If the server does not come back after the reboot, SSH will not help.
- Run everything inside
tmuxorscreen, so a dropped connection does not kill the tool halfway. - Record the current state:
rpm -qa | sort > /root/packages-before.txt systemctl list-units --type=service --state=running > /root/services-before.txt - Disable third-party repos that have no build for the target release. Re-enable the matching versions afterwards.
- 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
- Install the target release (9 or 10) on a new host and recreate the configuration, ideally with Ansible so the next move is cheaper.
- Move databases with their own dump tools (
mysqldump,pg_dump) instead of copying data files between major versions. - 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 - Lower the DNS TTL a day ahead, or put both hosts behind a load balancer.
- 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.
