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
| Feature | Rocky Linux | AlmaLinux |
|---|---|---|
| RHEL Compatibility | 1:1 Binary | 1:1 Binary (ABI future) |
| Governance | Community Foundation | Non-profit Foundation |
| Commercial Backing | None | CloudLinux |
| Paid Support | Third-party | CloudLinux |
| Migration Tools | migrate2rocky | almalinux-deploy |
| Release Timing | Days after RHEL | Days after RHEL |
| Customization | Minimal changes | Minimal 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
- Test First: Always test migration on non-production systems
- Backup Everything: Multiple backup types (snapshots, tar, databases)
- Document Thoroughly: Inventory, configurations, procedures
- Schedule Maintenance Windows: Communicate with stakeholders
- Have Rollback Plan: Know how to restore from backups
During Migration
- Use Screen/Tmux: Prevent SSH disconnection issues
- Monitor Progress: Watch logs in separate terminal
- Don't Interrupt: Let migration complete fully
- Keep Notes: Document any errors or warnings
Post-Migration
- Verify Thoroughly: Check all services and applications
- Monitor Closely: Watch logs for several days
- Update Documentation: Reflect new OS version
- 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:
-
Migration is Necessary: CentOS 7 reaches EOL June 2024. Unpatched systems create security risks and compliance issues.
-
Both Options are Viable: Rocky Linux and AlmaLinux are both excellent choices. Selection often comes down to philosophical preferences or support requirements.
-
In-Place Migration Works: The migrate2rocky and almalinux-deploy scripts provide reliable in-place migrations for most systems.
-
Testing is Critical: Never migrate production without testing the exact procedure on replicas first.
-
Backups are Mandatory: Comprehensive backups provide safety net for unexpected issues.
-
Verification is Essential: Thorough post-migration testing ensures all services function correctly.
-
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:
- Update disaster recovery documentation
- Modify monitoring and alerting for new OS version
- Train team on any differences
- Establish regular update schedule
- Join community forums and mailing lists
- Contribute back to chosen distribution
- 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.


