Migrating from CentOS to Rocky Linux or AlmaLinux

The discontinuation of CentOS Linux in December 2021 forced millions of system administrators to evaluate migration paths for their production infrastructure. This unexpected shift transformed the enterprise Linux landscape, creating both challenges and opportunities for organizations relying on CentOS for their critical systems.

This comprehensive guide provides detailed instructions for migrating from CentOS to Rocky Linux or AlmaLinux, two community-driven, RHEL-compatible distributions that emerged as the leading CentOS alternatives. Whether you're managing a handful of servers or orchestrating migrations across hundreds of systems, this guide covers planning, execution, verification, and troubleshooting for successful transitions.

Table of Contents

  • Introduction
  • Understanding the CentOS Situation
  • Rocky Linux vs AlmaLinux: Comparison
  • Pre-Migration Planning and Assessment
  • Backup and Recovery Preparation
  • Migration Method 1: In-Place Migration (Recommended)
  • Migration Method 2: Fresh Installation
  • Migrating Specific Workloads
  • Post-Migration Verification
  • Troubleshooting Common Issues
  • Migrating at Scale
  • Alternative Migration Paths
  • Best Practices and Recommendations
  • Conclusion

Introduction

On December 8, 2020, Red Hat announced that CentOS Linux would be discontinued, with CentOS 8 reaching end-of-life on December 31, 2021, and CentOS 7 receiving updates until June 30, 2024. This decision redirected the CentOS project toward CentOS Stream, a rolling-release distribution positioned upstream of Red Hat Enterprise Linux (RHEL) rather than downstream.

This change eliminated the stable, predictable CentOS Linux that organizations had relied upon for nearly two decades, forcing administrators to choose between:

  • Rocky Linux: Founded by Gregory Kurtzer (original CentOS founder), providing 1:1 RHEL binary compatibility
  • AlmaLinux: Created by CloudLinux, offering RHEL compatibility with commercial backing
  • CentOS Stream: Red Hat's rolling release, upstream of RHEL
  • RHEL: Migrating to paid Red Hat subscriptions
  • Alternative Distributions: Moving to Ubuntu, Debian, or other Linux distributions

Both Rocky Linux and AlmaLinux provide drop-in replacements for CentOS, maintaining binary compatibility with RHEL and offering long-term support lifecycles. This guide focuses on migrating to these community-driven alternatives that preserve the stability and predictability that made CentOS popular.

Understanding the CentOS Situation

CentOS History and Timeline

# Check your current CentOS version
cat /etc/centos-release

# Example outputs:
# CentOS Linux release 7.9.2009 (Core)
# CentOS Linux release 8.4.2105

Critical Timeline:

  • December 2020: CentOS 8 EOL announcement
  • December 31, 2021: CentOS 8 reached end-of-life (no more updates)
  • June 30, 2024: CentOS 7 reaches end-of-life
  • Ongoing: CentOS Stream continues as upstream RHEL preview

Why Migration is Necessary

Security Risks:

# Check time since last security update
rpm -qa --last | grep -i kernel | head -5

# Systems without updates receive no security patches
# Unpatched vulnerabilities accumulate over time
# Compliance frameworks require current security updates

Compliance Issues:

  • PCI-DSS requires supported operating systems
  • HIPAA mandates security patch management
  • SOC 2 compliance demands current software
  • Insurance and audit requirements

Technical Debt:

  • Missing security patches create vulnerabilities
  • Software packages become increasingly outdated
  • Third-party software may drop support
  • Container base images become insecure

Rocky Linux vs AlmaLinux: Comparison

Both distributions aim to replace CentOS with RHEL-compatible alternatives, but subtle differences exist.

Rocky Linux Overview

# Rocky Linux characteristics
cat << 'EOF'
Founded: 2020
Founder: Gregory Kurtzer (original CentOS founder)
Governance: Rocky Enterprise Software Foundation (community-led)
Funding: Sponsorships, donations
Binary Compatibility: 1:1 with RHEL
Support Lifecycle: 10 years (matching RHEL)
Commercial Support: Emerging third-party options
EOF

Key Features:

  • Community-driven governance structure
  • Strong focus on open-source principles
  • Active development community
  • Growing ecosystem support

AlmaLinux Overview

# AlmaLinux characteristics
cat << 'EOF'
Founded: 2020
Founder: CloudLinux Inc.
Governance: AlmaLinux OS Foundation (non-profit)
Funding: CloudLinux sponsorship, donations
Binary Compatibility: 1:1 with RHEL (moving to ABI compatibility)
Support Lifecycle: 10 years (matching RHEL)
Commercial Support: CloudLinux paid support available
EOF

Key Features:

  • Commercial backing from CloudLinux
  • Mature infrastructure from day one
  • Professional support available
  • Strong security focus

Feature Comparison

FeatureRocky LinuxAlmaLinux
RHEL Compatibility1:1 Binary1:1 Binary (ABI future)
GovernanceCommunity FoundationNon-profit Foundation
Commercial BackingNoneCloudLinux
Paid SupportThird-partyCloudLinux
Migration Toolsmigrate2rockyalmalinux-deploy
Release TimingDays after RHELDays after RHEL
CustomizationMinimal changesMinimal changes

Which to Choose?

Choose Rocky Linux if:

  • You prefer pure community governance
  • You value independence from corporate influence
  • Your team has CentOS 7 experience
  • You don't require commercial support

Choose AlmaLinux if:

  • You want commercial support options
  • You prefer organizational backing
  • You need professional SLAs
  • You value CloudLinux's infrastructure

Reality: Both distributions are excellent CentOS replacements. The differences are primarily philosophical rather than technical. Many organizations choose based on community preference or existing vendor relationships.

# Test both distributions before deciding
# Use VMs or containers to evaluate each
docker run -it rockylinux:9 bash
docker run -it almalinux:9 bash

Pre-Migration Planning and Assessment

Successful migrations begin with thorough planning and system assessment.

System Inventory

#!/bin/bash
# Create comprehensive system inventory

REPORT_DIR="/root/migration-assessment-$(date +%Y%m%d)"
mkdir -p "$REPORT_DIR"

echo "Creating system inventory for migration planning..."

# System information
hostnamectl > "$REPORT_DIR/system-info.txt"
cat /etc/centos-release >> "$REPORT_DIR/system-info.txt"
uname -a >> "$REPORT_DIR/system-info.txt"

# Hardware details
lscpu > "$REPORT_DIR/cpu-info.txt"
free -h > "$REPORT_DIR/memory-info.txt"
df -h > "$REPORT_DIR/disk-info.txt"
lsblk >> "$REPORT_DIR/disk-info.txt"

# Installed packages
rpm -qa | sort > "$REPORT_DIR/installed-packages.txt"
yum repolist > "$REPORT_DIR/repositories.txt"

# Running services
systemctl list-units --type=service --state=running > "$REPORT_DIR/services.txt"

# Kernel modules
lsmod > "$REPORT_DIR/kernel-modules.txt"

# Network configuration
ip addr show > "$REPORT_DIR/network-config.txt"
ip route show >> "$REPORT_DIR/network-config.txt"

# SELinux status
sestatus > "$REPORT_DIR/selinux-status.txt"

# Custom RPMs (not from official repos)
rpm -qa --qf '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH} %{VENDOR}\n' | grep -v "CentOS\|Red Hat" > "$REPORT_DIR/custom-packages.txt"

echo "Inventory saved to $REPORT_DIR"

Identify Critical Services

#!/bin/bash
# Document critical services and their configurations

cat << 'EOF' > /root/critical-services.md
## Critical Services Inventory

### Web Services
- Nginx: /etc/nginx/
- Apache: /etc/httpd/
- Configurations: Custom vhosts, SSL certificates

### Database Services
- PostgreSQL: /var/lib/pgsql/
- MariaDB: /var/lib/mysql/
- Configurations: Custom my.cnf, pg_hba.conf

### Application Services
- Custom applications: /opt/applications/
- SystemD units: /etc/systemd/system/
- Cron jobs: /etc/cron.d/, /var/spool/cron/

### Network Services
- Firewalld: /etc/firewalld/
- DNS: /etc/named/
- NTP: /etc/chrony/

### Monitoring & Logging
- Prometheus exporters
- Log forwarding (rsyslog)
- Monitoring agents
EOF

Check Third-Party Software

# Identify non-standard repositories
yum repolist all

