One dnf install gives you PHP 8.5 on Fedora 45 and Fedora 44. That part is easy. The work starts after it, with PHP-FPM, with SELinux once the site leaves /var/www, and with an app that isn’t ready for 8.5 and still wants 8.4 or 8.3.
We install PHP with the extensions most frameworks need and wire PHP-FPM to nginx. Then we fix the 403 a custom document root triggers, move the common php.ini limits into a drop-in and add Composer.
Older versions get both Remi methods. One runs PHP 8.4 next to the system 8.5. The other switches the system PHP through a module stream, and dnf5 makes that switch look like it did nothing. Everything here ran in October 2026 on Fedora 45 and Fedora 44 with SELinux enforcing.
PHP versions on Fedora 45 and 44
Both releases ship a single PHP, with no versioned packages in the Fedora repositories. Older branches come from the Remi repository, maintained by the same person who packages PHP for Fedora. Support dates follow the PHP supported versions page.
| PHP branch | Fedora 45 | Fedora 44 | Security support ends |
|---|---|---|---|
| 8.5 | Default (php) | Default (php) | 31 December 2029 |
| 8.4 | Remi | Remi | 31 December 2028 |
| 8.3 | Remi | Remi | 31 December 2027 |
Check what the Fedora repositories hold on your machine.
dnf list --available php php-cli php-fpm 'php8*'
Fedora 45 lists 8.5.11 and finds nothing for php8*:
Available packages
php.x86_64 8.5.11-2.fc45 fedora
php-cli.x86_64 8.5.11-2.fc45 fedora
php-fpm.x86_64 8.5.11-2.fc45 fedora
Repositories loaded.
No matches found for "php8*".
Fedora 44 returned the same 8.5.11 release (build 8.5.11-1.fc44) from updates, so everything below applies to both releases unchanged.
Install PHP and common extensions
Skip the php metapackage. It recommends httpd, so a default install drags Apache onto an nginx host.
Install the CLI, FPM and the extensions instead. This set covers what WordPress and Laravel ask for.
sudo dnf install -y php-cli php-fpm php-mysqlnd php-pgsql php-gd php-intl php-mbstring php-xml php-bcmath php-sodium php-pecl-zip php-pecl-apcu
Two names trip people up. The zip extension is php-pecl-zip. OPcache has no package of its own, since in PHP 8.5 it ships inside php-common, which obsoletes the old php-opcache.
Here are the requested packages, before 28 dependencies.
Installing:
php-bcmath x86_64 0:8.5.11-2.fc45 fedora 98.5 KiB
php-cli x86_64 0:8.5.11-2.fc45 fedora 25.8 MiB
php-fpm x86_64 0:8.5.11-2.fc45 fedora 12.9 MiB
php-gd x86_64 0:8.5.11-2.fc45 fedora 133.7 KiB
php-intl x86_64 0:8.5.11-2.fc45 fedora 614.6 KiB
php-mbstring x86_64 0:8.5.11-2.fc45 fedora 1.2 MiB
php-mysqlnd x86_64 0:8.5.11-2.fc45 fedora 397.8 KiB
php-pecl-apcu x86_64 0:5.1.28-4.fc45 fedora 123.1 KiB
php-pecl-zip x86_64 0:1.22.8-4.fc45 fedora 127.3 KiB
php-pgsql x86_64 0:8.5.11-2.fc45 fedora 242.2 KiB
php-sodium x86_64 0:8.5.11-2.fc45 fedora 113.5 KiB
php-xml x86_64 0:8.5.11-2.fc45 fedora 690.6 KiB
Confirm the version and that OPcache loaded.
php -v
Its last line names the Zend OPcache build.
PHP 8.5.11 (cli) (built: Sep 22 2026 13:32:06) (NTS gcc x86_64)
Copyright (c) The PHP Group
Built by Fedora Project
Zend Engine v4.5.11, Copyright (c) Zend Technologies
with Zend OPcache v8.5.11, Copyright (c), by Zend Technologies
php -m prints 57 lines with this set, section headers included. Each extension has its own file under /etc/php.d, numbered so OPcache loads first.
Run PHP-FPM behind nginx
Start the FastCGI process manager and enable it at boot.
sudo systemctl enable --now php-fpm
Fedora ships a default www pool that listens on a Unix socket and runs as apache, even on a host with no Apache installed. Its socket ACL already admits both web servers.
sudo grep -Ev '^;|^$' /etc/php-fpm.d/www.conf | head -11
Pool identity, socket and process limits come first.
[www]
user = apache
group = apache
listen = /run/php-fpm/www.sock
listen.acl_users = apache,nginx
listen.allowed_clients = 127.0.0.1
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
Install nginx next. Its Fedora package ships an upstream for that socket in /etc/nginx/conf.d/php-fpm.conf and a PHP location block in /etc/nginx/default.d/php.conf. The default server runs PHP with no edits.
sudo dnf install -y nginx
echo '<?php echo "PHP " . PHP_VERSION . " via " . php_sapi_name() . PHP_EOL;' | sudo tee /usr/share/nginx/html/info.php
sudo systemctl enable --now nginx
curl -s http://localhost/info.php
It answers from the FPM SAPI, not the CLI.

