Dev

Install PHP on Garuda, Arch and Manjaro with Apache or Nginx

Arch Linux’s official repositories no longer carry PHP 8.4. The php package in extra now tracks the 8.5 branch, php-legacy tracks 8.3, and 8.4 survives only as the php84 package in the AUR, which still sat on an unpatched build on 22 October 2026. So on Garuda, Arch or Manjaro, sudo pacman -S php installs PHP 8.5, and that’s the build you want this week because it carries the PHP2Shell fix.

Original content from computingforgeeks.com - post 161420

This guide installs PHP from the official repositories, enables the extensions most apps need, and serves PHP through Apache with mod_php or through Nginx with PHP-FPM. It also shows how to prove a running server is patched, because on Arch the upgrade alone does not swap the PHP your web server is running. Every command below was run on Arch Linux with PHP 8.5.12 in October 2026, including the upgrade and restart of a live PHP-FPM and Apache.

Check which PHP branch your repositories ship

Ask pacman what the sync repositories hold, because Manjaro and Garuda do not always carry the same build as Arch on the same day. pacman -Si reads the package databases from your last sync, so run it after the sudo pacman -Syu in the next section (never a bare pacman -Sy, which sets up a partial upgrade). The query itself changes nothing on the system:

pacman -Si php php-legacy | grep -E '^(Repository|Name|Version|Build Date)'

On Arch both packages come from extra, and both were rebuilt on 21 October:

Repository      : extra
Name            : php
Version         : 8.5.12-1
Build Date      : Wed Oct 21 13:42:26 2026
Repository      : extra
Name            : php-legacy
Version         : 8.3.36-1
Build Date      : Wed Oct 21 13:48:52 2026

That leaves three ways to get PHP on an Arch-based system, and only two of them were patched on 22 October 2026:

  • php from extra: 8.5.12-1, patched
  • php-legacy from extra: 8.3.36-1, patched
  • php84 from the AUR: 8.4.24-2, not patched

Pick php unless an application pins you to an older branch. Manjaro’s stable branch already had its own 8.5.12-0.1 build the same day, but Manjaro holds packages back from Arch for days to weeks, so run the same pacman -Si php check there before you trust a version. We did not test Garuda separately, and the same command tells you what its mirrors serve. If a php84 from Chaotic-AUR is installed there, the AUR warning below applies to it too.

Update the system

Arch does not support partial upgrades, so sync and upgrade the whole system before you add PHP. Installing a new package against a stale system is how you end up with a binary linked to libraries the rest of the box does not have yet. The pacman cheat sheet covers the flags if you need more than this one:

sudo pacman -Syu

Reboot afterwards if the upgrade pulled in a new kernel, then carry on.

Install PHP on Garuda, Arch and Manjaro

The php package holds the CLI and the core extensions. The web server modules (php-fpm, php-apache) are separate packages that come in the next step:

sudo pacman -S php

pacman resolves three small libraries alongside it and asks for confirmation:

Package (4)      New Version  Net Change  Download Size

extra/argon2     20190702-7     0.11 MiB       0.03 MiB
extra/libzip     1.11.4-1       0.47 MiB       0.25 MiB
extra/oniguruma  6.9.10-3       0.87 MiB       0.22 MiB
extra/php        8.5.12-1      39.20 MiB       5.69 MiB

Total Download Size:    6.19 MiB
Total Installed Size:  40.65 MiB

:: Proceed with installation? [Y/n]

Confirm the version the CLI reports.

php -v

The build date of 21 October matches the PHP2Shell release, and OPcache is compiled in, so there is no separate package to add for it:

PHP 8.5.12 (cli) (built: Oct 21 2026 13:42:26) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.5.12, Copyright (c) Zend Technologies
    with Zend OPcache v8.5.12, Copyright (c), by Zend Technologies

The patch release will be higher if you install later. Arch moves php to the next branch when upstream does, so expect the minor version to change on a future pacman -Syu as well.

Check for PHP2Shell (CVE-2026-109618, CVE-2026-109619)

PHP2Shell is two critical remote code execution bugs in PHP itself, CVE-2026-109618 and CVE-2026-109619, which PHP rated CVSS v4.0 9.2 in its 20 October pre-announcement and fixed upstream on 21 October 2026 in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 (see the PHP security advisory). Arch’s php 8.5.12-1 and php-legacy 8.3.36-1 already carry the fix. Arch ships the upstream release rather than backporting patches into an old version number, so here the package version is the check: you need upstream 8.5.12 (or 8.3.36 for php-legacy) or later, at any package release. Manjaro’s own builds end in -0.x, so its patched 8.5.12-0.1 is fine even though it sorts below Arch’s 8.5.12-1.

