Ubuntu’s default repositories include PHP, but they often ship an older version. Ubuntu 22.04 LTS ships PHP 8.1. Ubuntu 24.04 LTS ships PHP 8.3. If you need a different version, or you want to run multiple versions side by side, you need the Ondrej PPA.
This guide covers installing PHP on Ubuntu via apt, adding the Ondrej PPA for specific versions, installing the extensions WordPress and other applications need, switching between PHP versions, and verifying that everything is working.
Installing PHP from the default repositories#
The simplest installation uses Ubuntu’s built-in packages:
sudo apt update
sudo apt install php
This installs the default PHP version for your Ubuntu release along with the Apache mod_php module. If you are running Nginx instead of Apache, install PHP-FPM instead:
sudo apt update
sudo apt install php-fpm
PHP-FPM (FastCGI Process Manager) runs PHP as a separate service that Nginx communicates with through a Unix socket. This is the standard setup for Nginx and is more efficient than embedding PHP in the web server process. See Nginx vs Apache: which one is better for WordPress for why this architecture matters for performance.
Verify the installation:
php -v
This prints the PHP version, build date, and whether thread safety is enabled. For a full breakdown of what the output means and how to confirm which PHP version your web server is actually using, see How to check your PHP version and find php.ini.
Installing a specific PHP version with the Ondrej PPA#
The Ondrej Sury PPA is the standard third-party repository for PHP on Ubuntu. It provides every actively maintained PHP version (8.1, 8.2, 8.3, 8.4) and backports security patches promptly. Nearly every hosting provider and deployment guide uses this PPA.
Add the PPA
sudo apt install software-properties-common
sudo add-apt-repository ppa:ondrej/php
sudo apt update
The
software-properties-common
package provides the
add-apt-repository
command. After adding the PPA and updating, the new PHP packages are available alongside the default ones.
Install a specific version
sudo apt install php8.3
Replace
8.3
with the version you need. This installs the CLI binary and the core module. For Nginx, install the FPM package for that version:
sudo apt install php8.3-fpm
You can install multiple versions simultaneously. They do not conflict because each version has its own binary (
php8.2
,
php8.3
), its own FPM service (
php8.2-fpm
,
php8.3-fpm
), and its own configuration directory (
/etc/php/8.2/
,
/etc/php/8.3/
).
Available PHP versions
At the time of writing, the Ondrej PPA provides:
| Version | Status |
|---|---|
| 8.1 | Security fixes only (EOL December 2025) |
| 8.2 | Active support |
| 8.3 | Active support (latest stable) |
| 8.4 | Active support |
Older versions (7.4, 8.0) are available in the PPA but have reached end of life and no longer receive security patches. Do not use them for new installations.
Installing PHP extensions#
A bare PHP installation does not do much. Most applications require extensions for database access, image processing, encryption, and other functionality. Extensions are installed as separate packages.
Extensions WordPress requires
WordPress needs a minimum set of extensions to function:
sudo apt install php8.3-mysql php8.3-curl php8.3-gd php8.3-mbstring php8.3-xml php8.3-zip
What each extension does:
| Extension | Purpose |
|---|---|
php-mysql
| MySQL and MariaDB database access. WordPress cannot connect to its database without this. |
php-curl
| HTTP requests. Used for plugin/theme updates, REST API calls, and external service communication. |
php-gd
| Image processing. Used for thumbnail generation, image cropping, and resizing in the media library. |
php-mbstring
| Multibyte string handling. Required for proper UTF-8 support in post content, comments, and metadata. |
php-xml
| XML parsing. Used by the WordPress importer, RSS feeds, sitemaps, and many plugins. |
php-zip
| ZIP archive handling. Required for plugin and theme installation from ZIP files. |
Additional commonly needed extensions
sudo apt install php8.3-intl php8.3-soap php8.3-bcmath php8.3-imagick php8.3-redis php8.3-opcache
| Extension | Purpose |
|---|---|
php-intl
| Internationalization functions. Required by WooCommerce and other plugins that handle currency, dates, and locale-specific formatting. |
php-soap
| SOAP protocol support. Required by some payment gateways and enterprise integrations. |
php-bcmath
| Arbitrary precision math. Used by WooCommerce for precise price calculations. |
php-imagick
| ImageMagick bindings. Better image quality than GD for thumbnail generation. WordPress uses it automatically when available. |
php-redis
| Redis client. Required if you use Redis for object caching. |
php-opcache
| Opcode caching. Caches compiled PHP bytecode so scripts do not need to be recompiled on every request. This should always be installed on production servers. |
Install all common extensions in one command
For a WordPress server with WooCommerce:
sudo apt install php8.3-fpm php8.3-mysql php8.3-curl php8.3-gd php8.3-mbstring php8.3-xml php8.3-zip php8.3-intl php8.3-soap php8.3-bcmath php8.3-imagick php8.3-opcache
List installed extensions
To see which extensions are currently loaded:
php -m
This prints every loaded extension. To check if a specific extension is installed:
php -m | grep mysql
Check extension details
To see the version and configuration of a specific extension:
php --ri mysql
The
--ri
flag prints runtime information for the named extension.
Switching between PHP versions#
If you have multiple PHP versions installed, you need to control which one is used by the CLI and which one PHP-FPM serves to the web server.
Switching the CLI version
The
update-alternatives
system manages which
php
command points to which version:
sudo update-alternatives --set php /usr/bin/php8.3
To see all available versions and pick interactively:
sudo update-alternatives --config php
This shows a numbered list. Enter the number for the version you want. The change takes effect immediately for new CLI invocations.
Verify:
php -v
Switching the web server PHP version
The CLI version and the web server version are independent. Changing the CLI version with
update-alternatives
does not affect which PHP version serves your website.
Nginx with PHP-FPM
Nginx connects to PHP-FPM through a socket defined in the Nginx site configuration. The socket path includes the PHP version:
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
To switch versions, change the socket path to the new version:
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
Then make sure the new version’s FPM service is running and restart Nginx:
sudo systemctl start php8.2-fpm
sudo systemctl restart nginx
You can optionally stop the old FPM service to free resources:
sudo systemctl stop php8.3-fpm
sudo systemctl disable php8.3-fpm
Apache with PHP-FPM
If Apache is using PHP-FPM through mod_proxy_fcgi, the process is similar: update the proxy target in the Apache configuration and restart.
If Apache is using mod_php, disable the old module and enable the new one:
sudo a2dismod php8.2
sudo a2enmod php8.3
sudo systemctl restart apache2
Running multiple versions simultaneously
On a server hosting multiple sites, you can run different PHP versions for different sites. Each PHP-FPM version runs its own service and listens on its own socket. Point each Nginx server block to the appropriate socket.
Site A on PHP 8.2:
server {
server_name sitea.com;
# ...
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
# ...
}
}
Site B on PHP 8.3:
server {
server_name siteb.com;
# ...
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
# ...
}
}
Both FPM services need to be running:
sudo systemctl enable php8.2-fpm php8.3-fpm
sudo systemctl start php8.2-fpm php8.3-fpm
Configuring PHP-FPM#
After installation, PHP-FPM’s pool configuration controls how many worker processes run and how they behave. The default pool configuration is at:
/etc/php/8.3/fpm/pool.d/www.conf
Key settings:
[www]
user = www-data
group = www-data
listen = /run/php/php8.3-fpm.sock
pm = dynamic
pm.max_children = 10
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 5
| Directive | What it controls |
|---|---|
pm
| Process manager type.
dynamic
spawns and kills workers based on demand.
static
keeps a fixed number running.
ondemand
spawns workers only when requests arrive. |
pm.max_children
| Maximum number of worker processes. Each worker handles one PHP request at a time. This is the ceiling on concurrent PHP execution. |
pm.start_servers
| Number of workers created when PHP-FPM starts. |
pm.min_spare_servers
| Minimum idle workers kept alive, ready for incoming requests. |
pm.max_spare_servers
| Maximum idle workers. Excess idle workers are killed to free memory. |
The right values depend on your server’s available memory. Each PHP-FPM worker consumes roughly 20-60 MB depending on the application. A server with 2 GB of RAM available for PHP can comfortably run 20-30 workers with a typical WordPress site.
After changing pool configuration:
sudo systemctl restart php8.3-fpm
Verifying the installation#
Check that PHP-FPM is running
sudo systemctl status php8.3-fpm
You should see
active (running)
. If it shows
failed
, check the logs:
sudo journalctl -u php8.3-fpm --no-pager -n 50
Check that the socket exists
ls -la /run/php/php8.3-fpm.sock
If the socket file does not exist, PHP-FPM is not running or is configured to listen on a different path.
Test PHP execution from the command line
php -r "echo 'PHP is working. Version: ' . phpversion() . PHP_EOL;"
Test PHP execution through the web server
Create a test file:
echo '<?php phpinfo();' | sudo tee /var/www/html/info.php
Visit
http://your-server-ip/info.php
in a browser. If you see the PHP info page, PHP-FPM and Nginx (or Apache) are communicating correctly. The page shows the PHP version, loaded extensions, and active configuration.
Delete the test file immediately after checking:
sudo rm /var/www/html/info.php
Leaving phpinfo() accessible on a production server exposes server internals to anyone who finds the URL.
Verify database connectivity
If you installed
php-mysql
for WordPress, verify it can connect to your database. The
php-mysql
extension provides both the
mysqli
and
PDO_mysql
drivers. WordPress uses
mysqli
. See MySQL vs MariaDB: which should you use for database setup and compatibility details.
Check that the extension is loaded:
php -m | grep mysqli
If
mysqli
appears in the output, the database extension is installed and loaded.
Troubleshooting#
“Unable to locate package php8.3-fpm”
The Ondrej PPA is not added, or
apt update
was not run after adding it:
sudo add-apt-repository ppa:ondrej/php
sudo apt update
sudo apt install php8.3-fpm
PHP-FPM starts but Nginx returns 502
Nginx cannot reach the PHP-FPM socket. Common causes:
- The socket path in the Nginx configuration does not match the actual socket. Check
listenin the FPM pool config andfastcgi_passin the Nginx config. - PHP-FPM is running as a different user than expected. The socket’s ownership must allow Nginx to connect.
- PHP-FPM crashed after starting. Check
journalctl -u php8.3-fpmfor errors.
Extensions not loading after installation
If
php -m
does not show a newly installed extension, the extension’s .ini file may not be in the right directory. Check:
ls /etc/php/8.3/fpm/conf.d/ | grep extension-name
Each extension typically has a .ini file like
20-mysql.ini
that enables it. If the file exists but the extension is not loading, check for errors:
php -i 2>&1 | grep -i error
After installing extensions, restart PHP-FPM:
sudo systemctl restart php8.3-fpm
The CLI picks up new extensions immediately, but PHP-FPM needs a restart because it caches the configuration at startup.
Wrong PHP version serving the site
The CLI version (
php -v
) and the web server version can differ. If your site is running on an unexpected PHP version, check the Nginx configuration for the
fastcgi_pass
socket path. The version number in the socket path (
php8.2-fpm.sock
vs
php8.3-fpm.sock
) determines which PHP version handles web requests. See How to check your PHP version and find php.ini for how to confirm which version is active from the web server’s perspective.
PHP installation on Hostney#
On Hostney, PHP is pre-installed and managed through the control panel. You do not install PHP manually or manage extensions through apt.
The PHP version is shown and changeable through Hosting > PHP Manager. Switching versions is a dropdown selection that takes effect immediately. All commonly needed extensions (mysql, curl, gd, mbstring, xml, zip, intl, imagick, opcache) are pre-installed and enabled.
PHP-FPM pool settings, memory limits, and other php.ini directives are configurable through Hosting > PHP Manager > Variables tab without SSH access.