# Check for EPEL packages
rpm -qa | grep epel

# Check for commercial software
rpm -qa | grep -E "oracle|mongodb|elastic|puppet|chef"

# List packages from third-party repos
yum list installed | grep -v "@base\|@updates\|@extras"

# Document proprietary drivers
lsmod | grep -E "nvidia|amd|proprietary"

Assess Migration Complexity

cat << 'EOF' > /root/migration-complexity.md
## Migration Complexity Assessment

### Low Complexity (Safe for in-place migration)
- [ ] Standard LAMP/LEMP stack
- [ ] Using official CentOS repositories only
- [ ] No custom kernel modules
- [ ] Standard configurations
- [ ] Testing environment available

### Medium Complexity (In-place possible with caution)
- [ ] EPEL packages installed
- [ ] Third-party repositories (Docker, PostgreSQL)
- [ ] Custom configurations but well-documented
- [ ] Some proprietary software
- [ ] Limited testing environment

### High Complexity (Consider fresh installation)
- [ ] Custom compiled kernel
- [ ] Proprietary drivers
- [ ] Unsupported commercial software
- [ ] Extensive customizations
- [ ] No testing environment
- [ ] Critical production system

**Decision**: Based on assessment, choose migration method
EOF

Create Migration Timeline

cat << 'EOF' > /root/migration-timeline.md
## CentOS to Rocky Linux Migration Timeline

### Phase 1: Preparation (Week 1-2)
- [ ] Complete system inventory
- [ ] Document configurations
- [ ] Create backups
- [ ] Set up testing environment
- [ ] Test migration on replica

### Phase 2: Testing (Week 3-4)
- [ ] Perform test migration
- [ ] Validate applications
- [ ] Document issues and solutions
- [ ] Update migration procedures
- [ ] Train team on new procedures

### Phase 3: Non-Critical Systems (Week 5-6)
- [ ] Migrate development servers
- [ ] Migrate testing environments
- [ ] Validate monitoring
- [ ] Document any issues

### Phase 4: Production Migration (Week 7-12)
- [ ] Schedule maintenance windows
- [ ] Migrate production servers (staged)
- [ ] Monitor closely for issues
- [ ] Update documentation
- [ ] Validate compliance

### Phase 5: Cleanup (Week 13-14)
- [ ] Remove old backups
- [ ] Update disaster recovery plans
- [ ] Final documentation updates
- [ ] Team retrospective
EOF

Backup and Recovery Preparation

Never migrate without comprehensive backups and tested recovery procedures.

Complete System Backup

#!/bin/bash
# Comprehensive backup before migration

BACKUP_DIR="/backup/pre-migration-$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"

echo "Starting complete system backup..."

# Full system backup (excluding virtual filesystems)
tar --exclude=/backup \
    --exclude=/proc \
    --exclude=/tmp \
    --exclude=/mnt \
    --exclude=/dev \
    --exclude=/sys \
    --exclude=/run \
    --exclude=/media \
    --exclude=/var/cache \
    --exclude=/var/tmp \
    -czf "$BACKUP_DIR/system-backup.tar.gz" /

# Backup critical configurations separately
tar -czf "$BACKUP_DIR/etc-backup.tar.gz" /etc
tar -czf "$BACKUP_DIR/var-lib-backup.tar.gz" /var/lib

# Create RPM package list
rpm -qa --qf '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' | sort > "$BACKUP_DIR/rpm-list.txt"

# Backup yum/dnf configuration
tar -czf "$BACKUP_DIR/yum-backup.tar.gz" /etc/yum.repos.d/ /etc/yum.conf

echo "System backup completed: $BACKUP_DIR"
echo "Backup size: $(du -sh $BACKUP_DIR)"

Database Backups

#!/bin/bash
# Backup all databases before migration

BACKUP_DIR="/backup/databases-$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"

# PostgreSQL backup
if systemctl is-active --quiet postgresql; then
    echo "Backing up PostgreSQL..."
    sudo -u postgres pg_dumpall > "$BACKUP_DIR/postgresql-all.sql"
    gzip "$BACKUP_DIR/postgresql-all.sql"
fi

# MariaDB/MySQL backup
if systemctl is-active --quiet mariadb; then
    echo "Backing up MariaDB..."
    mysqldump --all-databases --single-transaction \
        --routines --triggers --events \
        > "$BACKUP_DIR/mariadb-all.sql"
    gzip "$BACKUP_DIR/mariadb-all.sql"
fi

echo "Database backups completed: $BACKUP_DIR"

Snapshot-Based Backups

# For virtual machines - create snapshot before migration

# VMware snapshot
# Create snapshot via vSphere/ESXi interface
# Name: "Pre-Rocky-Migration-$(date +%Y%m%d)"

# LVM snapshot
sudo lvcreate -L 20G -s -n root-pre-migration /dev/vg0/root

# Cloud snapshots (AWS example)
aws ec2 create-snapshot \
    --volume-id vol-1234567890abcdef0 \
    --description "Pre-Rocky-Linux-migration-$(date +%Y%m%d)"

# Verify snapshot created
aws ec2 describe-snapshots --snapshot-ids snap-xxxxxxxxx

Migration Method 1: In-Place Migration (Recommended)

In-place migration converts CentOS to Rocky Linux or AlmaLinux without reinstallation.

Migrating to Rocky Linux

Step 1: Prepare the System

# Update CentOS to latest version before migration
sudo yum update -y

# Reboot if kernel updated
if [ -f /var/run/reboot-required ]; then
    echo "Reboot required - please reboot before migration"
    # sudo reboot
fi

# Verify system is fully updated
yum check-update

Step 2: Download Migration Script

# Download official migrate2rocky script
curl https://raw.githubusercontent.com/rocky-linux/rocky-tools/main/migrate2rocky/migrate2rocky.sh -o migrate2rocky.sh

# Review the script (recommended)
less migrate2rocky.sh

# Make executable
chmod +x migrate2rocky.sh

Step 3: Run Migration

# Execute migration script
# Use screen or tmux for SSH sessions
screen -S rocky-migration

# Run the migration
sudo ./migrate2rocky.sh -r

# The script will:
# 1. Verify system compatibility
# 2. Download Rocky Linux repositories
# 3. Replace CentOS packages with Rocky equivalents
# 4. Update all packages
# 5. Install Rocky branding

# This process takes 15-60 minutes depending on:
# - Number of packages
# - Network speed
# - System resources

Step 4: Reboot and Verify

# Reboot system after migration
sudo reboot

# After reboot, verify Rocky Linux
cat /etc/rocky-release
# Should show: Rocky Linux release 8.x (Green Obsidian)

# Check OS information
hostnamectl

# Verify RPM database
rpm -qa | grep -i rocky

# Check for any CentOS remnants
rpm -qa | grep -i centos

Migrating to AlmaLinux

Step 1: Prepare the System

# Update CentOS completely
sudo yum update -y

# Clean yum cache
sudo yum clean all

# Verify no broken packages
rpm -Va

# Reboot if necessary
if [ -f /var/run/reboot-required ]; then
    sudo reboot
fi

Step 2: Download AlmaLinux Migration Tool

# Download almalinux-deploy script
curl -O https://raw.githubusercontent.com/AlmaLinux/almalinux-deploy/master/almalinux-deploy.sh

# Verify script integrity (optional but recommended)
# Check SHA256 from official AlmaLinux documentation

# Make executable
chmod +x almalinux-deploy.sh

Step 3: Execute Migration

# Run in screen/tmux session
screen -S alma-migration

# Execute migration
sudo bash almalinux-deploy.sh

# The script will:
# 1. Check system compatibility
# 2. Backup current release files
# 3. Download AlmaLinux repositories
# 4. Replace CentOS packages
# 5. Update system to AlmaLinux

# Migration typically takes 20-60 minutes

Step 4: Verify Migration

# Reboot after migration
sudo reboot

# Verify AlmaLinux installation
cat /etc/almalinux-release
# Output: AlmaLinux release 8.x (Sky Tiger)

# Check system information
hostnamectl

# Verify package base
rpm -qa | grep -i alma

# Check for remaining CentOS packages
rpm -qa | grep -i centos | grep -v centos-release

Post-Migration Package Cleanup

# Remove old CentOS branding packages (if any remain)
sudo rpm -e --nodeps $(rpm -qa | grep -i centos-logos)
sudo rpm -e --nodeps $(rpm -qa | grep -i centos-release)

# Clean package cache
sudo dnf clean all

# Rebuild RPM database
sudo rpm --rebuilddb

# Update all packages
sudo dnf update -y

Migration Method 2: Fresh Installation

For complex systems or when in-place migration is too risky.

Fresh Installation Procedure

Step 1: Document Current System

#!/bin/bash
# Comprehensive documentation for fresh installation

DOC_DIR="/root/fresh-install-docs-$(date +%Y%m%d)"
mkdir -p "$DOC_DIR"

# Installed packages
rpm -qa > "$DOC_DIR/packages.txt"

# Service configurations
systemctl list-unit-files --state=enabled > "$DOC_DIR/enabled-services.txt"

# Network configuration
cp -r /etc/sysconfig/network-scripts "$DOC_DIR/"
ip addr show > "$DOC_DIR/ip-config.txt"

# Firewall rules
firewall-cmd --list-all-zones > "$DOC_DIR/firewall-rules.txt"

# Cron jobs
crontab -l > "$DOC_DIR/root-crontab.txt"
ls -la /etc/cron.d/ > "$DOC_DIR/cron.d-files.txt"

# Users and groups
getent passwd > "$DOC_DIR/users.txt"
getent group > "$DOC_DIR/groups.txt"

# Application data locations
find /opt -type d -maxdepth 2 > "$DOC_DIR/opt-structure.txt"
find /var/www -type d -maxdepth 2 > "$DOC_DIR/www-structure.txt" 2>/dev/null

Step 2: Backup Application Data

#!/bin/bash
# Backup application data and user files

BACKUP_DIR="/backup/fresh-install-$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"

# Web application data
if [ -d /var/www ]; then
    tar -czf "$BACKUP_DIR/var-www.tar.gz" /var/www
fi

# Application directories
if [ -d /opt ]; then
    tar -czf "$BACKUP_DIR/opt.tar.gz" /opt
fi

# User home directories
tar -czf "$BACKUP_DIR/home.tar.gz" /home

# Databases (dump format)
# See database backup section earlier

echo "Application data backed up to $BACKUP_DIR"

Step 3: Install Fresh Rocky Linux / AlmaLinux

# Download ISO from official sources
# Rocky Linux: https://rockylinux.org/download
# AlmaLinux: https://almalinux.org/get-almalinux/

# Boot from installation media
# Follow installation wizard:
# 1. Select language
# 2. Configure disk partitions (match old layout)
# 3. Configure network (same IP/hostname)
# 4. Set root password
# 5. Create user accounts
# 6. Select minimal or server installation
# 7. Complete installation and reboot

Step 4: Restore Configuration and Data

#!/bin/bash
# Restore configurations on fresh installation

BACKUP_DIR="/backup/fresh-install-20241215"

# Install packages from old system
# Review list and install needed packages
while read package; do
    dnf install -y "$package" || echo "Failed: $package"
done < "$BACKUP_DIR/packages.txt"

# Restore configurations
tar -xzf "$BACKUP_DIR/etc-specific.tar.gz" -C /

# Restore application data
tar -xzf "$BACKUP_DIR/var-www.tar.gz" -C /
tar -xzf "$BACKUP_DIR/opt.tar.gz" -C /

# Restore databases
# PostgreSQL
gunzip < "$BACKUP_DIR/postgresql-all.sql.gz" | sudo -u postgres psql

# MariaDB
gunzip < "$BACKUP_DIR/mariadb-all.sql.gz" | mysql

# Set proper permissions
chown -R nginx:nginx /var/www  # or apache:apache
restorecon -R /var/www  # Restore SELinux contexts

# Enable and start services
systemctl enable nginx postgresql
systemctl start nginx postgresql

Migrating Specific Workloads

Different workloads require specific considerations during migration.

Web Servers (Apache/Nginx)

# Before migration - backup configurations
tar -czf /backup/httpd-config.tar.gz /etc/httpd
tar -czf /backup/nginx-config.tar.gz /etc/nginx

# After migration - verify web server
systemctl status httpd
systemctl status nginx

# Test configuration
httpd -t  # Apache
nginx -t  # Nginx

# Check virtual hosts
httpd -S  # Apache vhost summary
nginx -T  # Nginx full configuration

# Verify SSL certificates
openssl x509 -in /etc/ssl/certs/cert.pem -text -noout

# Restart web services
systemctl restart httpd nginx

Database Servers

# PostgreSQL migration verification
sudo -u postgres psql -c "SELECT version();"

# Check databases
sudo -u postgres psql -l

# Verify data directory
ls -la /var/lib/pgsql/

# MariaDB/MySQL verification
mysql -e "SELECT VERSION();"

# Check databases
mysql -e "SHOW DATABASES;"

# Verify data integrity
mysqlcheck --all-databases

# Check performance
mysqladmin status

Docker and Container Workloads

# Verify Docker installation
docker --version
systemctl status docker

# List existing containers
docker ps -a

# List images
docker images

# Verify networks
docker network ls

# Test container creation
docker run hello-world

# Check Docker Compose
docker-compose --version

# Verify volumes
docker volume ls

Kubernetes Nodes

# After migration, rejoin cluster or verify node status

# Check kubelet
systemctl status kubelet

# Verify node status
kubectl get nodes

# Check running pods
kubectl get pods --all-namespaces

# Verify CNI plugin
ls -la /etc/cni/net.d/

# Check container runtime
crictl version

# Drain node before migration
kubectl drain node-name --ignore-daemonsets

# Uncordon after migration
kubectl uncordon node-name

Post-Migration Verification

Thorough verification ensures migration success.

System Verification Checklist

#!/bin/bash
# Comprehensive post-migration verification

echo "Post-Migration Verification Report"
echo "===================================="
echo ""

# OS Version
echo "Operating System:"
cat /etc/os-release | grep "^NAME\|^VERSION"
echo ""

# Kernel Version
echo "Kernel:"
uname -r
echo ""

# System Status
echo "System Status:"
systemctl is-system-running
echo ""

# Failed Services
echo "Failed Services:"
systemctl --failed
echo ""

# Disk Space
echo "Disk Space:"
df -h / | tail -1
echo ""

# Memory
echo "Memory:"
free -h | grep Mem
echo ""

# Network
echo "Network Connectivity:"
ping -c 3 google.com > /dev/null 2>&1 && echo "✓ Internet OK" || echo "✗ Internet FAILED"
echo ""

# SELinux
echo "SELinux Status:"
sestatus | grep "Current mode"
echo ""

# Package Database
echo "RPM Database:"
rpm -qa > /dev/null 2>&1 && echo "✓ RPM DB OK" || echo "✗ RPM DB DAMAGED"
echo ""

# Repository Access
echo "Repository Access:"
dnf repolist > /dev/null 2>&1 && echo "✓ Repos OK" || echo "✗ Repos FAILED"
echo ""

Application-Specific Testing

#!/bin/bash
# Test critical applications

# Web server response
curl -I http://localhost > /dev/null 2>&1
if [ $? -eq 0 ]; then
    echo "✓ Web server responding"
else
    echo "✗ Web server not responding"
fi

# Database connection
if systemctl is-active --quiet postgresql; then
    sudo -u postgres psql -c "SELECT 1;" > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        echo "✓ PostgreSQL responding"
    else
        echo "✗ PostgreSQL connection failed"
    fi
fi

# Custom application health check
# Add application-specific tests here
curl http://localhost:8000/health

Security Verification

# Verify SELinux is enforcing
sestatus

# Check for AVC denials
ausearch -m avc -ts recent

# Verify firewall
firewall-cmd --state
firewall-cmd --list-all

# Check open ports
ss -tulpn

# Verify SSH configuration
sshd -t

# Check for unauthorized changes
rpm -Va | grep '^..5'  # Files with changed content

Troubleshooting Common Issues

Migration Script Failures

# Issue: Migration script fails with dependency errors

# Solution: Update CentOS fully first
sudo yum update -y
sudo yum clean all
sudo rpm --rebuilddb

# Remove problematic packages
sudo rpm -e --nodeps package-name

# Retry migration
sudo ./migrate2rocky.sh -r

Package Conflicts

# Issue: RPM conflicts during migration

# Identify conflicting packages
rpm -qa | grep -i conflict