pacman -Q php

A fresh install prints the patched build.

php 8.5.12-1

If yours reads 8.5.12 or later and nothing else runs PHP yet, you’re done here and can skip to the extensions. The rest of this section is for a server that already runs PHP-FPM or Apache. Check the SAPI packages there too, since they are what serves web requests. We set our test server back to the previous release to show the upgrade:

pacman -Q php php-fpm php-apache

All three report 8.5.11-1, one release short of the fix:

php 8.5.11-1
php-fpm 8.5.11-1
php-apache 8.5.11-1

Upgrade the whole system, as always on Arch, then restart PHP. In our test pacman replaced the files but restarted nothing, so PHP-FPM kept answering with X-Powered-By: PHP/8.5.11 after the upgrade finished, and Apache with mod_php did the same. The restart is the step that actually loads the fix:

sudo pacman -Syu
sudo systemctl try-restart php-fpm httpd

try-restart only restarts units that are already running, so it will not start Apache on a box where Nginx owns port 80. It does not cover other PHP branches: php-legacy runs its own php-legacy-fpm unit, so add that name to the line if you use it (the AUR php84 runs php84-fpm). Long-running PHP CLI processes (queue workers, anything under supervisor) still hold the old binary and need their own restart. Then compare the upgrade time in pacman’s log with the time PHP-FPM last started:

grep -E 'upgraded php-fpm ' /var/log/pacman.log | tail -1
systemctl show -p ActiveEnterTimestamp php-fpm

The service start must be later than the upgrade line. In our test it is, by two seconds. On a mod_php-only server, grep for upgraded php-apache instead and read the httpd timestamp:

[2026-10-22T20:02:33+0000] [ALPM] upgraded php-fpm (8.5.11-1 -> 8.5.12-1)
ActiveEnterTimestamp=Thu 2026-10-22 20:02:35 UTC

If you already serve a PHP page, the response header is the quickest end-to-end proof, because it comes from the process handling the request (use systemctl show -p ActiveEnterTimestamp httpd instead of the FPM unit for mod_php):

curl -sI http://localhost/index.php | grep -i x-powered-by

After the restart the header reports the fixed release.

X-Powered-By: PHP/8.5.12

Arch’s default php.ini has expose_php = On, which is why the header exists. If you have turned it off, use the timestamp check instead.

PHP 8.4 from the AUR is not patched yet

The AUR’s php84 was still at 8.4.24-2 on 22 October 2026, last updated in August and flagged out of date, while the fixed upstream release is 8.4.27. Building it with an AUR helper such as yay gives you a vulnerable PHP. Move the application to php or to the patched php-legacy 8.3 if you can. If you cannot do that until the package catches up, PHP’s advisory lists mitigations that only reduce exposure, and patching is the fix. Three of them go into the PHP-FPM pool. The AUR package keeps its configuration under /etc/php84/, so its pool file is:

sudo vim /etc/php84/php-fpm.d/www.conf

Append these lines to the [www] pool. We tested them in Arch’s own /etc/php/php-fpm.d/www.conf, not on a php84 build. Use 32M for post_max_size if the site takes uploads, and keep upload_max_filesize below it:

php_admin_flag[session.upload_progress.enabled] = off
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 8M

Restart the service with sudo systemctl restart php84-fpm and check the values through a web request, not the CLI. A probe page served by Nginx then reported upload_progress='0' memory_limit=-1 post_max_size=8M, while php -r on the same box still showed upload progress as 1, because the pool settings never reach the CLI. memory_limit = -1 lets a single request take all the RAM, so watch memory and put the limit back once you are on a fixed build. With mod_php (php84-apache), the same settings go into httpd.conf as php_admin_flag session.upload_progress.enabled off, php_admin_value memory_limit -1 and php_admin_value post_max_size 8M, followed by an Apache restart. When we did that with Arch’s mod_php, the probe reported the same three values. The advisory lists further measures (limits on field, part and header counts and nesting), so read it before you rely on these.

Install and enable PHP extensions

Extensions are separate packages named php-<name>. This set covers both web server setups below plus a few common modules. intl no longer needs a package of its own because it is compiled into php (the package lists Provides: php-intl), so asking for php-intl just reinstalls PHP:

sudo pacman -S php-apache php-cgi php-fpm php-gd php-embed php-redis php-snmp

Apache comes in as a dependency of php-apache, and php-redis drags in php-igbinary. These are the PHP lines from the 45-package transaction:

