+1 (276) 265-7197

Still on CentOS 7? Planning the Move to Rocky or Alma 9

CentOS 7 stopped receiving updates on 30 June 2024. Not "is approaching end of life" — stopped. Kernel, glibc, openssl, httpd: whatever version is on that box is the last version it will ever get from the distro, and the CVEs published since then stay open unless you are paying for extended support from TuxCare or Red Hat. A surprising number of profitable applications are still running there, and the reason is usually sensible: the box works, and nobody wanted to be the person who broke it.

This is the path off, written the way we run it.

First: is it actually CentOS 7?

Check rather than assume — we have walked into "CentOS 7" estates that turned out to be two 7.x boxes, one CentOS 6, and a Stream 8 machine that went EOL in May 2024 as well.

cat /etc/os-release
rpm -q --qf '%{VERSION}\n' centos-release 2>/dev/null
php -v; httpd -v; mysql --version

Write the four versions down per host. That list is the scope of the project, and it is usually smaller than people fear.

In-place upgrade or build new?

There are two honest options.

In-place with ELevate. AlmaLinux's ELevate project extends Red Hat's leapp tooling to convert CentOS 7 to Alma/Rocky/Oracle 8, and then 8 to 9. It works, and we have used it. But it is two sequential major upgrades on a live machine, it leaves behind a filesystem with years of accumulated drift, and if it fails mid-run your recovery is a restore. It is the right call when the server has hardware-specific setup, unusual licensed software, or an operator who genuinely knows every file on it.

Build a new EL9 host and cut over. For most LAMP applications this is faster, safer, and cheaper. You get a clean Rocky 9 or AlmaLinux 9 machine, install current httpd 2.4, PHP 8.3/8.4, and MySQL 8.4 from vendor repos, deploy the application, test, then move DNS. Rollback is "point DNS back", which is the warm rollback path we want on every one-way change. The old box stays powered on and read-only for a week.

If you cannot answer "what is installed on that server and why" without SSH-ing in and reading, you do not have a system you can upgrade in place — you have one you need to rebuild and document. Rebuilding forces that inventory.

The four things that actually break

1. OpenSSL 3 and system-wide crypto policies. EL9 ships OpenSSL 3 and enforces a system crypto policy that removes TLS 1.0/1.1, SHA-1 signatures, and sub-2048-bit RSA. Old API clients, legacy payment gateways, and internal tools pinned to ancient TLS will simply fail to connect, often with an unhelpful handshake error. Test those integrations early. update-crypto-policies --set LEGACY exists as a temporary bridge, but it weakens the whole host — treat it as a dated exception with a ticket, not a setting.

2. MySQL is not the default. EL8/EL9's AppStream ships MariaDB; dnf install mysql-server gets you a MySQL 8.0 module that is itself now past its support window. If the application is on MySQL, install from Oracle's repo and target 8.4 LTS so you are not doing this again next year. Do not let a server migration quietly become a MariaDB migration — the dialects have diverged enough (JSON functions, sequences, utf8mb4 collations, invisible columns) to produce bugs you will debug at 2 a.m. If you do want MariaDB, decide it deliberately and test it as its own project.

3. SELinux is enforcing, and it means it. CentOS 7 boxes frequently have SELINUX=permissive set years ago to make an upload directory work. On the new host, leave it enforcing and fix the labels properly: semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/app/storage(/.*)?' then restorecon -Rv, plus setsebool -P httpd_can_network_connect on if PHP calls out to APIs or a remote database. Ten minutes of ausearch -m avc -ts recent during testing buys you a hardening control you were otherwise writing off.

4. PHP came from somewhere unusual. CentOS 7's stock PHP is 5.4. Any app still running was almost certainly fed by SCL (rh-php72) or Remi, which means paths like /opt/rh/..., a non-standard php.ini location, and an FPM unit with a name nobody remembers. On EL9, PHP 8.3 or 8.4 comes from the AppStream module stream or Remi at normal paths. Diff the old php --ini output and the loaded extension list (php -m) against the new host before you test — a missing php-mbstring, php-intl, or an old php-mcrypt dependency is the usual cause of a blank page after cutover.

Also check the Apache config, but expect less drama: 2.4 to 2.4 means the Require syntax is unchanged. What bites is modules that moved or vanished, mod_php no longer being a supported path (use PHP-FPM behind mpm_event), and config split across /etc/httpd/conf.d/ files that were edited in place and never committed anywhere.

The order we run it

  1. Inventory versions, extensions, cron jobs, and outbound integrations on the old host.
  2. Build the EL9 host from a script or Ansible playbook — not by hand, so it is reproducible.
  3. Restore last night's production database onto it. This doubles as a backup-restore drill.
  4. Deploy the application, run the test suite and a manual pass over the five routes that make money.
  5. Test the legacy TLS integrations specifically.
  6. Cut over in a low-traffic window: put the app read-only or accept a short write freeze, take a final delta of the database, flip DNS with a lowered TTL set 48 hours earlier.
  7. Watch error logs and p95 latency for a week. Keep the old host off the network but intact for two.

What this costs

A single-server LAMP application with a typical amount of accumulated configuration is usually a week of engineering, most of it testing rather than installing. A PHP major-version jump bundled in adds more, and often should be a separate change so that when something breaks you know which change broke it.

If your CentOS 7 box is behind a WAF, has no inbound ports open, and runs an internal tool with five users, you have less urgency than a public e-commerce site and it is fine to schedule this next quarter. If it terminates TLS on the public internet and takes card numbers, the unpatched openssl on it is a finding waiting to happen. Either way the honest answer is the same: it is a planned week of work, not an emergency, and it gets more expensive the longer the version gap grows.

If you want the inventory and the migration plan without doing the reading yourself, tell us what versions you are on and we will tell you which of the two paths we would take.