This article was last reviewed for Debian 9 (Stretch).
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).
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 |
- ^ 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.
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] |
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