How to Install PHP and Composer on Fedora

Install PHP and Composer on Fedora by enabling the Remi repository and using dnf to install the necessary packages.

The scenario

You cloned a modern PHP project or pulled a WordPress theme, ran the dependency manager, and got a wall of red text about missing extensions. Or maybe you just need PHP 8.3 for a local development environment, but the default Fedora repository only offers 8.1. The system is holding you back with an older version, and forcing an upgrade manually will break your package manager. You need a clean, supported way to get the latest PHP stack without fighting dnf.

What is actually happening

Fedora ships with a conservative PHP version to guarantee stability across the entire desktop and server ecosystem. That version lives in the base repository and is tied to a dnf module stream. Modules let Fedora package multiple versions of the same software without dependency collisions. When you enable a different stream, dnf switches the entire PHP ecosystem to that version. The Remi repository is the community standard for newer PHP releases on RHEL-based systems. It mirrors Fedora's module structure but pushes updates faster. Composer is distributed as a self-contained PHAR archive, but Fedora packages it so you get automatic security patches through dnf. Installing both together means your language runtime and your dependency manager stay synchronized.

Fedora treats PHP as a modular platform rather than a single binary. The core interpreter lives in php-cli or php-fpm. Every extension like mbstring, pdo, or gd ships as a separate package. This design keeps the base installation lean. It also means you only install what your project actually requires. The module system tracks these dependencies and prevents you from mixing extensions compiled for PHP 8.1 with a PHP 8.3 runtime. Mixing them causes immediate segmentation faults.

The module system works by locking package versions to a specific stream. When you run dnf module enable php:remi-8.3, you are telling the package manager to ignore the base stream and resolve all php-* packages from Remi. The transaction replaces the old binaries, updates the configuration symlinks, and drops new .ini files into /etc/php.d/. The switch is atomic. Either the entire stream changes, or the transaction rolls back.

Run dnf module list php before you change anything. See which stream is currently enabled. Switching streams requires a clean transaction.

The installation procedure

Here is how to add the Remi repository and switch your system to the latest stable PHP stream. The Remi package provides the repository metadata and the GPG key for signature verification.

sudo dnf install -y https://rpms.remirepo.net/fedora/remi-release-$(rpm -E %fedora).rpm
# rpm -E %fedora expands to your current release number
# This prevents downloading the wrong repo config for a different Fedora version
# The package registers the remi-safe and remi-modular repositories

Next, you need to tell dnf to switch the PHP module stream. The default Fedora stream stays enabled until you explicitly override it. The remi-8.3 stream pulls the interpreter, the CLI, and all compatible extensions from Remi.

sudo dnf module enable -y php:remi-8.3
# This switches the module stream and marks the old stream as disabled
# dnf will now resolve all php-* packages from the Remi repository
# Module switches require a full transaction to complete

Now install the core interpreter and the extensions your project will need. Most modern frameworks require mbstring, xml, curl, pdo, and zip. The php-fpm package is only necessary if you are running a web server. php-cli is enough for terminal scripts and Composer.

sudo dnf install -y php php-cli php-fpm php-common php-devel php-mbstring php-xml php-curl php-gd php-json php-pdo php-pecl-apcu php-pecl-zip
# php-common provides the base configuration files in /etc/php.d/
# php-devel installs headers for compiling C extensions later
# php-pecl-apcu and php-pecl-zip are frequently required by frameworks
# dnf resolves dependencies and installs the matching 8.3 versions

Finally, install Composer. The Fedora package wraps the official PHAR archive and sets up the correct permissions and man pages. It also registers the composer command in your system path.

sudo dnf install -y composer
# This installs the Composer PHAR and a wrapper script in /usr/bin
# The wrapper handles PHP version detection automatically
# You can now run composer from any terminal without sudo

Convention aside: configuration files for PHP live in /etc/php.d/. The package manager owns /usr/lib/php/. Never edit files in /usr/lib/. Your changes will vanish on the next dnf upgrade. Drop custom .ini files in /etc/php.d/ and name them with a high number like 99-custom.ini to ensure they load last.

Commit the transaction and verify the package manager state. Run dnf upgrade --refresh weekly to keep the Remi metadata current.

Verify the setup

Here is how to confirm the interpreter and dependency manager are running the correct versions. The version output must match the stream you enabled.

php -v
# Shows the PHP version, build date, and copyright notice
# Look for PHP 8.3.x in the first line
# If it shows 8.1 or 8.2, the module switch did not apply
composer -V
# Prints the Composer version and PHP runtime it is bound to
# The output should reference the same PHP version as the previous command
# Composer will refuse to run if the PHP version is below its minimum requirement

Check that the extensions actually loaded. A missing extension will cause your application to crash on startup, even if the package is installed.

php -m | grep -E "mbstring|pdo|curl|xml|zip"
# Lists all loaded extensions and filters for the critical ones
# Each line confirms the extension is compiled and active
# Missing lines mean the package failed to install or the ini file is disabled

Run php -i | grep "Loaded Configuration" to see exactly which .ini files the interpreter read. Cross-reference that list with /etc/php.d/. If your custom settings are not applying, the file name might be sorting before the base configuration.

Common pitfalls and error messages

Module conflicts are the most frequent issue. If you previously installed PHP packages from the default stream, dnf will refuse to switch streams until you remove the conflicting packages. The package manager protects you from breaking the runtime.

Error: Module php:8.1 conflicts with php:remi-8.3

Resolve this by running sudo dnf module reset php first. The reset command clears the stream lock and lets you enable the new one cleanly.

Composer will complain if your PHP installation lacks the zip or openssl extensions. You will see a warning during installation or when running composer install.

Your lock file does not contain a compatible set of packages. Please run composer update.

This message usually means a dependency requires a newer PHP version or a missing extension. Run composer diagnose to get a structured report of your environment. Fix the missing extension before forcing an update.

SELinux denials appear when you run a web server and the PHP process tries to write to a directory it does not own. You will see Permission denied in your web server logs and avc: denied in the journal.

sudo ausearch -m avc -ts recent | grep php
# Shows recent SELinux denials related to PHP
# The output includes the source process and the target file context
# Use restorecon -Rv /path/to/webroot to fix incorrect contexts

Never disable SELinux to fix a permission error. Adjust the file context or run setsebool -P httpd_execmem 1 if your application requires memory execution. Read the denial message first. The journal tells you exactly what is blocked.

PHP-FPM pool misconfigurations cause silent failures. The default pool lives in /etc/php-fpm.d/www.conf. If you change the user or group directives without updating the web server configuration, the socket permissions will reject connections. Check /var/log/php-fpm/www-error.log for startup failures. Restart the service with sudo systemctl restart php-fpm after every config change. Always verify the socket path matches your web server block.

When to use this approach

Use the Remi repository when you need a PHP version newer than the base Fedora release provides. Use the default Fedora PHP stream when you are running a production server that requires long-term stability over bleeding-edge features. Use dnf install composer when you want automatic security updates and system-wide availability. Use the official Composer PHAR when you need to run multiple isolated Composer versions per project. Use php-fpm when you are serving traffic through nginx or Apache. Use php-cli when you are running cron jobs, CLI tools, or local development scripts. Stay on the remi-8.3 stream until your project explicitly requires 8.4 or 8.5.

Where to go next