PHP Basic Setup on Ubuntu

From WikiMLT

PHP ver­sion and repos­i­to­ries

By de­fault Ubun­tu 22.04 sup­ports PHP 8.x. We can check that by the fol­low­ing com­mand.

apt-cache policy php

In or­der to in­stall any sup­port­ed (ac­tive) PHP ver­sions on Ubun­tu in­de­pen­dent of the ver­sion of the OS we could use the third par­ty repos­i­to­ry On­drej PPA.

sudo add-apt-repository ppa:ondrej/php
sudo apt update

List and in­stall PHP pack­ages

Here is a script that will cre­ate a list of the PHP and re­lat­ed pack­ages in­stalled on the sys­tem.

PHP_VER="8.1"
OS_VER="$(lsb_release -ir | grep -oP ':\s+\K.*' | awk '{print tolower($0)}' | sed -z 's/\n/./')"
for pkg in $(sudo apt-cache policy *php${PHP_VER}* | grep -P "^(lib.*|php)${PHP_VER}.*:$" | sed 's/:$//');
do echo "$pkg";
done | tee /tmp/list-of-php${PHP_VER}-pkgs-${OS_VER}.txt

The lists of the PHP pack­ages that should be in­stalled on the serv­er to run CMS as Word­Press and Me­di­aWi­ki, and oth­er ser­vices like as NextCloud, Plex and more, are the fol­low:

Some of the pack­ages, pro­vid­ed in the lists above, are de­pen­den­cies of oth­er and will be au­to­mat­i­cal­ly in­stalled. We ca use the fol­low­ing com­mands to in­stall the core pack­ages list.

PHP_VER="8.1"
sudo apt install -y php${PHP_VER} php${PHP_VER}-cli php${PHP_VER}-fpm
sudo apt install -y php${PHP_VER}-mbstring php${PHP_VER}-gd php${PHP_VER}-zip 
sudo apt install -y php${PHP_VER}-iconv php${PHP_VER}-simplexml 
sudo apt install -y php${PHP_VER}-xmlreader php${PHP_VER}-mysql
sudo apt install -y php${PHP_VER}-curl php${PHP_VER}-xml php${PHP_VER}-xmlrpc 
sudo apt install -y php${PHP_VER}-imagick php${PHP_VER}-bcmath php${PHP_VER}-dom
sudo apt install -y php${PHP_VER}-exif php${PHP_VER}-fileinfo php${PHP_VER}-json
sudo apt install -y php${PHP_VER}-apcu php${PHP_VER}-mcrypt php${PHP_VER}-intl
sudo php${PHP_VER} -m | grep 'apcu\|mcrypt'  # Test does specific expensions are installed
apcu
mcrypt

Mi­grate to a new­er PHP ver­sion

Ap­proach 1

Gen­er­ate a list and in­stall the new pack­ages on the fly.

OLD_PHP_VER="7.4"; NEW_PHP_VER="8.1"
for pkg in $(sudo apt-cache policy *php${OLD_PHP_VER}* | grep -P "^(lib.*|php)${OLD_PHP_VER}.*:$" | sed -e 's/:$//' -e "s/${OLD_PHP_VER}/${NEW_PHP_VER}/");
do sudo apt install "$pkg" -y;
done 2>/tmp/php${NEW_PHP_VER}.install.error.log

Ap­proach 2

Use pre­vi­ous­ly gen­er­at­ed list to in­stall the new pack­ages.

OLD_PHP_VER="7.4"; NEW_PHP_VER="8.1"
while IFS= read -r pkg;
do sudo apt install "${pkg/$OLD_PHP_VER/$NEW_PHP_VER}" -y;
done </tmp/list-of-php7.4-pkgs-ubuntu.22.04.txt 2>/tmp/php${NEW_PHP_VER}.install.error.log

Re­move the old ver­sion

REMOVE_PHP_VER="7.4"
# remove 'echo' to apply the actual changes
for pkg in $(sudo apt-cache policy *php${REMOVE_PHP_VER}* | grep -P "^(lib.*|php)${REMOVE_PHP_VER}.*:$" | sed 's/:$//');
do echo sudo apt remove -y "$pkg"; 
done 2>/tmp/php${REMOVE_PHP_VER}.remove.error.log

PHP Con­fig­u­ra­tion

CLI Ver­sion

sudo nano /etc/php/8.1/cli/php.ini
# Thin Server 1G                            # Normal Server 16G     # Default
opcache.enable = 1                          # 1                     # 1
opcache.enable_cli = 1                      # 0                     # 0
sudo nano /etc/php/8.1/mods-available/apcu.ini
extension=apcu.so
apc.enable_cli=1

Some ser­vices as NextCloud/cron.php are us­ing Memcache\APCu in the com­mand line. In case it is not en­abled by the con­fig­u­ra­tion, as it is shown above, the CLI com­mand can en­able this pa­ra­me­ter for a while.

sudo -u www-data php --define apc.enable_cli=1 /var/www/nextcloud/occ maintenance:repair

Set CLI Ver­sion

sudo update-alternatives --set php /usr/bin/php8.1 && php -v

Apache2 Mod­ule

The con­fig­u­ra­tion file for the mod­ule liba­pache2-mod-php is /etc/php/8.1/apache2/php.ini. My prefer­able con­fig­u­ra­tion is the same as the PHP-FPM's con­fig­u­ra­tion – fpm/php.ini, for this rea­son it is not ex­plic­it­ly list­ed here. This file wont be used when PHP-FPM is in use, but it's good to be con­fig­ured in case you switch to liba­pache2-mod-php for some rea­son.

PHP-FPM Ser­vice

My prefer­able con­fig­u­ra­tion is shown be­low.

sudo nano /etc/php/8.1/{fpm,apache2}/php.ini
# Thin Server 1G                            # Normal Server 16G     # Default
zlib.output_compression = On                # On                    # Off
max_execution_time = 600                    # 600                   # 30
max_input_time = 120                        # 120                   # 60
max_input_vars = 3000                       # 3000                  # 1000
memory_limit = 256M                         # 2048M                 # 128M
post_max_size = 128M                        # 1024M                 # 8M        
upload_max_filesize = 128M                  # 512M                  # 2M
max_file_uploads = 40                       # 80                    # 20
allow_url_fopen = On                        # On                    # On
default_socket_timeout = 360                # 360                   # 60
pcre.backtrack_limit = 400000               # 400000                # 100000
session.cookie_secure = True                # True                  # True
session.gc_maxlifetime = 14400              # 14400                 # 1440 (seconds)
session.cache_expire = 540                  # 540                   # 180  (minutes)
mbstring.encoding_translation = On          # On                    # Off
opcache.enable = 1                          # 1                     # 1
opcache.enable_cli = 1                      # 0                     # 0
opcache.memory_consumption = 256            # 2048                  # 128
opcache.interned_strings_buffer = 64        # 256                   # 8
opcache.max_accelerated_files = 1000000     # 1000000               # 10000
  • Ac­cord­ing to the val­ue of opcache.memory_consumption – for a sin­gle small site about 50 MB should be enough. For ex­am­ple, a serv­er that run about 10 in­stances of MediaWiki/​​​WordPress con­sumes about 500 MB. Ref: Zen­dOP­cache.

PHP-FPM ser­vice spe­cif­ic con­fig­u­ra­tion.

sudo nano /etc/php/8.1/fpm/pool.d/www.conf
# Thin Server 1G                            # Normal Server 16G     # Default
pm.max_children = 50                        # 100                   # 5
pm.start_servers = 4                        # 8                     # 2
pm.min_spare_servers = 2                    # 2                     # 1
pm.max_spare_servers = 6                    # 9                     # 3
pm.max_requests = 1000                      # 2000                  # 500
;php_admin_value[memory_limit] = 512M       # 2048M                 # 32M
  • php_admin_value[memory_limit] – ac­cord­ing to the doc­u­men­ta­tion of NextCloud the val­ue should be at least 512M. The val­ue -1, re­moves the lim­it. Not set ; means, the rel­e­vant val­ue from php.ini is in used.

PHP and Apache2 – PHP-FPM, HTTP2

It is prefer­able to use PHP-FPM in­stead the Apache's PHP mod­ule. PHP-FPM is the mod­ern way to han­dle PHP files – it is faster, it sup­ports HTTP2 and so on.

In or­der to dis­able the Apache2 PHP mod­ule – liba­pache2-mod-php, and pre­pare for PHP-FPM ex­e­cute the fol­low­ing com­mands.

sudo a2dismod php8.1 mpm_prefork mpm_worker
sudo a2enmod headers rewrite ssl setenvif http2 dav_fs expires ext_filter proxy_fcgi mpm_event

I al­so pre­fer to do not en­able phpX.X‑fpm con­fig­u­ra­tion by de­fault.

sudo a2disconf php8.1-fpm

Thus we can en­able dif­fer­ent PHP ver­sions for the dif­fer­ent vir­tu­al hosts when it is need­ed. So at the vir­tu­al host lev­el we can use the fol­low­ing di­rec­tives.

# Redirect to local php-fpm if mod_php is not available
# The variable PHP_IS_ENABLED is set in apache2.conf
<IfDefine !PHP_IS_ENABLED>
    Include /etc/apache2/conf-available/php8.1-fpm.conf
</IfDefine>
#apache2.conf
# Define a variable flag if mod_php is enabled
# Then use it in the VH configuration to trigger 'php_flag' enable/disable...
# https://stackoverflow.com/questions/39450760/how-to-check-in-htaccess-if-php-is-enabled
<IfModule mod_php.c>
    Define PHP_IS_ENABLED
</IfModule>
<IfModule mod_php5.c>
    Define PHP_IS_ENABLED
</IfModule>
<IfModule mod_php7.c>
    Define PHP_IS_ENABLED
</IfModule>
<IfModule mod_php8.c>
    Define PHP_IS_ENABLED
</IfModule>

En­able and Start PHP-FPM Ser­vice

To en­able and start the PHP-FPM ser­vice use the fol­low­ing com­mands. Note in this ex­am­ple two PHP ver­sions are in use.

sudo systemctl enable --now php7.4-fpm.service
sudo systemctl enable --now php8.1-fpm.service

When the mod­ule liba­pache2-mod-php is in use, to ap­ply some changes of the PHP con­fig­u­ra­tion the Apache ser­vice must be restart­ed. When php-fpm is in use we can restart just its ser­vice to ac­com­plish the same task. How­ev­er dur­ing the ini­tial set­up I would restart them both few times…

sudo systemctl restart apache2.service
sudo systemctl restart nginx.service
# sudo systemctl restart php7.4-fpm.service
sudo systemctl restart php8.1-fpm.service
sudo systemctl restart php8.2-fpm.service

Ref­er­ences

Er­rors solv­ing: