How to Install PHP on CentOS Stream 10 and 9

Install PHP on CentOS Stream 10 and 9 using AppStream repos. Configure for Apache or Nginx with PHP-FPM and common extensions.

Last updatedAuthorJoshua JamesRead time6 minGuide typeCentOS Stream

Most CentOS Stream web stacks start with AppStream PHP packages because DNF keeps the runtime, extensions, and security updates tied to the system package set. You can install PHP on CentOS Stream 10 as PHP 8.3 directly, while CentOS Stream 9 uses module streams for PHP 8.1, 8.2, and 8.3.

Use the Apache path when HTTPD will serve PHP through the packaged PHP-FPM handler, or choose the Nginx PHP-FPM path when Nginx will pass requests to a FastCGI socket. The same package workflow covers CLI checks, common extensions, PHP-FPM service setup, updates, removal, and AppStream troubleshooting.

CentOS Stream 10 and CentOS Stream 9 are the supported releases here. Commands are separated only where package behavior differs between the two releases.

Install PHP on CentOS Stream

Start by matching your CentOS Stream release to the PHP branch and web-server integration you plan to use.

Choose a PHP Version on CentOS Stream

CentOS Stream ReleasePackage SourcePHP BranchesWhat To Do
CentOS Stream 10AppStream packagesPHP 8.3Install PHP packages directly with DNF.
CentOS Stream 9AppStream module streamsPHP 8.1, 8.2, and 8.3Enable one PHP module stream before installing packages.

PHP 8.3 is the best AppStream choice for new deployments unless an application requires PHP 8.2 or 8.1. For newer branches outside AppStream, keep that workflow separate and use the dedicated guide to install Remi RPM repository on CentOS Stream.

Update CentOS Stream Before Installing PHP

Refresh package metadata and apply pending system updates before adding PHP packages:

sudo dnf upgrade --refresh

Commands that start with sudo require an account with administrator privileges. If your user cannot run sudo, switch to a properly privileged account before continuing.

Install PHP 8.3 on CentOS Stream 10

CentOS Stream 10 provides PHP 8.3 as normal AppStream packages, so module commands are not needed.

Install PHP for Apache on CentOS Stream 10

Use the Apache package path when your site runs through HTTPD. The php package is a small AppStream metapackage that pulls PHP-FPM and the Apache PHP handler configuration, and it may also pull httpd if Apache is not already present. For the full web-server setup, use the separate guide to install Apache HTTPD on CentOS Stream.

sudo dnf install php php-cli

Test Apache’s configuration, start PHP-FPM, then restart HTTPD so Apache can pass PHP files to the default PHP-FPM socket:

sudo apachectl configtest
sudo systemctl enable --now php-fpm
sudo systemctl restart httpd

Install PHP-FPM for Nginx on CentOS Stream 10

Use PHP-FPM for Nginx. This installs the FastCGI service and the PHP command-line binary without installing the Apache PHP package:

sudo dnf install php-fpm php-cli

Install PHP on CentOS Stream 9 with AppStream Modules

CentOS Stream 9 exposes supported PHP branches through DNF module streams. Enable exactly one stream, then install the package set that matches your web server.

List PHP Module Streams on CentOS Stream 9

Check the current AppStream PHP branches before choosing one:

dnf module list php

Relevant output includes:

CentOS Stream 9 - AppStream
Name Stream Profiles                   Summary
php  8.1    common [d], devel, minimal PHP scripting language
php  8.2    common [d], devel, minimal PHP scripting language
php  8.3    common, devel, minimal     PHP scripting language

Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled

Enable a PHP Stream on CentOS Stream 9

For new deployments, enable PHP 8.3:

sudo dnf module enable php:8.3

For applications that still require PHP 8.2, enable that stream instead and skip the PHP 8.3 command:

sudo dnf module enable php:8.2

PHP 8.1 remains available for compatibility workloads with sudo dnf module enable php:8.1. Run only one module-enable command before installing packages.

Verify the enabled stream when you are unsure which branch DNF will use:

dnf module list php --enabled

For PHP 8.3, relevant output includes:

CentOS Stream 9 - AppStream
Name Stream  Profiles               Summary
php  8.3 [e] common, devel, minimal PHP scripting language

Install PHP for Apache on CentOS Stream 9

After enabling the stream, install the Apache-oriented PHP package set and CLI component:

sudo dnf install php php-cli

Test Apache’s configuration, start PHP-FPM, then restart HTTPD so Apache can use the PHP handler configuration installed with the package set:

