How To

Installing Nginx With PHP-FPM on Ubuntu 24.04|22.04

Nginx is a high performance web server that’s free to use. Nginx is designed for speed and scalability with capabilities of reverse proxy and load balancing to a number of backend servers both with HTTP, TCP and UDP protocols. This website is powered by WordPress and Nginx and the performance is really good. Nginx has small memory footprint as compared to Apache, handling same number of concurrent connections. Below you’ll install Nginx with PHP-FPM on Ubuntu, serve a PHP page through it, and confirm the PHP build is patched against PHP2Shell. Every command except the reboot was run as a sudo user on fresh Ubuntu 24.04 and 22.04 systems in October 2026, including an upgrade from the pre-fix PHP builds.

Original content from computingforgeeks.com - post 67228

Key Features of Nginx

  • Content Cache: Cache static and dynamic content
  • Load Balancing: HTTP, TCP, and UDP load balancing with Layer 7 request routing using URI, cookie, args, and more.
  • Reverse proxy multiple protocols: HTTP, gRPC, memcached, PHP‑FPM, SCGI, uwsgi
  • Handle hundreds of thousands of clients simultaneously
  • Stream HTTP video: FLV, HDS, HLS, MP4
  • HTTP/2 gateway
  • Dual‑stack RSA/ECC SSL/TLS offload
  • Monitoring plugins: AppDynamics, Datadog, Dynatrace plug‑ins

This guide has been created to help users running Ubuntu server to install Nginx web server and configure PHP-FPM (FastCGI Process Manager).

Step 1: Update Ubuntu server

Before you begin, you should have a running Ubuntu server that has been updated and upgraded to the latest available packages.

sudo apt update && sudo apt -y full-upgrade
[ -f /var/run/reboot-required ] && sudo reboot

The second line reboots only when the upgrade installed something that needs it, such as a new kernel.

Step 2: Install Nginx on Ubuntu

Apache and Nginx can’t both listen on port 80. If Apache is already installed on this server, stop and disable it before you install Nginx, because Nginx cannot start while Apache holds the port, and apt still finishes without an error, so the failure is easy to miss. On a fresh server the command prints Unit file apache2.service does not exist, which you can ignore.

sudo systemctl disable --now apache2

With port 80 free, install the Nginx package from the Ubuntu archive.

sudo apt install -y nginx

The package enables and starts the service on its own. Check the first lines of its status.

systemctl status nginx --no-pager | head -n 3

On our Ubuntu 24.04 server it reports enabled and active (running):

● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: enabled)
     Active: active (running) since Thu 2026-10-22 19:48:46 UTC; 1s ago

UFW firewall can be configured to allow ports 80 and 443:

sudo ufw allow proto tcp from any to any port 80,443

UFW answered Rules updated for IPv4 and IPv6 on both test servers. The rule only filters traffic once UFW itself is enabled.

Step 3: Install PHP-FPM on Ubuntu

Nginx does not run PHP itself, so it hands PHP requests to PHP-FPM over a Unix socket. Install PHP-FPM with the common extensions, and leave out the plain php metapackage. It pulls in php8.3 on 24.04 (php8.1 on 22.04), whose first listed alternative is Apache’s PHP module, libapache2-mod-php8.3, so it brings in Apache, which then fails to start because Nginx already owns port 80.

sudo apt update
sudo apt install -y php-fpm php-cli php-json php-pdo php-mysql php-zip php-gd php-mbstring php-curl php-xml php-pear php-bcmath

Ubuntu 24.04 installs PHP 8.3 and 22.04 installs PHP 8.1. The service name and config paths carry that branch number, so save it in a variable for the rest of this guide.

PHPV=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')
echo "$PHPV"

On 24.04 the variable holds the PHP 8.3 branch:

8.3

If you set this server up with an earlier version of this guide, the php metapackage may have left Apache and its PHP module behind. Check with dpkg -l apache2, and if it’s listed and you don’t use Apache, purge both. PHP-FPM, the php metapackage and Nginx stay installed and running:

sudo apt purge -y apache2 libapache2-mod-php${PHPV}

PHP-FPM is a service of its own, and the package starts it on install. Check it the same way as Nginx.

systemctl status php${PHPV}-fpm --no-pager | head -n 3

The unit is enabled, so it comes back after a reboot, and it is running:

● php8.3-fpm.service - The PHP 8.3 FastCGI Process Manager
     Loaded: loaded (/usr/lib/systemd/system/php8.3-fpm.service; enabled; preset: enabled)
     Active: active (running) since Thu 2026-10-22 19:49:30 UTC; 78ms ago

PID and Socket file are located in the directory:

ls /run/php/

Besides the versioned socket, Ubuntu keeps a php-fpm.sock link that always points at the default PHP branch:

php-fpm.sock
php8.3-fpm.pid
php8.3-fpm.sock

On 22.04 the same files carry php8.1 in their names, and the link works the same way, which is why the Nginx config below points at php-fpm.sock.

Step 4: Configure PHP-FPM with Nginx

Edit FPM default www pool configuration file

sudo vim /etc/php/${PHPV}/fpm/pool.d/www.conf

Set the listen line to the versionless socket path, so the Nginx side does not change when you move to another PHP branch:

listen = /run/php/php-fpm.sock

PHP-FPM reads the pool file only at start, so restart it. Afterwards /run/php/php-fpm.sock is the pool’s real socket instead of a link:

sudo systemctl restart php${PHPV}-fpm

Next, keep the FastCGI settings in one snippet that every site can include.

sudo vim /etc/nginx/php_fastcgi.conf

Add the following. It includes fastcgi.conf rather than fastcgi_params on purpose: on Ubuntu only fastcgi.conf sets SCRIPT_FILENAME, and without it PHP-FPM logs Primary script unknown and Nginx returns 404 for every PHP page, which is exactly what we got with fastcgi_params.

# 404
try_files $fastcgi_script_name =404;

# fastcgi_params plus SCRIPT_FILENAME
include fastcgi.conf;

# fastcgi settings
fastcgi_pass			unix:/run/php/php-fpm.sock;
fastcgi_index			index.php;
fastcgi_buffers			8 16k;
fastcgi_buffer_size		32k;
fastcgi_hide_header             X-Powered-By;
fastcgi_hide_header             X-CF-Powered-By;

The snippet does nothing until a server block includes it. For the default site, open its config.

sudo vim /etc/nginx/sites-available/default

Replace its contents with this server block, which adds index.php to the index list and sends .php requests through the snippet. Your own application’s server block takes the same location block.

server {
	listen 80 default_server;
	listen [::]:80 default_server;

	root /var/www/html;
	index index.php index.html index.htm index.nginx-debian.html;

	server_name _;

	location / {
		try_files $uri $uri/ =404;
	}

	location ~ \.php$ {
		include php_fastcgi.conf;
	}
}

Test the configuration before reloading, so a typo does not take the site down.

sudo nginx -t

Both lines should report success, and on an error Nginx names the file and line it choked on:

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

Reload Nginx to apply it.

sudo systemctl reload nginx

Now drop a small test page into the web root and request it through Nginx:

echo '<?php echo PHP_VERSION, " ", PHP_SAPI, PHP_EOL;' | sudo tee /var/www/html/info.php
curl -s http://127.0.0.1/info.php

After tee echoes the PHP line back, curl prints the PHP version and fpm-fcgi, which proves Nginx passed the request to PHP-FPM instead of serving the file as text:

8.3.6 fpm-fcgi

Keep the test page for the PHP2Shell check in the next step, and delete it there.

Step 5: Check PHP-FPM for PHP2Shell (CVE-2026-109618, CVE-2026-109619)

PHP2Shell is a pair of critical remote code execution bugs in PHP itself, CVE-2026-109618 and CVE-2026-109619, scored CVSS v4.0 9.2 in php.net’s 20 October pre-announcement. PHP fixed them upstream on 21 October 2026 in 8.5.12, 8.4.27, 8.3.36 and 8.2.35. Ubuntu backported the fix without changing the upstream version, into 8.3.6-0ubuntu0.24.04.13 on 24.04 and 8.1.2-1ubuntu2.28 on 22.04, so a fresh install from this guide is already patched. The PHP security advisory has the details.

Because the version number does not move, php -v proves nothing here. The package changelog does, since it names the CVEs the build fixes. Every command in this step uses PHPV, and in a new shell (or on a server you set up earlier) that variable is empty, which turns php${PHPV}-common into the unrelated php-common package and makes the version check below print a false patched. Set it again first; the second line stops with an error if it is still empty:

PHPV=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')
: "${PHPV:?set PHPV first}"

With the branch set, read the changelog:

zgrep -E 'CVE-2026-10961[89]' /usr/share/doc/php${PHPV}-common/changelog.Debian.gz

A patched build prints these three lines on both releases. No output means the installed package is older than the fixed build:

    - debian/patches/CVE-2026-109618_109619.patch: Avoid state corruption via
    - CVE-2026-109618
    - CVE-2026-109619

Minimized Ubuntu images strip /usr/share/doc, so there’s no changelog to read. This comparison checks the package version instead. It’s written for 24.04; on 22.04 put 8.1.2-1ubuntu2.28 in place of the 24.04 version. If your PHP comes from ppa:ondrej/php instead of Ubuntu, compare against the PPA build for your branch instead (8.5.12, 8.4.27, 8.3.36 or 8.1.34-9), because a PPA version always sorts above Ubuntu’s and would read as patched.

dpkg --compare-versions "$(dpkg-query -W -f='${Version}' php${PHPV:?set PHPV first}-common)" ge 8.3.6-0ubuntu0.24.04.13 && echo patched || echo VULNERABLE

It printed VULNERABLE on our test server while the older 24.04 release build was installed, and this after the upgrade:

patched

A fresh install can skip to removing the test page. On an existing server where either check fails, upgrade every package of the PHP branch. The Apache module starts with lib, so the glob misses it and it’s named separately. APT prints a Skipping ... it is not installed line for each name the server does not have, which is harmless.

sudo apt update
sudo apt install -y --only-upgrade "php${PHPV}*" "libapache2-mod-php${PHPV}"

Restart PHP-FPM yourself so no worker keeps the old code in memory. If Apache with mod_php is also active on the server, restart apache2 as well, and restart long-running PHP CLI processes such as queue workers kept alive by supervisor or a systemd unit.

sudo systemctl restart php${PHPV}-fpm

To prove the restart picked up the new build, compare two times. First find when the PHP packages were last upgraded, including rotated logs.

zgrep -hE " (install|upgrade) php${PHPV}-(common|fpm):" /var/log/dpkg.log* | sort | tail -1

Our 24.04 server shows the jump from the release build to the fixed one:

2026-10-22 19:50:12 upgrade php8.3-common:amd64 8.3.6-0maysync1 8.3.6-0ubuntu0.24.04.13

Then ask systemd when PHP-FPM last came up. A service that started before the upgrade is still running the old code, whatever the package database says.

systemctl show -p ActiveEnterTimestamp php${PHPV}-fpm

The timestamp must be later than the dpkg line, and here it is:

ActiveEnterTimestamp=Thu 2026-10-22 19:50:39 UTC

The test page from Step 4 helps only on 22.04. There the patched build reports its package revision in PHP_VERSION, so the page printed a bare 8.1.2 before the upgrade and this after it. On 24.04 the page says 8.3.6 before and after the fix, so rely on the timestamp there.

8.1.2-1ubuntu2.28 fpm-fcgi

Remove the test page once you’ve read it, since it tells anyone which PHP build you run:

sudo rm /var/www/html/info.php

Ubuntu 20.04 has no free fix. Its php7.4 patch (7.4.3-4ubuntu2.29+esm5) ships only through Ubuntu Pro, and the Ondrej PPA no longer publishes focal builds. Without Pro, move the site to Ubuntu 24.04 and follow this guide there, since its PHP 8.3 already carries the fix.

Check other Nginx articles:

Nginx Books to read:

Keep reading

Upgrade Ubuntu 24.04 to Ubuntu 26.04 LTS (Step by Step) Ubuntu Upgrade Ubuntu 24.04 to Ubuntu 26.04 LTS (Step by Step) UFW Firewall Commands with Examples on Ubuntu 26.04 / 24.04 Security UFW Firewall Commands with Examples on Ubuntu 26.04 / 24.04 PHP2Shell on End-of-Life PHP 8.1, 8.0 and 7.4 (WHMCS, ionCube) Php PHP2Shell on End-of-Life PHP 8.1, 8.0 and 7.4 (WHMCS, ionCube) Upgrade a Single Package on Ubuntu / Debian with apt Debian Upgrade a Single Package on Ubuntu / Debian with apt CapRover Docker Install on Debian 13: Deploy Your First App Containers CapRover Docker Install on Debian 13: Deploy Your First App Fix ifup / ifdown Command Not Found on Debian and Ubuntu Debian Fix ifup / ifdown Command Not Found on Debian and Ubuntu

Leave a Comment

Press ESC to close