A reliable PHP stack depends on one small handoff: Nginx must send PHP requests to the PHP-FPM socket that matches Ubuntu’s default PHP branch. To configure PHP-FPM on Ubuntu, install the Nginx and PHP-FPM packages, confirm the branch-specific socket, wire that socket into your server block, and test the full request path before hosting a real application.
The package names stay stable across supported Ubuntu LTS releases, but the default PHP branch changes. Ubuntu 26.04 uses PHP 8.5, Ubuntu 24.04 uses PHP 8.3, and Ubuntu 22.04 uses PHP 8.1 from the Ubuntu repositories, so the commands detect the active branch before they write service names or socket paths.
Configure PHP-FPM on Ubuntu for Nginx
Install Nginx, the PHP command-line package, PHP-FPM, and curl for local HTTP checks. The explicit php-cli and php-fpm packages keep the setup focused on Nginx instead of using the broader php metapackage.
sudo apt update
sudo apt install nginx php-cli php-fpm curl
If the server still needs a complete Nginx baseline, install Nginx on Ubuntu before adding PHP-FPM. For broader PHP package choices, extensions, and alternate PHP branches, use install PHP on Ubuntu instead of expanding this Nginx-focused setup.
The php-fpm metapackage comes from Ubuntu’s universe component on supported LTS releases. If APT cannot locate php-fpm, enable Universe and Multiverse in Ubuntu; only Universe is required for this package.
| Ubuntu Release | Default PHP-FPM Branch | Service Unit | Default Socket |
|---|---|---|---|
| Ubuntu 26.04 | PHP 8.5.x | php8.5-fpm.service | /run/php/php8.5-fpm.sock |
| Ubuntu 24.04 | PHP 8.3.x | php8.3-fpm.service | /run/php/php8.3-fpm.sock |
| Ubuntu 22.04 | PHP 8.1.x | php8.1-fpm.service | /run/php/php8.1-fpm.sock |
Find the PHP-FPM Branch and Socket on Ubuntu
Store the active PHP branch in a shell variable, then print the matching socket path. Keep this terminal session open for later commands that reuse PHP_VERSION.
PHP_VERSION=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')
printf 'PHP %s\n' "$PHP_VERSION"
printf '/run/php/php%s-fpm.sock\n' "$PHP_VERSION"
On Ubuntu 26.04, the detected branch and socket look like this:
PHP 8.5 /run/php/php8.5-fpm.sock
Verify the branch-specific PHP-FPM unit is running and enabled for boot:
systemctl is-active "php${PHP_VERSION}-fpm"
systemctl is-enabled "php${PHP_VERSION}-fpm"
A healthy service returns:
active enabled
Check the default pool user, group, and socket. Ubuntu’s packaged Nginx and PHP-FPM defaults both use www-data, so the default pool can serve Nginx without changing worker ownership.
grep -E '^(user|group|listen) =' "/etc/php/${PHP_VERSION}/fpm/pool.d/www.conf"
Relevant output on Ubuntu 26.04 includes:
user = www-data group = www-data listen = /run/php/php8.5-fpm.sock
Confirm the socket exists before wiring Nginx to it:
test -S "/run/php/php${PHP_VERSION}-fpm.sock" && echo "PHP-FPM socket exists"
PHP-FPM socket exists
Configure Nginx to Use PHP-FPM on Ubuntu
Create a small document root and PHP test file. Replace example.com with the hostname and path for your real site when you adapt the server block.
sudo mkdir -p /var/www/example.com/public
printf '%s\n' '<?php echo "php-fpm-ok\n";' | sudo tee /var/www/example.com/public/index.php >/dev/null
Write an Nginx server block that passes only PHP files to the detected PHP-FPM socket. The Ubuntu Nginx package ships snippets/fastcgi-php.conf, which sets the common FastCGI parameters and includes a file-existence check before forwarding the request.
PHP_VERSION=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')
sudo tee /etc/nginx/sites-available/example.com >/dev/null <<EOF
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com/public;
index index.php index.html;
location / {
try_files \$uri \$uri/ /index.php?\$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php${PHP_VERSION}-fpm.sock;
}
location ~ /\. {
deny all;
}
}
EOF
Enable the server block, test the Nginx configuration, and reload the service only after the syntax check passes.
sudo ln -sf /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com
sudo nginx -t
A valid Nginx configuration returns:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
sudo systemctl reload nginx
Send a local request with the matching host header. This proves Nginx selected the server block, sent the request to PHP-FPM, and received executed PHP output instead of raw PHP source.
curl -fsS -H 'Host: example.com' http://127.0.0.1/
php-fpm-ok
If this server will accept public traffic, open only the ports your site actually uses. Configure UFW firewall on Ubuntu for the firewall layer, then secure Nginx with Let’s Encrypt on Ubuntu for TLS certificates, redirects, and renewal handling.
Tune PHP-FPM Pool Settings on Ubuntu
Most PHP-FPM tuning happens inside the pool file for the active branch. Back up the default pool before changing worker limits or process-manager mode.
sudo cp "/etc/php/${PHP_VERSION}/fpm/pool.d/www.conf" "/etc/php/${PHP_VERSION}/fpm/pool.d/www.conf.bak"
sudo nano "/etc/php/${PHP_VERSION}/fpm/pool.d/www.conf"
Use the process-manager mode that matches the traffic pattern. The PHP-FPM configuration reference documents these directives in detail, but the practical choice is usually straightforward.
| Mode | Best Fit | Important Directives |
|---|---|---|
dynamic | General websites with regular traffic changes | pm.max_children, pm.start_servers, pm.min_spare_servers, pm.max_spare_servers |
ondemand | Low-traffic sites where idle workers should exit | pm.max_children, pm.process_idle_timeout, pm.max_requests |
static | Predictable high traffic on a server with reserved memory | pm.max_children |
For a modest dynamic pool, start with conservative values and raise them only after watching memory use under real traffic.
pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 8
pm.max_requests = 500
For a low-traffic site, ondemand keeps fewer idle workers resident in memory.
pm = ondemand
pm.max_children = 10
pm.process_idle_timeout = 10s
pm.max_requests = 500
Test the PHP-FPM configuration before restarting the service. The filtered form keeps the success output stable even though PHP-FPM prefixes its raw message with a timestamp.
sudo "php-fpm${PHP_VERSION}" -t 2>&1 | grep 'test is successful' | sed -E 's/^\[[^]]+\] NOTICE: //'
On Ubuntu 26.04, the filtered success line uses the PHP 8.5 path. Ubuntu 24.04 and 22.04 print their active branch paths instead.
configuration file /etc/php/8.5/fpm/php-fpm.conf test is successful
sudo systemctl restart "php${PHP_VERSION}-fpm"
After tuning PHP-FPM for production traffic, Nginx FastCGI caching can reduce repeated PHP work for cacheable pages. Use set up Nginx FastCGI cache on Ubuntu when your application can safely cache dynamic responses.
Create a Separate PHP-FPM Pool on Ubuntu
A separate pool is useful when one application needs its own worker limits, status endpoint, or socket. Keep the default www pool for simple single-site servers, and add a separate pool only when isolation or per-site tuning is worth the extra configuration.
sudo cp "/etc/php/${PHP_VERSION}/fpm/pool.d/www.conf" "/etc/php/${PHP_VERSION}/fpm/pool.d/example.conf"
sudo nano "/etc/php/${PHP_VERSION}/fpm/pool.d/example.conf"
Use a unique pool name and socket. This example keeps the same www-data user as Nginx for a standard Ubuntu web root; sites with stronger isolation requirements should also create a matching Linux user and update the site’s file ownership.
[example]
user = www-data
group = www-data
listen = /run/php/php8.5-fpm-example.sock
listen.owner = www-data
listen.group = www-data
pm = ondemand
pm.max_children = 10
pm.process_idle_timeout = 10s
pm.max_requests = 500
Replace 8.5 in the socket path with the value printed by PHP_VERSION on Ubuntu 24.04 or 22.04. Then test PHP-FPM and restart the branch-specific service.
sudo "php-fpm${PHP_VERSION}" -t
sudo systemctl restart "php${PHP_VERSION}-fpm"
Point the matching Nginx server block at the new pool socket, using the same branch-specific socket name you set in the pool file:
fastcgi_pass unix:/run/php/php8.5-fpm-example.sock;
The Nginx FastCGI module documentation defines the fastcgi_pass directive and the accepted Unix-socket syntax.
Monitor PHP-FPM Status on Ubuntu
PHP-FPM can expose a lightweight status endpoint for local checks and monitoring systems. Add a status path to the pool that should report its worker state.
pm.status_path = /fpm-status
ping.path = /fpm-ping
Add a restricted Nginx location for the same socket. This block uses fastcgi_params instead of snippets/fastcgi-php.conf because the status path is handled by PHP-FPM itself, not by a real PHP file in the document root. Replace 8.5 with the active branch on Ubuntu 24.04 or 22.04.
location ~ ^/(fpm-status|fpm-ping)$ {
allow 127.0.0.1;
allow ::1;
deny all;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php8.5-fpm.sock;
}
Keep PHP-FPM status endpoints private. Exposing pool state publicly can reveal process counts, request activity, and application behavior that should stay behind local access controls or a monitoring-only path.
Test PHP-FPM, reload both services, and query the status endpoint locally.
sudo "php-fpm${PHP_VERSION}" -t
sudo systemctl reload "php${PHP_VERSION}-fpm"
sudo nginx -t
sudo systemctl reload nginx
curl -fsS -H 'Host: example.com' http://127.0.0.1/fpm-status
For the default www pool before tuning, relevant status lines include the pool name and process manager. If you changed pm earlier, the process-manager line reflects that pool setting.
pool: www process manager: dynamic
Update PHP-FPM and Nginx on Ubuntu
Ubuntu updates PHP-FPM, Nginx, and their security fixes through APT. Refresh package metadata, then review available upgrades before applying them on production systems.
sudo apt update
apt list --upgradable
Apply normal package upgrades during a maintenance window:
sudo apt upgrade
For a narrower web-stack update, keep the branch variable available and ask APT to upgrade only these packages.
PHP_VERSION=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')
sudo apt install --only-upgrade nginx php-cli php-fpm "php${PHP_VERSION}-fpm" "php${PHP_VERSION}-cli"
After package upgrades that touch Nginx, PHP-FPM, or pool files, repeat the syntax checks before reloading services.
sudo "php-fpm${PHP_VERSION}" -t
sudo nginx -t
sudo systemctl reload "php${PHP_VERSION}-fpm"
sudo systemctl reload nginx
Troubleshoot PHP-FPM on Ubuntu
Most PHP-FPM failures come from a socket mismatch, a failed pool reload, missing Nginx FastCGI handling, or file permissions that prevent PHP workers from reading the application files.
Fix 502 Bad Gateway from PHP-FPM
A 502 response usually means Nginx reached the PHP location block but could not connect to the configured FastCGI backend. Check the PHP-FPM unit, socket, and active Nginx fastcgi_pass line together.
PHP_VERSION=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')
systemctl is-active "php${PHP_VERSION}-fpm"
test -S "/run/php/php${PHP_VERSION}-fpm.sock" && echo "socket exists"
sudo nginx -T 2>/dev/null | grep 'fastcgi_pass'
The socket in Nginx must match the active PHP-FPM branch. On Ubuntu 26.04, matching output looks like this:
active
socket exists
fastcgi_pass unix:/run/php/php8.5-fpm.sock;
If the socket path is wrong, update the server block, test Nginx, and reload both services.
sudo nginx -t
sudo systemctl reload nginx
sudo systemctl restart "php${PHP_VERSION}-fpm"
Fix PHP Source Displaying in the Browser
If the browser displays PHP source code instead of executing it, Nginx is serving the file as static text. Confirm that the selected server block includes a PHP location with include snippets/fastcgi-php.conf; and a matching fastcgi_pass socket.
sudo nginx -T 2>/dev/null | grep -A4 'location ~ \\.php'
On Ubuntu 26.04, relevant output should include both lines with the PHP 8.5 socket. Ubuntu 24.04 and 22.04 use their matching branch sockets.
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.5-fpm.sock;
Fix PHP-FPM Permission Errors
Permission problems appear when PHP-FPM workers cannot read the application files or write to directories the application owns. Check the pool identity and the target path before changing ownership recursively.
grep -E '^(user|group) =' "/etc/php/${PHP_VERSION}/fpm/pool.d/www.conf"
namei -l /var/www/example.com/public/index.php
For a standard Ubuntu Nginx setup, PHP-FPM runs as www-data. Application files should be readable along the whole path, and only directories that truly need runtime writes should be writable by the web process.
Fix PHP-FPM Memory Pressure
High memory use usually means pm.max_children is too high for the server or the application has slow requests holding workers open. Inspect worker memory before raising limits.
ps -o pid,rss,cmd -C "php-fpm${PHP_VERSION}"
The RSS column reports memory in KiB per visible worker. Use that number against available RAM before increasing pm.max_children, and prefer fixing slow PHP requests before turning every tuning problem into a larger pool.
Remove PHP-FPM and Nginx Configuration from Ubuntu
Remove the example server block first if it was only used for validation. Keep the package removal step for servers that no longer host Nginx or PHP-FPM sites.
Deleting
/var/www/example.comremoves the example web root. Do not run this cleanup against a production document root unless you have verified backups and confirmed the path is not shared by another site.
sudo rm -f /etc/nginx/sites-enabled/example.com /etc/nginx/sites-available/example.com
sudo rm -rf /var/www/example.com
sudo nginx -t
sudo systemctl reload nginx
If Nginx and the distro-default PHP-FPM branch are no longer needed, remove the packages installed for this stack. Save PHP_VERSION before removing PHP packages so the branch-specific package name still resolves.
PHP_VERSION=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;' 2>/dev/null || true)
sudo apt remove nginx php-cli php-fpm "php${PHP_VERSION}-cli" "php${PHP_VERSION}-fpm"
Verify the main packages are gone:
if dpkg-query -W -f='${binary:Package}\n' nginx php-fpm "php${PHP_VERSION}-fpm" 2>/dev/null | grep -q .; then
echo "Some Nginx or PHP-FPM packages are still installed"
else
echo "Nginx and PHP-FPM packages removed"
fi
Nginx and PHP-FPM packages removed
APT may report orphaned dependencies after package removal. Review them before cleanup, especially on reused servers where older kernels, desktop packages, or unrelated tools may already be marked autoremovable.
sudo apt autoremove --dry-run
Conclusion
PHP-FPM is connected to Nginx through the correct Ubuntu socket, with syntax checks and a local HTTP test proving that PHP requests execute through the FastCGI path. From here, harden the public edge with Let’s Encrypt, tune worker limits around real traffic, and add FastCGI caching only where the application can safely reuse dynamic responses.


Formatting tips for your comment
You can use basic HTML to format your comment. Useful tags currently allowed in published comments:
<code>command</code>command<strong>bold</strong><em>italic</em><a href="https://example.com">link</a><blockquote>quote</blockquote>