sudo apachectl configtest
sudo systemctl enable --now php-fpm
sudo systemctl restart httpd

Install PHP-FPM for Nginx on CentOS Stream 9

For Nginx, install PHP-FPM and the CLI component from the enabled stream:

sudo dnf install php-fpm php-cli

Verify PHP on CentOS Stream

Check the active PHP branch after installation:

php -r 'echo PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION . PHP_EOL;'

A PHP 8.3 install returns:

8.3

Use php -v when you need the full patch version and build details.

Install Common PHP Extensions on CentOS Stream

Most CMS and framework deployments need database, XML, image, internationalization, cache, and archive extensions in addition to the base runtime. Install the common AppStream extension set with DNF:

sudo dnf install php-mysqlnd php-gd php-opcache php-intl php-bcmath php-xml php-mbstring php-pdo php-pecl-apcu php-pecl-zip

The package names track your selected source. On CentOS Stream 9, DNF installs these extensions from the enabled PHP module stream.

  • php-mysqlnd: MySQL native driver support for database connections.
  • php-gd: Image manipulation support for applications that generate thumbnails or process uploads.
  • php-opcache: Bytecode caching for faster repeated PHP execution.
  • php-intl: Locale, collation, and internationalization functions.
  • php-bcmath: Arbitrary precision math used by some commerce and accounting applications.
  • php-xml: XML parsing and DOM support.
  • php-mbstring: Multi-byte string handling for UTF-8-heavy applications.
  • php-pdo: Database abstraction support used by many frameworks.
  • php-pecl-apcu: User cache support for storing application data in memory.
  • php-pecl-zip: ZIP archive handling for uploads, backups, and import/export workflows.

Verify the installed modules with a focused module check:

php -m | grep -E '^(apcu|bcmath|gd|intl|mbstring|mysqli|mysqlnd|PDO|pdo_mysql|xml|Zend OPcache|zip)$' | LC_ALL=C sort -u

Relevant output includes:

PDO
Zend OPcache
apcu
bcmath
gd
intl
mbstring
mysqli
mysqlnd
pdo_mysql
xml
zip

Install PHP Development Tools

Development servers that build extensions or use step debugging can add the development headers and Xdebug package:

sudo dnf install php-devel php-pecl-xdebug3

The development package pulls compiler and header dependencies. Keep it off production servers unless the application or deployment workflow needs those build tools.

Configure PHP-FPM for Nginx on CentOS Stream

Skip this Nginx pool-ownership section when you installed PHP for Apache. Apache also uses PHP-FPM with current AppStream packages, but its default handler expects the packaged apache pool settings. Nginx needs the pool user and socket ownership changed to nginx.

Confirm that the Nginx system user exists before changing PHP-FPM ownership:

id nginx

The command should return an nginx UID and group. If it reports id: 'nginx': no such user on a new Nginx server, sudo dnf install nginx creates the package-owned user on current CentOS Stream releases. Finish the Nginx server setup before editing the PHP-FPM pool.

Set PHP-FPM Pool Ownership for Nginx

Back up the default pool file, then set the worker user, group, and socket ownership to nginx:

sudo cp -a /etc/php-fpm.d/www.conf /etc/php-fpm.d/www.conf.bak
sudo sed -i -E 's/^user = .*/user = nginx/; s/^group = .*/group = nginx/' /etc/php-fpm.d/www.conf
sudo sed -i -E 's/^;?listen\.owner = .*/listen.owner = nginx/; s/^;?listen\.group = .*/listen.group = nginx/' /etc/php-fpm.d/www.conf

Verify the edited lines:

grep -E '^(user|group|listen\.owner|listen\.group) =' /etc/php-fpm.d/www.conf

Expected output:

user = nginx
group = nginx
listen.owner = nginx
listen.group = nginx

Test the PHP-FPM configuration before starting the service:

sudo php-fpm -tt 2>&1 | grep -o 'configuration file /etc/php-fpm.conf test is successful'

A valid configuration returns:

configuration file /etc/php-fpm.conf test is successful

Start and Verify PHP-FPM

Start PHP-FPM and enable it for future boots:

sudo systemctl enable --now php-fpm

Check the running and enabled state:

systemctl is-active php-fpm
systemctl is-enabled php-fpm

Expected output:

active
enabled

Add PHP Handling to an Nginx Server Block

Add this location block inside the Nginx server block that serves your PHP site:

