Even though this isn’t the kind of post I usually write on this blog, I think this is something worth sharing. Since I needed to reuse my old CentOS 7 jump host VM for a new project — installing Red Hat OpenShift Virtualization (a blog series is coming soon) — I had to upgrade it to CentOS Stream 9. While there’s no officially supported way to upgrade directly from CentOS 7 to Stream 9, it’s entirely possible with the right tools, careful planning, and a bit of patience. In this post, I’ll walk you through how I did it: first, upgrading from CentOS 7 to Stream 8 using ELevate, and then moving from Stream 8 to Stream 9 with dnf system-upgrade. This guide captures all the exact steps I followed to make it work.
This guide is based on a real upgrade from a homelab virtual machine and focuses on the cleanest working steps — no retries, no dead ends. You’ll find practical, real outputs and decisions explained step by step.
Prerequisites and Assumptions
- This was done in a test VM, not a production system.
- The system had internet access and enough free disk space.
- All commands were run as root (or with
sudo).
Phase 1: Upgrade from CentOS 7 to CentOS Stream 8
Step 1: Fully update your CentOS 7 system
Why: Always start with the latest available updates to avoid issues during the upgrade process.
1 2 3 4 5 | yum update -y reboot |
Step 2: Add EPEL repo and install ELevate tools
Why: EPEL provides access to additional packages, and ELevate is the only community-supported tool to migrate between CentOS major versions.
1 2 3 4 5 | yum install -y epel-release yum install -y leapp-upgrade leapp-data-centos |
Step 3: Fix known blockers
Why: The leapp preupgrade command will fail if deprecated drivers are loaded or if required answers are missing. I proactively address these issues.
Remove deprecated kernel driver:
1 2 3 4 | modprobe -r pata_acpi |
Create the answer file:
1 2 3 4 5 6 7 8 | # /var/log/leapp/answerfile [remove_pam_pkcs11_module_check] confirm = True [driver_allowlist] allow_drivers = pata_acpi |
Step 4: Run pre-upgrade check
Why: This simulates the upgrade and generates a report highlighting any blockers or warnings.
1 2 3 4 | leapp preupgrade |
I validated the report at /var/log/leapp/leapp-report.txt and /var/log/leapp/answerfile.
Step 5: Perform the upgrade
Why: This command prepares the system and schedules the upgrade once all checks are passed.
1 2 3 | leapp upgrade --target 8.9 |
Then reboot:
1 2 3 4 | reboot |
After the reboot, we see the system automatically upgrade.
After reboot, the system was running CentOS Stream 8 with kernel 4.18.x.
After the upgrade we can see the report.
Phase 2: Upgrade from CentOS Stream 8 to Stream 9
Step 1: Switch to Stream 8 repos (vault)
Why: CentOS Stream 8 has reached EOL. Official mirrors may return 404 errors, so I switch to the vault.
1 2 3 4 5 6 7 8 | # /etc/yum.repos.d/CentOS-Stream-BaseOS.repo baseurl=https://vault.centos.org/8-stream/BaseOS/x86_64/os/ # /etc/yum.repos.d/CentOS-Stream-AppStream.repo baseurl=https://vault.centos.org/8-stream/AppStream/x86_64/os/ |
Then:
1 2 3 4 5 | dnf clean all dnf makecache |
Step 2: Install system upgrade plugin
Why: This plugin provides the dnf system-upgrade functionality for in-place upgrades.
1 2 3 4 | dnf install -y dnf-plugin-system-upgrade |
Step 3: Disable EPEL Modular (to avoid 404 errors)
Why: EPEL modular repos were returning 404 errors during the upgrade process. I disable them temporarily.
1 2 3 4 | dnf config-manager --set-disabled epel-modular |
Step 4: Start the upgrade to Stream 9
Why: This downloads all the necessary CentOS Stream 9 upgrade packages.
1 2 3 4 | dnf system-upgrade download --releasever=9 --allowerasing |
I resolved any conflicting packages (e.g., iptables-ebtables, make-devel) with:
1 2 3 4 | dnf remove iptables-ebtables make-devel |
Then, re-run the download:
1 2 3 4 | dnf system-upgrade download --releasever=9 --allowerasing |
Step 5: Reboot into the upgrade
Why: This reboots the system and puts it into the upgrade environment where the actual upgrade takes place.
1 2 3 4 | dnf system-upgrade reboot |
After the upgrade was completed, the system booted into CentOS Stream 9, running kernel 5.14.x.
Final Cleanup
Clean up old upgrade tools
Why: These tools are no longer needed and can interfere with package management.
1 2 3 4 | dnf remove leapp* python2-* -y |
Fix RPM DB backend warning.
Why: During the upgrade, RPM may warn about legacy databases. This command migrates to the proper backend.
1 2 3 4 | rpm --rebuilddb |
Clean DNF metadata and cache
Why: To ensure that no corrupted or outdated cache affects future updates.
1 2 3 4 5 | dnf clean all dnf autoremove -y |
Remove unused repos
Why: Vault and temporary extras repos were only needed during the upgrade. Cleaning them avoids future confusion.
1 2 3 4 | rm -f /etc/yum.repos.d/CentOS-Vault.repo /etc/yum.repos.d/CentOS-Stream-Extras-common.repo |
Re-enable EPEL (optional)
Why: Useful if you need extra packages from EPEL after the upgrade.
1 2 3 4 | dnf config-manager --set-enabled epel |
Fixing EPEL GPG Key Issues After the Upgrade
Why this step is needed:
After upgrading to CentOS Stream 9, trying to run dnf update may result in GPG check errors for EPEL packages. This happens because the system still references the old EPEL 8 GPG key, which doesn’t match the newly updated packages for EPEL 9.
Here’s how we fixed it:
Step 1: Download and import the correct GPG key for EPEL 9
1 2 3 4 5 | sudo curl -o /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-9 https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-9 sudo rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-9 |
Step 2: Update the EPEL repo files to point to the new key
1 2 3 4 | sudo sed -i 's|RPM-GPG-KEY-EPEL-8|RPM-GPG-KEY-EPEL-9|g' /etc/yum.repos.d/epel*.repo |
Step 3: Clean metadata and update
1 2 3 4 5 6 | sudo dnf clean all sudo dnf makecache sudo dnf update -y |
During this step, EPEL packages were successfully upgraded, and the epel-next-release package was also installed as a dependency.
After that, all update issues were resolved, and the system was fully up-to-date without any GPG key errors.
Troubleshooting FAQ
Q: Can I upgrade directly from CentOS 7 to CentOS Stream 9?
A: Not directly. You must first upgrade to CentOS Stream 8 using ELevate, then move to Stream 9 using dnf system-upgrade.
Q: My leapp upgrade fails because of missing drivers. What should I do?
A: Unload deprecated drivers (like pata_acpi) using modprobe -r, and whitelist them in the answer file if needed.
Q: I get GPG check FAILED when updating EPEL packages.
A: You’re probably still using the EPEL 8 GPG key. Replace it with the EPEL 9 key and update the repo files as shown in the “Fixing EPEL GPG Key Issues” section.
Q: My DNF/RPM shows “Signature not supported. Hash algorithm SHA1 not available.”
A: That’s a known cosmetic warning on newer systems. It doesn’t affect package installation or security validation on CentOS Stream 9.
Done!
You now have a clean CentOS Stream 9 system, upgraded from CentOS 7, without needing a fresh install. All steps were executed and tested in a homelab VM with full validation. This guide proves that even though it’s not officially supported, a clean upgrade path from CentOS 7 to Stream 9 is possible; just follow the steps, avoid shortcuts, and take it slow.
Share this article if you think it is worth sharing. If you have any questions or comments, comment here, or contact me on Twitter(yes for me is not X but still Twitter).
Leave A Comment