Why RHEL Version Differences Matter
Red Hat Enterprise Linux has been a staple of production datacenters since 2002. Each major release brings changes to core subsystems that directly affect how you provision, manage, and troubleshoot servers. If you are migrating from RHEL 6 to RHEL 9, you are not just upgrading a kernel. You are moving from SysVinit to systemd, from yum to dnf, from iptables to nftables, and from a Docker-centric container model to Podman.
Understanding these differences matters because upgrade projects fail when teams assume the new version works like the old one. A backup script that depends on service commands will need rewriting. Firewall rules built with raw iptables syntax need conversion. Python 2 scripts will not run without modification on RHEL 8 or 9.
This article walks through the technical differences between RHEL 6, 7, 8, and 9 in a way that is useful if you are planning a migration, maintaining mixed-version environments, or studying for the RHCSA/RHCE exams.
Timeline and Support Lifecycle
Red Hat follows a predictable lifecycle for each major version: roughly 10 years of full support plus optional Extended Life-cycle Support (ELS) for an additional period. Knowing where each version sits in this lifecycle determines whether you should patch, migrate, or plan for end-of-life.
| Version | Release Date | Kernel | Full Support End | Maintenance End | ELS End |
|---|---|---|---|---|---|
| RHEL 6 | Nov 2010 | 2.6.32 | May 2017 | Nov 2020 | Jun 2024 |
| RHEL 7 | Jun 2014 | 3.10 | Aug 2019 | Jun 2024 | Jun 2028 |
| RHEL 8 | May 2019 | 4.18 | May 2024 | May 2029 | May 2032 |
| RHEL 9 | May 2022 | 5.14 | May 2027 | May 2032 | May 2035 |
RHEL 6 reached its absolute end of life (including ELS) in June 2024. If you are still running it, there are no more security patches available from Red Hat. RHEL 7 is in its ELS phase, and RHEL 8 is in maintenance support. RHEL 9 is the current active release with full support until 2027.
Init System: SysVinit to systemd
The biggest single change in the RHEL lineage happened between versions 6 and 7: the switch from SysVinit to systemd.
RHEL 6: SysVinit
RHEL 6 uses the traditional SysVinit system with /etc/init.d/ scripts and runlevels numbered 0 through 6. You manage services with the service and chkconfig commands:
# RHEL 6 service management
service httpd start
service httpd status
chkconfig httpd on # enable at boot
chkconfig --list httpd # show runlevel config
Boot order is determined by numbered symlinks in /etc/rc.d/rcN.d/ directories. The system starts services sequentially, which makes boot times slower on hardware with many services.
RHEL 7, 8, and 9: systemd
RHEL 7 introduced systemd as PID 1. Services are defined as unit files (typically in /usr/lib/systemd/system/), and you manage them with systemctl:
# RHEL 7+ service management
systemctl start httpd
systemctl status httpd
systemctl enable httpd # enable at boot
systemctl list-unit-files # show all units
systemd starts services in parallel based on dependency declarations, which makes boot significantly faster. It also provides journal logging (journalctl), socket activation, cgroups integration, and timer units that replace many traditional cron jobs.
The old service and chkconfig commands still exist as wrappers on RHEL 7+, but they call systemd behind the scenes. Runlevels are replaced by targets:
- Runlevel 3 =
multi-user.target - Runlevel 5 =
graphical.target - Runlevel 1 =
rescue.target
Package Management: yum to dnf
RHEL 6 and 7: yum
Both RHEL 6 and 7 use yum (Yellowdog Updater Modified) for package management. RHEL 7's yum version is slightly newer but works essentially the same way:
# Works on RHEL 6 and 7
yum install nginx
yum update
yum search "web server"
yum info httpd
yum uses repository metadata in XML format and resolves dependencies using the rpm backend. It works reliably but can be slow with large repositories because of how it handles metadata.
RHEL 8 and 9: dnf
RHEL 8 replaced yum with dnf (Dandified yum). The command syntax is nearly identical for basic operations, but the internals are different:
# Works on RHEL 8 and 9
dnf install nginx
dnf update
dnf search "web server"
dnf module list # Application Streams (new in RHEL 8)
On RHEL 8 and 9, yum is a symlink to dnf, so existing scripts that call yum still work. However, dnf brings important improvements: faster dependency resolution using libsolv, better module/stream management, and automatic transaction history.
RHEL 8 also introduced Application Streams (AppStream), which lets you install multiple versions of software like Python, PHP, or Node.js from the same repository using the dnf module command. On RHEL 6 and 7, you needed Software Collections (SCL) to achieve something similar.
Default Filesystem: ext4 to XFS
RHEL 6 uses ext4 as the default filesystem. It is reliable and well-understood, with a maximum filesystem size of 16 TB and maximum file size of 16 TB.
RHEL 7 switched the default to XFS. This was not just a preference change. XFS handles large files and high I/O workloads better than ext4. It supports filesystems up to 500 TB (with 64-bit addressing, up to 8 EB theoretically) and has better parallel I/O performance on multi-core systems.
| Feature | ext4 (RHEL 6 default) | XFS (RHEL 7/8/9 default) |
|---|---|---|
| Max filesystem size | 16 TB | 500 TB (practical limit) |
| Shrink support | Yes | No |
| Online grow | Yes | Yes |
| Best for | General workloads, small VMs | Large files, databases, high throughput |
One practical consequence: you cannot shrink an XFS filesystem. If you need to reduce partition sizes, you must back up the data, recreate the filesystem, and restore. Plan your disk layout carefully during installation on RHEL 7+.
Firewall Management: iptables to firewalld to nftables
Firewall tooling has changed with each major version, and this is one of the most confusing areas for sysadmins managing mixed environments.
RHEL 6: iptables (direct)
On RHEL 6, you write iptables rules directly and save them with service iptables save. The rules file lives at /etc/sysconfig/iptables:
# RHEL 6 firewall management
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
service iptables save
service iptables restart
RHEL 7 and 8: firewalld with iptables backend
RHEL 7 introduced firewalld, a dynamic firewall manager that wraps iptables. It uses zones and services instead of raw chain rules:
# RHEL 7+ firewalld management
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-port=8080/tcp
firewall-cmd --reload
firewall-cmd --list-all
On RHEL 7, firewalld talks to the iptables backend. The raw iptables command still works, but mixing direct iptables rules with firewalld causes conflicts. Pick one approach and stick with it.
RHEL 8 and 9: firewalld with nftables backend
RHEL 8 switched firewalld's backend from iptables to nftables. The firewall-cmd interface stays the same, so most administrators will not notice the change. But if you were writing raw iptables rules and bypassing firewalld, those rules will not work on RHEL 8+ without the iptables-nft compatibility layer.
RHEL 9 goes further by removing the iptables compatibility packages from the default install. The iptables command is technically available as a wrapper around nft, but Red Hat recommends using either firewalld or native nft syntax:
# Native nftables syntax (RHEL 8+)
nft add rule inet filter input tcp dport 80 accept
nft list ruleset
Container Support: Docker to Podman
Container support across RHEL versions reflects the broader industry shift away from Docker toward daemonless container tools.
RHEL 6: No native container support
RHEL 6 predates the container era. You can install Docker from third-party repositories, but it is not supported by Red Hat and requires a newer kernel than the 2.6.32 that ships with RHEL 6.
RHEL 7: Docker
RHEL 7 includes Docker in the extras channel. Red Hat shipped and supported Docker CE (later renamed to Moby) for the first half of RHEL 7's lifecycle. The Docker daemon runs as root and manages containers through the docker CLI:
# RHEL 7 Docker usage
systemctl start docker
docker pull nginx
docker run -d -p 80:80 nginx
Red Hat deprecated Docker support in RHEL 7.6 (released October 2018) and began steering users toward Podman.
RHEL 8 and 9: Podman, Buildah, Skopeo
RHEL 8 removed Docker entirely from the default repositories. In its place, Red Hat provides three tools:
podmanfor running containers (rootless by default, no daemon needed)buildahfor building OCI-compliant container imagesskopeofor inspecting and copying container images between registries
# RHEL 8/9 container usage
podman pull nginx
podman run -d -p 80:80 nginx
podman generate systemd --name mycontainer # create systemd unit for container
Podman's CLI is deliberately Docker-compatible. Most docker commands work by replacing docker with podman. The key difference is that Podman runs without a central daemon, which means no single point of failure and better security isolation. RHEL 9 adds improved support for Podman pods and Quadlet files for declarative systemd-managed containers.
Security Features
SELinux Across Versions
Every RHEL version since RHEL 4 ships with SELinux enabled in enforcing mode by default. However, each version improves the policy and tooling:
- RHEL 6: SELinux with targeted policy,
semanage,audit2allow, and basic boolean management - RHEL 7: Improved labeling, systemd integration with SELinux contexts, better
sesearchandseinfotools - RHEL 8: Container SELinux policies (
container-selinux), udica for generating container-specific policies - RHEL 9: Further policy refinements, stricter defaults for new services
Crypto Policies (RHEL 8+)
RHEL 8 introduced system-wide cryptographic policies. Instead of configuring TLS versions and cipher suites individually in Apache, Nginx, OpenSSH, and every other service, you set a single policy that applies across the system:
# Set system-wide crypto policy
update-crypto-policies --set FUTURE # strictest
update-crypto-policies --set DEFAULT # balanced
update-crypto-policies --set LEGACY # needed for old clients
# Check current policy
update-crypto-policies --show
The DEFAULT policy on RHEL 8 disables TLS 1.0 and 1.1. The FUTURE policy goes further, requiring TLS 1.2 minimum and disabling SHA-1. On RHEL 9, the DEFAULT policy is stricter than RHEL 8's, with SHA-1 signatures disabled by default.
This is a common migration headache. Applications that worked on RHEL 7 may fail to establish TLS connections on RHEL 8 or 9 because the default crypto policy rejects older protocols. You can set the policy to LEGACY as a temporary workaround, but it should not be a permanent solution.
Other Security Changes
- RHEL 7 introduced
firewalldrich rules andsystemd-journaldfor centralized logging - RHEL 8 added FIPS 140-2 crypto module validation out of the box, improved OpenSCAP profiles, and Insights client integration
- RHEL 9 ships with OpenSSL 3.0, which deprecates many older algorithms. It also runs the kernel in FIPS mode more cleanly and includes improved Integrity Measurement Architecture (IMA) support
Python Versions
Python version changes across RHEL releases cause the most migration pain for automation teams. Here is what ships with each version:
| RHEL Version | Default Python | Available via AppStream/SCL | Notes |
|---|---|---|---|
| RHEL 6 | Python 2.6 | Python 2.7, 3.3 via SCL | /usr/bin/python = Python 2.6 |
| RHEL 7 | Python 2.7 | Python 3.6 via SCL/extras | /usr/bin/python = Python 2.7; yum depends on it |
| RHEL 8 | Python 3.6 (unversioned python not set) |
Python 3.8, 3.9, 3.11 via AppStream | No /usr/bin/python by default; use python3 |
| RHEL 9 | Python 3.9 | Python 3.11, 3.12 via AppStream | /usr/bin/python3 = Python 3.9; python unversioned symlink available |
On RHEL 8, there is no /usr/bin/python by default. This breaks any script with #!/usr/bin/python as its shebang line. You need to either install the python3 package and update shebangs, or run alternatives --set python /usr/bin/python3 to create the symlink.
RHEL 8 still offers Python 2.7 as an installable package (python2), but it is deprecated and receives minimal maintenance. RHEL 9 removed Python 2 entirely.
Full Comparison Table
This table summarizes all the major differences at a glance. Pin it to your migration planning wiki.
| Component | RHEL 6 | RHEL 7 | RHEL 8 | RHEL 9 |
|---|---|---|---|---|
| Release date | Nov 2010 | Jun 2014 | May 2019 | May 2022 |
| Kernel | 2.6.32 | 3.10 | 4.18 | 5.14 |
| Init system | SysVinit + Upstart | systemd | systemd | systemd |
| Package manager | yum (rpm) | yum (rpm) | dnf (rpm) | dnf (rpm) |
| Default filesystem | ext4 | XFS | XFS | XFS |
| Firewall tool | iptables (direct) | firewalld (iptables backend) | firewalld (nftables backend) | firewalld (nftables backend) |
| Container runtime | None (unsupported) | Docker | Podman, Buildah, Skopeo | Podman, Buildah, Skopeo |
| Python | 2.6 | 2.7 | 3.6 (2.7 optional) | 3.9 |
| OpenSSL | 1.0.1 | 1.0.2 | 1.1.1 | 3.0 |
| Crypto policies | N/A | N/A | Yes (DEFAULT, LEGACY, FUTURE, FIPS) | Yes (stricter DEFAULT) |
| SELinux | Enforcing (targeted) | Enforcing (targeted) | Enforcing (targeted + container) | Enforcing (targeted, stricter) |
| Network config tool | network scripts | NetworkManager + network scripts | NetworkManager (scripts deprecated) | NetworkManager only |
| NTP | ntpd | chrony (ntpd available) | chrony | chrony |
| GCC version | 4.4 | 4.8 | 8.5 | 11 |
| Maintenance support end | Nov 2020 | Jun 2024 | May 2029 | May 2032 |
Migration Considerations
Red Hat does not support in-place upgrades that skip versions. You can go from RHEL 7 to 8, or 8 to 9, but not 6 to 9 directly. The supported in-place upgrade tool is leapp, available for RHEL 7-to-8 and 8-to-9 transitions.
From RHEL 6 to 7 (or later)
There is no supported in-place upgrade path from RHEL 6. You need to build new RHEL 7 (or preferably RHEL 8/9) systems and migrate workloads. Key areas to address:
- Convert all init scripts from
/etc/init.d/to systemd unit files - Replace
chkconfigandserviceusage in automation scripts withsystemctl - Test all Python scripts, as Python 2.6 to 2.7 changes can break library compatibility
- Replace raw iptables rules with firewalld commands or zones
- Update network scripts to NetworkManager configuration
From RHEL 7 to 8
Use leapp for in-place upgrades. Before upgrading:
# Install and run the pre-upgrade assessment
yum install leapp-upgrade
leapp preupgrade
# Review /var/log/leapp/leapp-report.txt for issues
# Fix all inhibitors before proceeding
leapp upgrade
Common blockers include:
- Python 2 scripts that need porting to Python 3
- Direct iptables rules that need conversion to firewalld/nftables
- Docker containers that need migration to Podman
- Third-party packages that do not have RHEL 8 versions
- Custom kernel modules that need rebuilding for the 4.18 kernel
From RHEL 8 to 9
The RHEL 8 to 9 upgrade is smoother than 7 to 8, since both use systemd, dnf, and Podman. Still, watch out for:
- OpenSSL 3.0 dropping support for older algorithms (some TLS connections may fail)
- Stricter crypto policies (DEFAULT on RHEL 9 disables SHA-1 signatures)
- Network scripts completely removed (must use NetworkManager)
- Legacy iptables packages not installed by default
- Python 2 is gone entirely
General Tips for Any Migration
- Run
leapp preupgradeon a non-production clone first. Read the full report before touching production. - Test all custom scripts, especially anything that calls
python,iptables,service, oryum. - Verify third-party repositories have packages for the target RHEL version before starting.
- Schedule downtime. Even with leapp, in-place upgrades take 30 to 90 minutes depending on the number of installed packages.
- Keep the old system available (snapshot, backup, or parallel hardware) until you have fully validated the new environment.
Summary
The jump from RHEL 6 to RHEL 9 touches nearly every subsystem a sysadmin interacts with daily. The init system, package manager, firewall stack, container runtime, default filesystem, Python version, and security policies have all changed.
For teams still on RHEL 6, the priority is clear: that version is fully end-of-life with no patches available. RHEL 7 is in ELS and will reach its final end in June 2028. If you are planning new deployments, RHEL 9 is the target. If you are migrating existing workloads, the leapp tool handles RHEL 7-to-8 and 8-to-9 transitions, but each hop requires testing and remediation of deprecated features.
The practical approach is to inventory your custom scripts, document your firewall rules, check your Python dependencies, and test the upgrade path in a staging environment before committing to production. No amount of reading replaces running leapp preupgrade on a clone of your actual system and working through the report line by line.