location ~ \.php$ {
    try_files $uri =404;
    fastcgi_pass unix:/run/php-fpm/www.sock;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
}

Test the Nginx configuration after saving the server block:

sudo nginx -t

Expected output:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Reload Nginx only after the syntax test passes:

sudo systemctl reload nginx

Update PHP on CentOS Stream

PHP packages update through normal DNF transactions. To refresh metadata and update installed PHP packages only, use a quoted package glob so the shell does not expand it against local filenames:

sudo dnf upgrade --refresh 'php*'

On CentOS Stream 9, DNF stays on the enabled module stream. Switching from one PHP branch to another is a stream-change operation, not a normal update.

Troubleshoot PHP on CentOS Stream

PHP Module Stream Conflicts on CentOS Stream 9

If CentOS Stream 9 already has one PHP stream enabled, DNF can refuse a different stream until you reset the module state.

Check the enabled stream first:

dnf module list php --enabled

Reset the module, enable the target stream, then synchronize installed PHP packages to that branch:

sudo dnf module reset php
sudo dnf module enable php:8.3
sudo dnf distro-sync 'php*'

Replace php:8.3 with php:8.2 or php:8.1 only when your application requires that branch.

PHP-FPM Fails After Nginx Ownership Changes

If PHP-FPM fails to start after changing the pool user to nginx, confirm the Nginx user exists:

id nginx

A missing user looks like this:

id: 'nginx': no such user

Install or restore Nginx before using nginx as the PHP-FPM pool owner. If you need to revert the pool file, restore the backup created earlier and restart PHP-FPM:

sudo cp -a /etc/php-fpm.d/www.conf.bak /etc/php-fpm.d/www.conf
sudo systemctl restart php-fpm

Check the service again:

systemctl is-active php-fpm

A running service returns:

active

PHP Extension Package Is Missing

If an application names a missing extension, search for the matching package name:

dnf list 'php-*extension-name*'

Replace extension-name with the extension family, such as imagick or redis. Some less common packages may require EPEL, so use the separate guide to enable EPEL on CentOS Stream only when AppStream does not provide the extension.

Remove PHP from CentOS Stream

Remove PHP packages only after you have backed up application configuration, pool files, and any site-specific PHP settings you need to keep.

The quoted 'php*' pattern removes installed PHP packages and extensions. Review DNF’s transaction summary before confirming, especially on shared servers where multiple applications may depend on PHP.

If you used PHP-FPM, stop and disable the service first:

sudo systemctl disable --now php-fpm

Remove the PHP packages:

sudo dnf remove 'php*'

On CentOS Stream 9, reset the PHP module stream after removing the packages:

sudo dnf module reset php

Review optional dependency cleanup separately:

sudo dnf autoremove

Verify that the main PHP packages and command are gone:

rpm -q php php-cli php-fpm || true
hash -r
command -v php || echo "php command not found"

Expected output:

package php is not installed
package php-cli is not installed
package php-fpm is not installed
php command not found

This removes PHP, not Apache, Nginx, EPEL, or Remi. Remove those components separately only when no other application on the server uses them.

Conclusion

PHP is installed from CentOS Stream AppStream, with the active branch verified through the CLI and common extensions available through DNF. Apache deployments can use the php package path, while Nginx stacks can hand requests to PHP-FPM over /run/php-fpm/www.sock. For newer PHP branches outside AppStream, use the separate guide to install Remi RPM repository on CentOS Stream.

Share this guide

Help another Linux user troubleshoot faster

Share this guide with someone troubleshooting Linux systems or saving it for later.

Follow LinuxCapable

Want more LinuxCapable guides in Google?

Add LinuxCapable as a preferred source so Google can show more of our fresh Linux tutorials in Top Stories and From your sources when relevant.

Add LinuxCapable as a preferred source on Google
Search LinuxCapable

Need another guide?

Search LinuxCapable for package installs, commands, troubleshooting, and follow-up guides related to what you just read.

Found this guide useful?

Support LinuxCapable to keep tutorials free and up to date.

Buy me a coffeeBuy me a coffee
Before commenting, please review our Comments Policy.
Formatting tips for your comment

You can use basic HTML to format your comment. Useful tags currently allowed in published comments:

You type Result
<code>command</code> command
<strong>bold</strong> bold
<em>italic</em> italic
<a href="https://example.com">link</a> link
<blockquote>quote</blockquote> quote block

Got a Question or Feedback?

We read and reply to every comment - let us know how we can help or improve this guide.

Verify before posting: