There are no notfications.

This article was last reviewed for Debian 9 (Stretch).

PHP 7 installation and configuration for Apache 2.4 using PHP-FPM (Debian, repository)

PHP 7 installation and configuration for Apache 2.4 using PHP-FPM (Debian, repository)
Author: Stefán Örvar Sigmundsson
Initial publication:
Last updated:
Written in: English (United Kingdom)

PHP is the world's most popular server-side web development scripting language. The original and primary PHP interpreter implementation is the Zend Engine. This article will demonstrate how to install and configure PHP 7 and PHP-FPM for Apache 2.4 on Debian or its derivatives such as Ubuntu and Linux Mint. The scripting language will be configured for the domain name example.org as a virtual host.

PHP-FPM

PHP-FPM (FastCGI Process Manager) is as its name indicates a process manager for PHP over FastCGI. Apache and PHP can communicate via the FastCGI binary protocol which PHP-FPM implements along with advanced process management features.

PHP-FPM manages processes in what are called pools. A pool is a configurable unit of one or more processes that handle PHP requests. Pools can be optimised in a variety of ways to serve low to high PHP-intensity web sites. Some important features of pools are:

  • Pools are ownable by specified OS users and groups (for security reasons).
  • Pools are limitable to a minimum and maximum number of processes (for CPU performance reasons).
  • Pools are limitable to a maximum number of PHP requests per process before respawning (for RAM performance reasons).
Ideal pool and process combination
Pool Process Single web site Multiple web sites
PHP-intensity PHP-intensity Administrated
Single Single Low Low Together
Multiple High High Together
Multiple Single Impossible[1] Low Separately
Multiple High Separately
  1. ^ A single pool can serve multiple web sites but a single web site can not be served by multiple pools.

Apache modules

There are multiple Apache modules that can be used to interface with PHP 7. This article will focus on configuring mod_proxy_fcgi for the purpose of using PHP-FPM. The primary benefits of this implementation are:

  • The execution of PHP is outside of Apache and can therefore neither crash Apache nor be crashed by Apache.
  • The OS user and group running PHP can be configured either globally or per virtual host. This is a great security benefit as virtual hosts can have differing access permissions.
  • The PHP version can be configured either globally or per virtual host. This allows for multiple versions of PHP to be running on the server without conflict.
  • PHP-FPM offers advanced process management beyond the capabilities of the Zend Engine.
Implementation comparison
Apache PHP
Module Developer Package Execution User/Group Version Package
mod_php7.0 Apache Software Foundation libapache2-mod-php7.0 Inside Apache Per server Per server php7.0-common
mod_fcgid Apache Software Foundation libapache2-mod-fcgid Inside Apache Per virtual host Per virtual host php7.0-cgi[2]
mod_proxy_fcgi Apache Software Foundation Included in Apache 2.4 Outside Apache (PHP-FPM) Per virtual host Per virtual host php7.0-fpm[2]
  1. ^ a b Depends on php7.0-common and php7.0-cli.

Installation

PHP and PHP-FPM can be installed from the official Debian repository using APT:

root@computer:~# apt --assume-yes install php7.0-fpm

Configuration

PHP-FPM is stopped before beginning the configuration for the sake of simplicity:

root@computer:~# systemctl stop php7.0-fpm.service

The default log file for PHP-FPM (php7.0-fpm) is deleted and a new one (error.log) created in a dedicated directory (/var/log/php7.0-fpm/) for organisational purposes:

root@computer:~# rm /var/log/php7.0-fpm.log
root@computer:~# mkdir /var/log/php7.0-fpm/
root@computer:~# touch /var/log/php7.0-fpm/error.log

A file is created to contain the error log for PHP in a dedicated directory. PHP does not log errors by default but instead embeds them in the web pages where they occur. PHP errors and warnings should not be visible to the world for security reasons.

root@computer:~# mkdir /var/log/php7.0/
root@computer:~# touch /var/log/php7.0/error.log

A directory is created to contain the temporary files uploaded to the web server via PHP before they are saved elsewhere or discarded at the end of scripts:

root@computer:~# mkdir /var/tmp/php7.0/

There is a lot of clutter in the default configuration files even though they are operational. Clearing them will ensure that there is no conflict nor confusion:

root@computer:~# > /etc/php/7.0/fpm/php.ini
root@computer:~# > /etc/php/7.0/fpm/php-fpm.conf

The default pool created by the package is called www. A pool is created with a more descriptive name:

root@computer:~# rm /etc/php/7.0/fpm/pool.d/www.conf
root@computer:~# touch /etc/php/7.0/fpm/pool.d/example.org.conf

The default user and group assumed by the package are called www-data. A user and a group are created with a more descriptive name:

root@computer:~# useradd --comment "PHP" --shell "/usr/sbin/nologin" --system --user-group php

php.ini

The php.ini file contains PHP's primary configuration:

[PHP]

date.timezone = Atlantic/Reykjavik

display_errors = Off

error_log = /var/log/php7.0/error.log

error_reporting = 32767

log_errors = On

register_argc_argv = Off

session.gc_probability = 0

short_open_tag = Off

upload_tmp_dir = /var/tmp/php7.0/
[PHP]
Sets the configuration scope for the subsequent directives to PHP.
date.timezone = Atlantic/Reykjavik
The time zone of the server. The time zone (Atlantic/Reykjavik) should be replaced with the relevant time zone.
display_errors = Off
Disables the embedding of PHP errors and warnings in outputed HTML for security reasons.
error_log = /var/log/php7.0/error.log
A log file (/var/log/php7.0/error.log) is created to contain PHP errors and warnings.
error_reporting = 32767
A predefined construct (32767) that instructs the interpreter to log all PHP errors and warnings.
log_errors = On
Enables logging of PHP errors and warnings into the log file.
register_argc_argv = Off
Disables a CLI feature unnecessary for most users.
session.gc_probability = 0
Disables the garbage collection process to prevent session data loss. Sessions will have to be removed manually periodically.
short_open_tag = Off
Disables short form open tags for the sake of standardisation.
upload_tmp_dir = /var/tmp/php7.0/
A directory (/var/tmp/php7.0/) is created to contain uploaded files temporarily.

php-fpm.conf

The php-fpm.conf file contains PHP-FPM's primary configuration:

[global]

error_log = /var/log/php7.0-fpm/error.log

include = /etc/php/7.0/fpm/pool.d/*.conf
[global]
Sets the configuration scope for the subsequent directives to global.
error_log = /var/log/php7.0-fpm/error.log
A log file (/var/log/php-fpm/error.log) is created to contain PHP-FPM errors and warnings.
include = /etc/php/7.0/fpm/pool.d/*.conf
All process pool declaration files are included.

pool.d/example.org.conf

The pool.d/example.org.conf file contains a process pool declaration:

[example.org]

group = php

listen = 127.0.0.1:9000

pm = ondemand

pm.max_children = 5

pm.max_requests = 200

pm.process_idle_timeout = 10s

user = php
[example.org]
Sets the configuration scope for the subsequent directives to example.org.
group = php
The OS user of the process pool.
listen = 127.0.0.1:9000
The IP address and port used by Apache and PHP-FPM to communicate.
pm = ondemand
Sets the type of process manager.
pm.max_children = 5
Sets the maximum number of child processes.
pm.max_requests = 200
Sets the maximum number of requests processed per child process before respawning to reclaim leaked memory.
pm.process_idle_timeout = 10s
Sets the idle time for child processes before being killed.
user = php
The OS group of the process pool.

Conclusion

Log rotation

The package installs a default logrotate configuration file (/etc/logrotate.d/php-fpm) that can be customised:

/var/log/php7.0/*.log /var/log/php7.0-fpm/*.log
{
	copytruncate
	maxage 365
	missingok
	monthly
	notifempty
	rotate 12
}
/var/log/php7.0/*.log /var/log/php7.0-fpm/*.log
Sets the configuration scope for the subsequent section. The pattern matches all files (*) ending with the extension log in the /var/log/php7.0/ and /var/log/php7.0-fpm/ directories.
copytruncate
Copy the contents of the log file being rotated into a new file and then truncate the original log file.
maxage 365
Remove log files older than 365 days.
missingok
Do not consider it an error if a log file is missing.
monthly
Perform a log rotation monthly.
notifempty
Do not perform a log rotation on an empty log file.
rotate 12
Perform 12 log rotations before older log files are removed.

Apache configuration

This article assumes that the Apache installation is compatible and that its configuration has not been altered significantly.

Virtual host

A directive is added to the virtual host to map PHP-FPM to Apache so that all PHP files be passed off to PHP-FPM for processing:

ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/srv/http/example.org/$1

Directory indexing

The dir module defines directory index files. If a directory index file exists in a directory and a user navigates to the directory without specifying a particular file within it then the server will return the directory index file instead of an automatically generated index of the contents of the directory by the autoindex module or an HTTP 403 response status code.

<IfModule dir_module>
	DirectoryIndex index.php index.htm index.html index.xht index.xhtml
</IfModule>

Note that Apache will not generate a directory index for a directory when a user navigates to it without specifying a particular file within it if index.php is defined as a directory index and PHP-FPM is being used as a proxy server for the relevant virtual host. This is because functionality related to PHP is passed off to the proxy and PHP-FPM has no index generating feature. Instead a simple "File not found." message is returned to the user by PHP-FPM and Apache logs an error similar to the following:

[proxy_fcgi:error] AH01071: Got error 'Primary script unknown\n'

Configuration enablement

The implementation requires that the proxy and proxy_fcgi modules be enabled:

root@computer:~# a2enmod proxy proxy_fcgi

Reinitiation

Apache is restarted when the configuration is done:

root@computer:~# systemctl reload apache2.service

Directory ownership and permissions

The configuration directory should be protected:

root@computer:~# chown --recursive root:adm /etc/php/
root@computer:~# chmod --recursive 0770 /etc/php/

The log directories should be protected:

root@computer:~# chown --recursive php:adm /var/log/php7.0/
root@computer:~# chown --recursive php:adm /var/log/php7.0-fpm/
root@computer:~# chmod --recursive 0770 /var/log/php7.0/
root@computer:~# chmod --recursive 0770 /var/log/php7.0-fpm/

The temporary upload directory should be protected:

root@computer:~# chown --recursive php:php /var/tmp/php7.0/
root@computer:~# chmod --recursive 0770 /var/tmp/php7.0/

Process manager initiation

PHP-FPM is started when the configuration is done:

root@computer:~# systemctl start php7.0-fpm.service

See also

External links

This article has additional content here.