Delete the test file once it works with sudo rm /usr/share/nginx/html/info.php.
Apache users get the same result without extra work, because httpd on Fedora proxies .php files to this socket through /etc/httpd/conf.d/php.conf. The LAMP stack on Fedora guide takes that route.
Fix 403 Forbidden for a site in /srv/www
Real sites rarely live in /usr/share/nginx/html. A server block for an application in /srv/www/app reuses the packaged PHP handling through the default.d include. Include both listen lines: without listen [::]:80, requests over IPv6, localhost among them, fall through to the default server and return its test page:
sudo mkdir -p /srv/www/app
echo '<?php echo "app ok on PHP " . PHP_VERSION . PHP_EOL;' | sudo tee /srv/www/app/index.php
printf 'server {\n listen 80;\n listen [::]:80;\n server_name app.example.com;\n root /srv/www/app;\n include /etc/nginx/default.d/*.conf;\n}\n' | sudo tee /etc/nginx/conf.d/app.conf
sudo nginx -t
sudo systemctl reload nginx
There is no DNS for app.example.com yet, so send the Host header yourself. The config test passes and the file permissions are fine, yet the site returns 403. Check the error log and the label.
curl -s -o /dev/null -w '%{http_code}\n' -H 'Host: app.example.com' http://localhost/
sudo grep -v notice /var/log/nginx/error.log | tail -n 1
ls -Zd /srv/www/app
matchpathcon /srv/www/app
Our directory carries var_t, while the policy expects httpd_sys_content_t. mkdir gave it the label of its parent, and nothing applied the policy.
Don’t wait for an AVC denial in the audit log. This access is silenced by a dontaudit rule, so ls -Z is the check to run. Fedora policy already maps /srv/www for web content, and a relabel is all it takes.
sudo restorecon -Rv /srv/www
Each relabeled file is listed, and the same request now reaches PHP.

A document root the policy doesn’t know, such as /opt/app, needs a persistent rule first. Install policycoreutils-python-utils, run sudo semanage fcontext -a -t httpd_sys_content_t '/opt/app(/.*)?', then restorecon.
Directories the app writes to, such as uploads or cache, need httpd_sys_rw_content_t instead. Never answer a 403 like this with setenforce 0.
Raise upload and memory limits
The stock limits are too small for most CMS installs. Print the current values from the CLI:
php -r 'foreach (["memory_limit","upload_max_filesize","post_max_size","max_execution_time","date.timezone","expose_php"] as $k) echo $k, " = ", var_export(ini_get($k), true), PHP_EOL;'
Those are the stock values on Fedora 45. max_execution_time reads 0 only because the CLI never times out. PHP-FPM uses 30 seconds from php.ini.
memory_limit = '128M'
upload_max_filesize = '2M'
post_max_size = '8M'
max_execution_time = '0'
date.timezone = 'UTC'
expose_php = '1'
Leave /etc/php.ini alone. It’s a protected config file, so an update that changes it drops a php.ini.rpmnew beside yours to merge by hand. Put overrides in a drop-in that sorts last, so it wins.
printf 'memory_limit = 256M\nupload_max_filesize = 64M\npost_max_size = 64M\nmax_execution_time = 60\ndate.timezone = UTC\nexpose_php = Off\n' | sudo tee /etc/php.d/99-custom.ini
sudo systemctl reload php-fpm
Check the values the FPM pool sees, not just the CLI. Drop a one-line script into the site root and request it:
echo '<?php foreach (["memory_limit","upload_max_filesize","post_max_size","date.timezone"] as $k) echo $k, " = ", ini_get($k), PHP_EOL;' | sudo tee /srv/www/app/ini.php >/dev/null
curl -s -H 'Host: app.example.com' http://localhost/ini.php
Our pool picked up the drop-in.
memory_limit = 256M
upload_max_filesize = 64M
post_max_size = 64M
date.timezone = UTC
Keep post_max_size at least as large as upload_max_filesize, or large uploads fail with an empty $_POST. With expose_php = Off, responses no longer carry an X-Powered-By header.
Remove the script afterwards with sudo rm /srv/www/app/ini.php. Pool settings such as pm.max_children stay in /etc/php-fpm.d/www.conf.
Install Composer
Fedora packages Composer, so it updates with the rest of the system. That beats a composer.phar copied into /usr/local/bin and forgotten.
sudo dnf install -y composer
composer --version
It picks up the system PHP.
Composer version 2.10.3 2026-08-27 13:34:23
PHP version 8.5.11 (/usr/bin/php)
Run the "diagnose" command to get more detailed diagnostics output.
A quick composer require monolog/monolog in an empty directory confirms that Packagist downloads and autoloading work. Run Composer as your own user, never with sudo.
Run PHP 8.4 or 8.3 next to 8.5 with Remi
For one legacy app, keep the system PHP at 8.5 and add a parallel branch. Remi builds each branch under its own prefix with its own FPM service. Add the repository first. The release package matches your Fedora version.
sudo dnf install -y https://rpms.remirepo.net/fedora/remi-release-$(rpm -E %fedora).rpm
The parallel packages carry the branch in their names (php84-php-*, php83-php-*). Install the 8.4 CLI, FPM and the extensions the application needs:
sudo dnf install -y php84-php-cli php84-php-fpm php84-php-mysqlnd php84-php-mbstring php84-php-intl php84-php-xml
sudo systemctl enable --now php84-php-fpm
Both versions now coexist. php84 runs the 8.4 CLI, and php is still 8.5:
php84 -v
php -v | head -1
8.4 answers first, then the untouched system PHP.
PHP 8.4.26 (cli) (built: Sep 22 2026 15:00:02) (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.26, Copyright (c) Zend Technologies
PHP 8.5.11 (cli) (built: Sep 22 2026 13:32:06) (NTS gcc x86_64)
Give the legacy site its own server block that passes PHP to the 8.4 socket, /var/opt/remi/php84/run/php-fpm/www.sock:
sudo mkdir -p /srv/www/legacy
echo '<?php echo "legacy on PHP " . PHP_VERSION . PHP_EOL;' | sudo tee /srv/www/legacy/index.php
sudo restorecon -R /srv/www/legacy
printf 'server {\n listen 80;\n listen [::]:80;\n server_name legacy.example.com;\n root /srv/www/legacy;\n index index.php;\n location ~ \\.php$ {\n include fastcgi_params;\n fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;\n fastcgi_pass unix:/var/opt/remi/php84/run/php-fpm/www.sock;\n }\n}\n' | sudo tee /etc/nginx/conf.d/legacy.conf
sudo nginx -t && sudo systemctl reload nginx
curl -s -o /dev/null -w '%{http_code}\n' -H 'Host: legacy.example.com' http://localhost/
That returns 502. Unlike the Fedora pool, the Remi pool only grants the socket to apache, and the same grep on the nginx error log shows the refusal.
2026/10/13 12:14:25 [crit] 12564#12564: *14 connect() to unix:/var/opt/remi/php84/run/php-fpm/www.sock failed (13: Permission denied) while connecting to upstream, client: ::1, server: legacy.example.com, request: "GET / HTTP/1.1", upstream: "fastcgi://unix:/var/opt/remi/php84/run/php-fpm/www.sock:", host: "legacy.example.com"
Add nginx to listen.acl_users in the 8.4 pool and restart it:
sudo sed -i 's/^listen.acl_users = apache$/listen.acl_users = apache,nginx/' /etc/opt/remi/php84/php-fpm.d/www.conf
sudo systemctl restart php84-php-fpm
Each site now gets the PHP it was built for:

PHP 8.4 keeps its configuration under /etc/opt/remi/php84, with extension files in php.d there. Copy your 99-custom.ini into it too. PHP 8.3 works the same way with php83 in every name and path.
Switch the system PHP to 8.4 with a Remi module
When the whole server should run 8.4, replace the system PHP instead. Paths, service names and /etc/php.ini stay exactly as above. Remi ships module streams for every branch, and dnf5 can still enable them.
We ran this on Fedora 44 with the full extension set from the install section plus Composer already in place, 15 PHP packages in all.
sudo dnf module reset -y php
sudo dnf module enable -y php:remi-8.4
The obvious next step is sudo dnf distro-sync -y 'php*'. With dnf5 it prints a dependency problem, skips the 8.4 packages and ends with “Nothing to do”, and PHP stays on 8.5 even though the stream is enabled:

Run distro-sync without a package pattern. On an otherwise current system, only the PHP packages change, plus one PostgreSQL client library the 8.4 php-pgsql build pulls in:
sudo dnf distro-sync -y
Every installed PHP package, PECL extensions included, is swapped for its 8.4 build from remi-modular.
Transaction Summary:
Installing: 1 package
Upgrading: 1 package
Replacing: 15 packages
Downgrading: 14 packages
Now the CLI reports the Remi build.
PHP 8.4.26 (cli) (built: Sep 22 2026 15:00:02) (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.26, Copyright (c) Zend Technologies
OPcache is missing from that output. On 8.4 it is a separate package, so install it and restart PHP-FPM:
sudo dnf install -y php-opcache
sudo systemctl restart php-fpm
Afterwards, php -v ends with with Zend OPcache v8.4.26, and composer --version reports PHP 8.4.26. The enabled stream keeps future updates on 8.4.
To go back to the Fedora 8.5 build, run sudo dnf module reset -y php followed by the same plain sudo dnf distro-sync -y. On our full set that brought all 15 packages back to the Fedora builds, and Composer followed.
Database drivers for MariaDB and PostgreSQL are already in the extension set above, and phpMyAdmin on Fedora runs on this stack unchanged. On a Fedora 44 host, check the Remi release package for your new version before you upgrade to Fedora 45.
Why use remi repo? Is it need to pay??
Remi is free to use.
hey little update all your line in terminal not working in fedora 42