
Remi’s php84 Software Collection runs PHP 8.4 on Rocky Linux and AlmaLinux 9 or 8 without touching the PHP that ships with the OS. It installs under /opt/remi/php84, gives you its own php84 command and php84-php-fpm service, and leaves the system php package alone. Apps pinned to the AppStream build keep working while you move others over.
The steps below add EPEL and Remi, install PHP 8.4 with extensions, and show you how to prove the build is patched against PHP2Shell. If you would rather make PHP 8.4 the system default on EL10, the module stream guide for Rocky Linux 10 covers that route, and Ubuntu readers have a separate PHP 8.4 install for Ubuntu. Every command below was run on Rocky Linux 9 in October 2026 against Remi’s PHP 8.4.27 packages, and the install steps were repeated on AlmaLinux 8.
Add the EPEL and Remi repositories
Run this on a freshly provisioned Rocky Linux or AlmaLinux server when you can, rather than on a box already serving live traffic, so a dependency surprise never lands on production first. If you still need the server, our notes on installing Rocky Linux on a Hetzner root server get you there. CentOS Stream 8 is end of life and gets no updates at all, so put it on an EL9 or EL10 base before adding anything new to it.
Remi’s packages depend on libraries that only EPEL carries (libsodium, for one), and EPEL’s own instructions enable the CRB repository first (it is called PowerTools on EL8), because some EPEL packages need libraries from it. The config-manager subcommand comes from dnf-plugins-core, which a minimal install does not have, so install that too. Run the first line plus the one for your major version:
sudo dnf install -y dnf-plugins-core
## EL 9-based systems ##
sudo dnf config-manager --set-enabled crb
## EL 8-based systems ##
sudo dnf config-manager --set-enabled powertools
On our minimal Rocky Linux 9 server, config-manager failed with No such command: config-manager until dnf-plugins-core was installed, and then CRB showed up in the repolist. The PowerTools line is EPEL’s documented EL8 equivalent, which we did not run. With that done, install the EPEL release package.
sudo dnf -y install epel-release
Then install the Remi release package that matches your major version. Pick one line, not both:
## EL 9-based systems ##
sudo dnf install -y https://rpms.remirepo.net/enterprise/remi-release-9.rpm
## EL 8-based systems ##
sudo dnf install -y https://rpms.remirepo.net/enterprise/remi-release-8.rpm
Confirm both repositories are active before going further. A failed remi-release install leaves dnf unable to find php84 later, and the error then points at the wrong step.
sudo dnf repolist
On Rocky Linux 9 you should see epel, remi-modular and remi-safe next to the base repositories:
repo id repo name
appstream Rocky Linux 9 - AppStream
baseos Rocky Linux 9 - BaseOS
epel Extra Packages for Enterprise Linux 9 - x86_64
epel-cisco-openh264 Extra Packages for Enterprise Linux 9 openh264 (From Cisco) - x86_64
extras Rocky Linux 9 - Extras
remi-modular Remi's Modular repository for Enterprise Linux 9 - x86_64
remi-safe Safe Remi's RPM repository for Enterprise Linux 9 - x86_64
The remi-safe repository is the one that matters here, because it holds the php84 collection. Despite what older guides say, it is not a testing repository. It carries the stable Software Collections and is enabled by default, since its packages install side by side and never replace anything from the base OS. If it’s missing from your repolist, turn it on:
sudo dnf config-manager --set-enabled remi-safe
The same command enabled remi-safe cleanly on Rocky Linux 9 and AlmaLinux 8, although on both it was already on after the Remi release package went in.
Install PHP 8.4 on Rocky / AlmaLinux
Each PHP branch in remi-safe has its own metapackage named phpXY. List them to see which collections your server can install:
sudo dnf list --available "php8?"
Remi lists every collection from 8.0 to 8.6 on Rocky Linux 9, and AlmaLinux 8 showed the same list with el8 builds. Not all of them are good picks: php86 is a release candidate, and 8.0 and 8.1 are end of life upstream, so new work belongs on 8.4 or 8.5.
Available Packages
php80.x86_64 8.0-3.el9.remi remi-safe
php81.x86_64 8.1-4.el9.remi remi-safe
php82.x86_64 8.2-5.el9.remi remi-safe
php83.x86_64 8.3-1.el9.remi remi-safe
php84.x86_64 8.4-1.el9.remi remi-safe
php85.x86_64 8.5-1.el9.remi remi-safe
php86.x86_64 8.6-1.el9.remi remi-safe
Install the PHP 8.4 collection. The php84 metapackage pulls in the CLI, the common files and the runtime, and its weak dependencies add FPM and the usual extensions, so one package name gives you a working base.
sudo dnf install php84
dnf resolves the transaction and asks you to confirm it. The block below is trimmed to the PHP packages and the EPEL and SCL libraries they need on Rocky Linux 9; the full dependency list depends on what your server already has, and a minimal install pulls in more:
Installing:
php84 x86_64 8.4-1.el9.remi remi-safe 6.9 k
Installing dependencies:
libsodium x86_64 1.0.18-9.el9 epel 160 k
oniguruma5php x86_64 6.9.10-1.el9.remi remi-safe 222 k
php84-php-cli x86_64 8.4.27-1.el9.remi remi-safe 3.9 M
php84-php-common x86_64 8.4.27-1.el9.remi remi-safe 769 k
php84-runtime x86_64 8.4-1.el9.remi remi-safe 1.1 M
scl-utils x86_64 1:2.0.3-4.el9 appstream 36 k
Installing weak dependencies:
php84-php-fpm x86_64 8.4.27-1.el9.remi remi-safe 2.0 M
php84-php-mbstring x86_64 8.4.27-1.el9.remi remi-safe 535 k
php84-php-opcache x86_64 8.4.27-1.el9.remi remi-safe 515 k
php84-php-pdo x86_64 8.4.27-1.el9.remi remi-safe 95 k
php84-php-sodium x86_64 8.4.27-1.el9.remi remi-safe 41 k
php84-php-xml x86_64 8.4.27-1.el9.remi remi-safe 722 k
Answer y. On a first install dnf then asks to import the EPEL and Remi GPG keys (RPM-GPG-KEY-remi.el9 on EL9), and you have to accept those too, because a run that can’t import them stops with Refusing to automatically import keys when running unattended. Add -y to the install command if you’re scripting it.
Because this is a Software Collection, it stays separate from the base OS. Three paths are worth remembering:
- The installation lives under /opt/remi/php84
- Configuration files, including
php.iniand the FPM pools, sit in /etc/opt/remi/php84 - The FPM pool is configured to listen on /var/opt/remi/php84/run/php-fpm/www.sock
The collection does not add a plain php binary to your PATH, so call it as php84 when you check the version.
php84 --version
Rocky Linux 9 and AlmaLinux 8 both reported the same Remi build from 19 October, which is the patched release covered in the next section.
PHP 8.4.27 (cli) (built: Oct 19 2026 14:38:59) (NTS gcc x86_64)
Copyright (c) The PHP Group
Built by Remi's RPM repository <https://rpms.remirepo.net/> #StandWithUkraine #NoAI
Zend Engine v4.4.27, Copyright (c) Zend Technologies
with Zend OPcache v8.4.27, Copyright (c), by Zend Technologies
A command not found here means php84-php-cli never installed, so rerun the install and read the dnf error. A version below 8.4.27 means the server holds an older build, and the PHP2Shell section below shows how to fix that.
Enable PHP-FPM 8.4
The collection’s FPM service is what a web server talks to, and the package installs it disabled, so nothing serves PHP 8.4 over FastCGI until you start it. Enable it now so it also comes back after a reboot:
sudo systemctl enable --now php84-php-fpm
Then confirm the service is up:
systemctl is-active php84-php-fpm
It should answer with one word:
active
Anything else (inactive or failed) means the pool did not start, and sudo journalctl -u php84-php-fpm shows why. Skip this step only if you plan to run PHP through the collection’s Apache module instead of FPM.
Check PHP 8.4 for PHP2Shell (CVE-2026-109618, CVE-2026-109619)
PHP2Shell is the common name for a pair of critical remote code execution bugs in PHP itself, CVE-2026-109618 and CVE-2026-109619, both rated CVSS v4.0 9.2 in PHP’s 20 October pre-announcement. They were fixed upstream on 21 October 2026 in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 according to the PHP security advisory. Remi’s php84 collection already ships 8.4.27 for EL9 and EL8, so a server you build from this guide today is patched. One built before that runs 8.4.26 or older until you upgrade it.
PHP’s 21 October advisory told Remi users to switch to distro packages, because Remi had no update out that day. Remi shipped 8.4.27 on 22 October, so upgrading the collection is now enough. If you’d rather follow the advisory and move to distro PHP, the fixed AppStream options are the php:8.2 and php:8.3 module streams on Rocky Linux 9 (its php:8.1 stream was still unfixed on 22 October) and every PHP stream on AlmaLinux 9 and 8. None of them is PHP 8.4, so check your application first.
With Remi the package version is the check, because its changelog only says “Update to 8.4.27” and never names the CVE IDs, so grepping it for them prints nothing even on a fixed build. Ask rpm instead:
rpm -q php84-php-common
Anything at 8.4.27 or later is fixed. Our fresh Rocky Linux 9 install printed:
php84-php-common-8.4.27-1.el9.remi.x86_64
On a fresh install you can stop here. On an existing server that shows 8.4.26 or older, upgrade the whole collection in one transaction and then restart PHP-FPM, because the FPM master keeps serving the old code from memory until it restarts. try-restart restarts the service only if it is running, so it is safe on a box where FPM is stopped:
sudo dnf upgrade -y "php84*"
sudo systemctl try-restart php84-php-fpm
If the server runs PHP through the collection’s Apache module instead, restart httpd too. We did not test the Apache module path. On our FPM-only server the command just reported Unit httpd.service not found, which is harmless:
sudo systemctl try-restart httpd
For an in-place upgrade php84 --version only proves the CLI, so check when the FPM service last started instead:
systemctl show -p ActiveEnterTimestamp php84-php-fpm
The timestamp must not be earlier than the end of the upgrade. An older one means FPM is still the pre-upgrade process, so restart it again and recheck.
ActiveEnterTimestamp=Thu 2026-10-22 16:11:31 UTC
dnf history list only shows the upgrade time to the minute, which is too coarse for that comparison. List the transactions, then open the newest Upgrade row by its ID (7 on our server, so use your own) to get the end time in seconds:
sudo dnf history list php84-php-common
sudo dnf history info 7
The list shows the downgrade we used to fake an old server, then the upgrade. Running the upgrade again with nothing to update printed Nothing to do and added no row, so the newest Upgrade row is always a real one:
ID | Command line | Date and time | Action(s) | Altered
-------------------------------------------------------------------------------
7 | upgrade -y php84* | 2026-10-22 16:11 | Upgrade | 8
6 | downgrade -y php84-php* | 2026-10-22 16:11 | Downgrade | 8
5 | install -y php84 | 2026-10-22 16:10 | Install | 35 EE
The info output carries the exact times. FPM’s 16:11:31 start matches the end of the transaction, so the running FPM is the patched code:
Transaction ID : 7
Begin time : Thu Oct 22 16:11:30 2026
Begin rpmdb : 72bf32bfcec974470623bd3f75f9cd27135551b3e80e5cdcc4fad22e9a84d1bd
End time : Thu Oct 22 16:11:31 2026 (1 seconds)
A quicker cross-check is needs-restarting, which lists services still running deleted or replaced files. Empty output means nothing is left to restart:
sudo dnf needs-restarting -s
We rolled our Rocky Linux 9 server back to 8.4.26 and then started FPM on it to reproduce an unpatched box, which is the downgrade row above. The upgrade took a few seconds, and a PHP page served through the FPM socket answered 8.4.26 fpm-fcgi before it and 8.4.27 fpm-fcgi after the restart. The package restarted php84-php-fpm during the transaction in our test; restart anyway and confirm with the checks above. The other branches in remi-safe carry the fix too (8.5.12, 8.3.36, 8.2.35, plus backports for 8.1, 8.0 and 7.4), and if you are stuck on one of those older branches, our PHP2Shell notes for end-of-life PHP cover what else to check.
Install PHP 8.4 Extensions
Extensions for the collection are named php84-php-<extension>, and the repository carries more than 200 of them. List what is available.
sudo dnf list --available "php84-php-*"
As an example, install the mysqlnd and zip extensions. The zip name resolves to Remi’s php84-php-pecl-zip package, so either name works.
sudo dnf install php84-php-mysqlnd php84-php-zip
List the loaded modules to confirm both are active. The CLI and FPM read the same php.d directory under /etc/opt/remi/php84, so what loads here also loads in FPM once the service restarts.
php84 --modules
You should see mysqli, mysqlnd, pdo_mysql and zip in the list:
[PHP Modules]
bz2
calendar
Core
ctype
curl
date
dom
exif
fileinfo
filter
ftp
gettext
hash
iconv
json
libxml
mbstring
mysqli
mysqlnd
openssl
pcntl
pcre
PDO
pdo_mysql
pdo_sqlite
Phar
random
readline
Reflection
session
SimpleXML
sockets
sodium
SPL
sqlite3
standard
tokenizer
xml
xmlreader
xmlwriter
xsl
Zend OPcache
zip
zlib
[Zend Modules]
Zend OPcache
FPM reads new extensions only when it starts, so run sudo systemctl try-restart php84-php-fpm after adding one. Your Nginx or Apache FastCGI config then points at the /var/opt/remi/php84/run/php-fpm/www.sock socket, which we confirmed answers PHP 8.4 requests on Rocky Linux 9. If PHP 8.4 is the only PHP the server will ever run, Remi’s php:remi-8.4 module stream gives you a plain php command and standard paths on EL9 and EL8, the same route the Rocky Linux 10 guide linked above takes. For PHP 8.5, our PHP 8.5 guide for Rocky Linux 10 covers it. When you need several branches side by side, or the base OS PHP must stay put, the Remi collection is the one we’d run.