Package (45)         New Version              Net Change  Download Size
extra/php-igbinary   3.2.17RC1-1                0.10 MiB       0.04 MiB
extra/php-apache     8.5.12-1                  23.09 MiB       4.25 MiB
extra/php-cgi        8.5.12-1                  28.77 MiB       4.28 MiB
extra/php-embed      8.5.12-1                  23.09 MiB       4.24 MiB
extra/php-fpm        8.5.12-1                  28.82 MiB       4.34 MiB
extra/php-gd         8.5.12-1                   0.13 MiB       0.04 MiB
extra/php-redis      6.3.0-2                    0.86 MiB       0.24 MiB
extra/php-snmp       8.5.12-1                   0.06 MiB       0.02 MiB
Total Download Size:    63.33 MiB
Total Installed Size:  287.42 MiB

Arch installs extensions disabled. Right after this step php -m listed none of gd, intl, redis or snmp, because their extension= lines ship commented out in /etc/php/php.ini and in the drop-ins under /etc/php/conf.d/. Uncomment them:

sudo sed -i -E 's/^;extension=(gd|intl|snmp)$/extension=\1/' /etc/php/php.ini
sudo sed -i 's/^;extension=igbinary.so/extension=igbinary.so/' /etc/php/conf.d/igbinary.ini
sudo sed -i 's/^;extension=redis/extension=redis/' /etc/php/conf.d/redis.ini

Confirm PHP now loads all five.

php -m | grep -E '^(gd|igbinary|intl|redis|snmp)$'

Each module prints on its own line. A missing one means its extension= line is still commented:

gd
igbinary
intl
redis
snmp

Running PHP-FPM and Apache only read these files at start, so restart whichever one you use after changing them. If you need the 8.3 branch next to 8.5, the php-legacy side-by-side setup covers its separate config directory. For the full package record, including what depends on PHP, use pacman -Qi:

pacman -Qi php

The Provides line confirms intl is part of the package, and Required By lists every SAPI and extension installed above:

Name            : php
Version         : 8.5.12-1
Description     : A general-purpose scripting language that is especially suited to web development
Architecture    : x86_64
URL             : https://www.php.net/
Licenses        : PHP-3.01
Groups          : None
Provides        : php-interpreter=8.5  php-intl=8.5.12
Depends On      : libxml2  curl  libzip  pcre2  argon2  oniguruma
Optional Deps   : None
Required By     : php-apache  php-cgi  php-embed  php-fpm  php-gd  php-igbinary  php-snmp
Optional For    : None
Conflicts With  : php-intl
Replaces        : php-intl
Installed Size  : 39.20 MiB
Packager        : Pierre Schmitz <[email protected]>
Build Date      : Wed Oct 21 13:42:26 2026
Install Date    : Thu Oct 22 19:59:28 2026
Install Reason  : Explicitly installed
Install Script  : No
Validated By    : Signature

Validated By : Signature means pacman verified the Arch packager’s signature when it installed the package, which is worth confirming on a box that also builds packages from the AUR.

Run PHP with Apache

mod_php is not thread-safe, so Apache has to switch from the event MPM to prefork before it can load libphp.so. These two edits to /etc/httpd/conf/httpd.conf comment out the event module and enable prefork:

sudo sed -i 's/^LoadModule mpm_event_module/#LoadModule mpm_event_module/; s/^#LoadModule mpm_prefork_module/LoadModule mpm_prefork_module/' /etc/httpd/conf/httpd.conf

Then load the PHP module and its handler config at the end of the file. php_module.conf ships with php-apache and maps .php files to PHP:

printf 'LoadModule php_module modules/libphp.so\nAddHandler php-script .php\nInclude conf/extra/php_module.conf\n' | sudo tee -a /etc/httpd/conf/httpd.conf

Test the configuration before you start Apache.

sudo apachectl configtest

Syntax OK is what matters. The AH00558 line only means no ServerName is set, and setting one in httpd.conf silences it:

AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 10.0.1.50. Set the 'ServerName' directive globally to suppress this message
Syntax OK

Apache’s document root on Arch is /srv/http. Create a test page there:

sudo vim /srv/http/index.php

Add the following contents.

<html>
<body>
<div style="width: 100%; font-size: 40px; font-weight: bold; text-align:center;">
<?php
    print "Hello World";
?>
</div>
</body>
</html>

Start Apache and enable it at boot.

sudo systemctl enable --now httpd

Request the page from the server itself first, so a firewall or DNS problem can’t hide a PHP problem:

curl -s http://localhost/index.php

PHP ran the print statement, so the response carries the text and none of the <?php tags. If you see the tags, Apache served the file as plain text and the module is not loaded:

<html>
<body>
<div style="width: 100%; font-size: 40px; font-weight: bold; text-align:center;">
Hello World</div>
</body>
</html>

From another machine, open http://10.0.1.50/index.php with your server’s address. This capture is from the original Garuda test in February 2025:

