
Table of Contents
By Khimananda Oli | Last reviewed: August 2026
To install PHP on Ubuntu 24.04 LTS for production workloads, you must move beyond the default repository packages and configure PHP-FPM as a dedicated process manager behind Nginx. Most tutorials stop at apt install php, leaving you with an insecure, unoptimized CLI binary that cannot serve web traffic efficiently. This guide covers the complete workflow: adding the Ondřej Surý PPA for current releases, installing PHP-FPM with necessary extensions, integrating it with Nginx via Unix sockets, and applying the security hardening required for compliance-ready infrastructure.
sudo apt install php8.4-fpm, configure your Nginx server block to pass requests to the FPM socket at /run/php/php8.4-fpm.sock, and verify with php-fpm8.4 -t. Always disable dangerous functions and set memory limits before going live.How Do You Install PHP on Ubuntu Using the Ondřej Surý PPA?
The default Ubuntu repositories often lag behind the latest stable PHP releases by months or even years. In August 2026, relying on the base repo might give you PHP 8.3 when 8.4 is the current standard with critical performance improvements and security patches. The Ondřej Surý PPA is the de facto industry standard for Debian/Ubuntu systems, providing timely updates and co-installable versions.
Before adding any third-party repository, ensure your base system is updated and you have the prerequisite tools. This is also the right moment to review your initial Ubuntu server setup to confirm SSH hardening and firewall rules are in place before exposing new services.
# Update base system and install prerequisites
sudo apt update && sudo apt upgrade -y
sudo apt install -y software-properties-common apt-transport-https ca-certificates curl gnupg
# Add the Ondřej Surý PPA
sudo add-apt-repository ppa:ondrej/php -y
sudo apt update Once the PPA is active, you can query available versions. Never assume a version exists; always verify against the package index. This prevents deployment failures in automated pipelines where silent fallbacks can mask configuration drift.
# List available PHP versions
apt-cache policy php8.4-fpm php8.4-cli php8.4-common
# Install the core FPM package (includes CLI and common dependencies)
sudo apt install -y php8.4-fpm php8.4-cli php8.4-common Which PHP Extensions Are Required for Production Applications?
A bare PHP-FPM installation lacks the extensions most modern frameworks require. Installing everything "just in case" increases your attack surface and memory footprint. Instead, select extensions based on your actual application dependencies. For Laravel, WordPress, or Symfony applications in 2026, the following set covers 95% of production needs without bloat.
- php8.4-mysql / pgsql: Database drivers. Choose only what you use; never install both unless running multi-database workloads.
- php8.4-xml & php8.4-mbstring: Non-negotiable for string handling, DOM manipulation, and virtually every Composer package.
- php8.4-curl: Required for HTTP clients, payment gateways, and external API integrations.
- php8.4-gd / imagick: Image processing. GD is lighter; Imagick supports more formats but requires additional system libraries.
- php8.4-opcache: Mandatory for performance. Caches compiled bytecode in shared memory, reducing CPU overhead by 50–70%.
- php8.4-redis: Session storage, queue backends, and caching. Far superior to file-based sessions in multi-server environments.
- php8.4-zip & php8.4-intl: Archive handling and internationalization. Often overlooked during initial setup, causing runtime errors later.
# Install recommended production extensions in one command
sudo apt install -y php8.4-mysql php8.4-xml php8.4-mbstring \
php8.4-curl php8.4-gd php8.4-opcache php8.4-redis \
php8.4-zip php8.4-intl php8.4-bcmath
# Verify installed modules
php -m | grep -E 'opcache|redis|mbstring' After installation, restart FPM to load new extensions. Unlike Apache with mod_php, PHP-FPM does not hot-reload modules; a service restart is mandatory. In CI/CD pipelines, always include this restart step after extension installation to avoid deploying broken configurations.
How Do You Configure Nginx to Work with PHP-FPM?
Nginx does not execute PHP natively. It acts as a reverse proxy, passing requests to PHP-FPM via either a TCP port or a Unix domain socket. For single-server deployments, Unix sockets are faster and more secure: they avoid TCP overhead and cannot be accidentally exposed to the network. Reserve TCP connections only for distributed architectures where FPM runs on separate hosts.
Create or edit your Nginx server block. The critical directive is fastcgi_pass, which must match the socket path defined in /etc/php/8.4/fpm/pool.d/www.conf. On Ubuntu 24.04, the default socket location is /run/php/php8.4-fpm.sock.
# /etc/nginx/sites-available/example.com
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com/public;
index index.php index.html;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
# Performance tuning
fastcgi_buffer_size 16k;
fastcgi_buffers 4 16k;
fastcgi_read_timeout 300;
}
# Deny access to hidden files
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
} Test the configuration before reloading. A syntax error here takes down your entire site. This validation step should be automated in your deployment pipeline, as discussed in guides on deploying Laravel on Ubuntu VPS with Nginx.
# Validate Nginx config
sudo nginx -t
# Reload if valid
sudo systemctl reload nginx
# Verify FPM is listening
sudo ss -lx | grep php What Security Hardening Steps Are Essential After Installation?
Default PHP configurations prioritize compatibility over security. Before serving traffic, you must restrict dangerous functions, limit resource consumption, and hide version information. These changes are non-negotiable for SOC 2 or ISO 27001 compliance, and they prevent entire classes of exploits that target misconfigured interpreters.
Edit the production FPM ini file. Never modify cli/php.ini for web security; FPM uses its own configuration at /etc/php/8.4/fpm/php.ini.
# Critical security directives for /etc/php/8.4/fpm/php.ini
expose_php = Off ; Hide PHP version in headers
disable_functions = exec,passthru,shell_exec,system,proc_open,popen
max_execution_time = 30 ; Prevent runaway scripts
memory_limit = 256M ; Set realistic ceiling
upload_max_filesize = 10M ; Restrict uploads
post_max_size = 12M ; Must exceed upload_max
open_basedir = /var/www:/tmp ; Jail filesystem access
session.cookie_httponly = 1 ; Prevent JS session theft
session.cookie_secure = 1 ; HTTPS-only cookies
session.use_strict_mode = 1 ; Reject uninitialized sessions Additionally, tune the FPM pool configuration at /etc/php/8.4/fpm/pool.d/www.conf. The default pm = dynamic settings are rarely optimal. Calculate workers based on available RAM: each PHP worker consumes 30–60MB depending on your application. On a 4GB VPS, reserve 1GB for OS/Nginx/DB, leaving ~50 workers maximum. Over-provisioning causes OOM kills under load.
| Directive | Default Value | Production Recommendation | Rationale |
|---|---|---|---|
pm.max_children | 5 | RAM_MB / 50 | Prevents memory exhaustion while maximizing concurrency |
pm.start_servers | 2 | max_children / 4 | Balances cold-start latency vs idle resource waste |
pm.min_spare_servers | 1 | max_children / 8 | Maintains buffer for traffic spikes without over-provisioning |
pm.max_requests | 0 (unlimited) | 500–1000 | Recycles workers to prevent memory leaks from accumulating |
request_terminate_timeout | 0 (disabled) | 60s | Kills hung requests before they exhaust the worker pool |
After making changes, validate the FPM configuration syntax and restart the service. Invalid pool configs silently fail to start workers, leaving your site returning 502 errors.
# Test FPM configuration
sudo php-fpm8.4 -t
# Restart and verify status
sudo systemctl restart php8.4-fpm
sudo systemctl status php8.4-fpm --no-pager How Do You Manage Multiple PHP Versions on the Same Server?
Running multiple PHP versions simultaneously is common when hosting legacy applications alongside modern ones, or during migration windows. The Ondřej Surý PPA supports co-installation: php8.2-fpm, php8.3-fpm, and php8.4-fpm can all run concurrently, each with independent pools, sockets, and configurations.
Each version gets its own socket path (/run/php/php8.2-fpm.sock, etc.) and configuration directory. Switch between CLI versions using update-alternatives, but remember this does not affect FPM — each web application's Nginx config explicitly references its required socket.
# Install additional versions side-by-side
sudo apt install -y php8.2-fpm php8.3-fpm
# Set default CLI version
sudo update-alternatives --config php
# Verify all running FPM instances
sudo systemctl list-units --type=service | grep php.*fpm This approach eliminates downtime during upgrades. Deploy the new version, update Nginx configs incrementally, test thoroughly, then decommission the old version. For teams managing multiple environments, consider automating this process as outlined in guides on PHP-FPM tuning for high-traffic websites.
Install PHP on Ubuntu: Final Checklist and Next Steps
Successfully configuring PHP-FPM requires attention to detail that generic tutorials skip. You have now added the correct PPA, installed targeted extensions, configured Nginx with Unix sockets, applied security hardening, and planned for multi-version management. Before declaring production readiness, run through this verification checklist:
- Confirm FPM is active:
systemctl is-active php8.4-fpmreturns "active". - Validate socket permissions:
ls -la /run/php/php8.4-fpm.sockshows www-data ownership. - Test PHP execution: Create a temporary
info.phpwith<?php phpinfo(); ?>, verify output, then delete immediately. - Check OPcache status: Confirm
opcache.enable=1in phpinfo output. - Review error logs:
journalctl -u php8.4-fpm --since "1 hour ago"for warnings. - Run a security scan: Tools like Lynis or custom scripts to verify
disable_functionsandopen_basedir.
If you are building this as part of a larger infrastructure automation effort, consider codifying these steps in Ansible or Terraform rather than manual execution. Reproducible infrastructure prevents configuration drift and makes disaster recovery predictable. For teams exploring AI-assisted operations, our guide on automating DevOps tasks with AI assistants demonstrates how to generate validated PHP-FPM configurations using LLMs with proper guardrails.
Need help auditing your PHP deployment or designing a compliant infrastructure? Reach out to discuss your specific requirements.