# Remove conflicts manually
sudo rpm -e --nodeps conflicting-package

# Reinstall after migration
sudo dnf install package-name

Repository Issues

# Issue: Cannot access repositories after migration

# Clear cache
sudo dnf clean all
sudo rm -rf /var/cache/dnf

# Regenerate cache
sudo dnf makecache

# Verify repository configuration
ls -la /etc/yum.repos.d/

# Test repository access
sudo dnf repolist
sudo dnf check-update

SELinux Denials

# Issue: Services fail due to SELinux

# Check for denials
sudo ausearch -m avc -ts recent

# Temporarily set permissive for troubleshooting
sudo setenforce 0

# Fix SELinux contexts
sudo restorecon -R /var/www
sudo restorecon -R /etc/nginx

# Re-enable enforcing
sudo setenforce 1

# Generate policy for persistent denials
sudo ausearch -m avc -ts recent | audit2allow -M mypolicy
sudo semodule -i mypolicy.pp

Boot Issues

# Issue: System won't boot after migration

# Boot into rescue mode
# Select older kernel from GRUB menu

# Chroot into system
mount /dev/sda1 /mnt
mount --bind /dev /mnt/dev
mount --bind /proc /mnt/proc
mount --bind /sys /mnt/sys
chroot /mnt

# Reinstall bootloader
grub2-install /dev/sda
grub2-mkconfig -o /boot/grub2/grub.cfg

# Exit and reboot
exit
reboot

Migrating at Scale

Managing migrations across many servers requires automation.

Ansible Playbook for Migration

---
# rocky-migration-playbook.yml
- name: Migrate CentOS to Rocky Linux
  hosts: centos_servers
  serial: 1  # Migrate one server at a time
  become: yes

  tasks:
    - name: Create backup directory
      file:
        path: /backup/pre-migration-{{ ansible_date_time.date }}
        state: directory

    - name: Backup package list
      shell: rpm -qa > /backup/pre-migration-{{ ansible_date_time.date }}/packages.txt

    - name: Backup configurations
      archive:
        path: /etc
        dest: /backup/pre-migration-{{ ansible_date_time.date }}/etc-backup.tar.gz

    - name: Update CentOS
      yum:
        name: '*'
        state: latest

    - name: Reboot if needed
      reboot:
        reboot_timeout: 600
      when: ansible_facts['reboot_required'] is defined

    - name: Download migrate2rocky script
      get_url:
        url: https://raw.githubusercontent.com/rocky-linux/rocky-tools/main/migrate2rocky/migrate2rocky.sh
        dest: /root/migrate2rocky.sh
        mode: '0755'

    - name: Execute migration
      command: /root/migrate2rocky.sh -r
      register: migration_result

    - name: Reboot after migration
      reboot:
        reboot_timeout: 600

    - name: Verify Rocky Linux
      shell: cat /etc/rocky-release
      register: rocky_version

    - name: Display result
      debug:
        msg: "Migration successful: {{ rocky_version.stdout }}"

Batch Migration Script

#!/bin/bash
# Migrate multiple servers from inventory file

INVENTORY_FILE="/root/servers-to-migrate.txt"
LOG_FILE="/root/migration-log-$(date +%Y%m%d).txt"

# Read server list
while IFS= read -r server; do
    echo "$(date): Starting migration on $server" | tee -a "$LOG_FILE"

    # SSH to server and run migration
    ssh root@$server << 'ENDSSH'
        # Backup
        tar -czf /backup/pre-migration-$(date +%Y%m%d).tar.gz /etc

        # Update
        yum update -y

        # Download and run migration
        curl -O https://raw.githubusercontent.com/rocky-linux/rocky-tools/main/migrate2rocky/migrate2rocky.sh
        chmod +x migrate2rocky.sh
        ./migrate2rocky.sh -r

        # Reboot
        reboot
ENDSSH

    # Wait for server to come back online
    echo "Waiting for $server to reboot..." | tee -a "$LOG_FILE"
    sleep 60

    until ssh root@$server "echo 'Server online'"; do
        echo "Still waiting for $server..."
        sleep 30
    done

    # Verify migration
    ssh root@$server "cat /etc/rocky-release" | tee -a "$LOG_FILE"

    echo "$(date): Completed migration on $server" | tee -a "$LOG_FILE"
    echo "---" | tee -a "$LOG_FILE"

done < "$INVENTORY_FILE"

echo "All migrations completed. Check $LOG_FILE for details"

Alternative Migration Paths

CentOS Stream

# Convert CentOS Linux to CentOS Stream
# Not recommended for production stability

sudo dnf install centos-release-stream
sudo dnf swap centos-linux-repos centos-stream-repos
sudo dnf distro-sync

# CentOS Stream receives updates before RHEL
# Rolling release model
# Less predictable for production

Red Hat Enterprise Linux

# Convert to RHEL (requires subscription)
# Download convert2rhel tool
curl -o convert2rhel.rpm https://access.redhat.com/convert2rhel-latest.rpm
sudo yum install convert2rhel.rpm

# Register with Red Hat
subscription-manager register

# Run conversion
convert2rhel

# Requires valid RHEL subscription
# Provides official Red Hat support

Best Practices and Recommendations

Pre-Migration Best Practices

  1. Test First: Always test migration on non-production systems
  2. Backup Everything: Multiple backup types (snapshots, tar, databases)
  3. Document Thoroughly: Inventory, configurations, procedures
  4. Schedule Maintenance Windows: Communicate with stakeholders
  5. Have Rollback Plan: Know how to restore from backups

During Migration

  1. Use Screen/Tmux: Prevent SSH disconnection issues
  2. Monitor Progress: Watch logs in separate terminal
  3. Don't Interrupt: Let migration complete fully
  4. Keep Notes: Document any errors or warnings

Post-Migration

  1. Verify Thoroughly: Check all services and applications
  2. Monitor Closely: Watch logs for several days
  3. Update Documentation: Reflect new OS version
  4. Plan Regular Updates: Establish maintenance schedule

Recommended Timeline

# For production environments
Week 1-2: Planning and documentation
Week 3-4: Test environment migration and validation
Week 5-6: Non-critical system migration
Week 7+: Production migration (staged, monitored)

Conclusion

Migrating from CentOS to Rocky Linux or AlmaLinux is a necessary transition for organizations seeking stable, community-driven RHEL-compatible distributions. Both Rocky Linux and AlmaLinux provide excellent replacements for CentOS, offering binary compatibility, long-term support, and familiar environments for system administrators.

Key Takeaways:

  1. Migration is Necessary: CentOS 7 reaches EOL June 2024. Unpatched systems create security risks and compliance issues.

  2. Both Options are Viable: Rocky Linux and AlmaLinux are both excellent choices. Selection often comes down to philosophical preferences or support requirements.

  3. In-Place Migration Works: The migrate2rocky and almalinux-deploy scripts provide reliable in-place migrations for most systems.

  4. Testing is Critical: Never migrate production without testing the exact procedure on replicas first.

  5. Backups are Mandatory: Comprehensive backups provide safety net for unexpected issues.

  6. Verification is Essential: Thorough post-migration testing ensures all services function correctly.

  7. Plan for Scale: Large deployments benefit from automation via Ansible or similar tools.

When to Choose Rocky Linux:

  • Pure community governance preferred
  • Independence from corporate influence valued
  • Community-driven development desired

When to Choose AlmaLinux:

  • Commercial support options needed
  • CloudLinux backing valued
  • Professional SLAs required

Both distributions receive updates within days of RHEL releases, provide 10-year support lifecycles, and maintain the stability and predictability that made CentOS popular. The technical differences are minimal, making either choice reliable for production environments.

The CentOS discontinuation, while disruptive, created opportunities for truly community-driven Enterprise Linux distributions. By migrating to Rocky Linux or AlmaLinux, organizations maintain RHEL compatibility while supporting open-source community projects.

Next Steps

After successful migration:

  1. Update disaster recovery documentation
  2. Modify monitoring and alerting for new OS version
  3. Train team on any differences
  4. Establish regular update schedule
  5. Join community forums and mailing lists
  6. Contribute back to chosen distribution
  7. Plan for future LTS migrations

The migration from CentOS may have been forced by circumstance, but both Rocky Linux and AlmaLinux demonstrate the resilience and adaptability of the open-source community. With proper planning and execution, this migration strengthens rather than weakens your infrastructure foundation.