PHP Hello World test page served by Apache on Garuda Linux

The page looks the same on the current build, since it does not print a version.

Run PHP with Nginx and PHP-FPM

Nginx and Apache both want port 80, so stop Apache first if you followed the previous section:

sudo systemctl disable --now httpd

Install Nginx from extra.

sudo pacman -S nginx

Start it and enable it at boot.

sudo systemctl enable --now nginx

php-fpm is already installed from the extensions step. Leave its pool user alone: Arch’s /etc/php/php-fpm.d/www.conf runs the www pool as http, the same user Nginx runs as, and the socket at /run/php-fpm/php-fpm.sock is owned by http too. Start the service:

sudo systemctl enable --now php-fpm

Check that it came up.

systemctl status php-fpm --no-pager

You want active (running) and the Ready to handle connections status line:

● php-fpm.service - The PHP FastCGI Process Manager
     Loaded: loaded (/usr/lib/systemd/system/php-fpm.service; enabled; preset: disabled)
     Active: active (running) since Thu 2026-10-22 20:02:14 UTC; 10ms ago
   Main PID: 1828 (php-fpm)
     Status: "Ready to handle connections"
      Tasks: 3 (limit: 1204)
     Memory: 13M (peak: 13M)
        CPU: 92ms

If the unit shows failed instead, read journalctl -u php-fpm first, because PHP-FPM refuses to start on a pool error and says exactly which line it rejected.

Error: “[pool www] cannot get uid for user ‘www-data'”

Arch has no www-data user, since that name comes from Debian and Ubuntu. Setting user = www-data in the pool, as many guides copied from Debian do, makes PHP-FPM exit with status 78 and this error in journalctl -u php-fpm. Put user = http and group = http back and restart the service.

Point Nginx at PHP-FPM

Nginx needs a location block that passes .php requests to the FPM socket. Open the main config:

sudo vim /etc/nginx/nginx.conf

Add this block inside the default server { listen 80; ... } block, below its location / { ... }. fastcgi.conf already sets SCRIPT_FILENAME from the document root, so the block needs no fastcgi_param line of its own:

        location ~ \.php$ {
            root           /srv/http;
            fastcgi_pass   unix:/run/php-fpm/php-fpm.sock;
            fastcgi_index  index.php;
            include        fastcgi.conf;
        }

Validate the file before restarting anything.

sudo nginx -t

The types_hash warning appears with Arch’s stock nginx.conf and does not stop anything. The two lines after it are the ones to read:

2026/10/22 20:02:15 [warn] 1861#1861: could not build optimal types_hash, you should increase either types_hash_max_size: 1024 or types_hash_bucket_size: 64; ignoring types_hash_bucket_size
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Restart both services so they pick up the extension and Nginx changes:

sudo systemctl restart php-fpm nginx

The index.php you created for Apache is still in /srv/http, so request it again, this time through Nginx and PHP-FPM:

curl -s http://localhost/index.php

The same rendered page comes back. A 502 Bad Gateway here means PHP-FPM is down or the socket path is wrong, and a File not found. means the root line does not point at the directory holding the script:

<html>
<body>
<div style="width: 100%; font-size: 40px; font-weight: bold; text-align:center;">
Hello World</div>
</body>
</html>

Open http://10.0.1.50/index.php from another machine to see the same page in a browser.

Keep PHP patched on Arch

On Garuda, Arch and Manjaro the patched path is the plain one: php from the official repositories, enabled extensions, and either mod_php or PHP-FPM behind Nginx. Whichever you pick, follow every pacman -Syu that touches PHP with a restart and a look at the X-Powered-By header, because the upgrade on its own leaves the old PHP serving requests.

Udemy Video Courses to Learn MySQL / MariaDB Databases:

Similar guides:

Keep reading

Install GitHub CLI (gh) on Linux, macOS, and Windows Programming Install GitHub CLI (gh) on Linux, macOS, and Windows Claude Sonnet 5.5 Released: Benchmarks, Pricing, vs Opus 5.5 AI Claude Sonnet 5.5 Released: Benchmarks, Pricing, vs Opus 5.5 Best Linux Laptops for Programming and Developers (2026) Programming Best Linux Laptops for Programming and Developers (2026) Best Monitor Arms for a Multi-Monitor Developer Desk Programming Best Monitor Arms for a Multi-Monitor Developer Desk Best Mouse and Keyboard for Programming Programming Best Mouse and Keyboard for Programming Install Node.js 12 on Ubuntu / Debian / Linux Mint Debian Install Node.js 12 on Ubuntu / Debian / Linux Mint

Leave a Comment

Press ESC to close