Differences between revisions 5 and 6
Revision 5 as of 2020-07-11 14:19:21
Size: 4223
Comment:
Revision 6 as of 2020-07-11 18:05:01
Size: 4560
Comment:
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
## page was renamed from FastCGISetup
Line 5: Line 4:

See [[PHPFPMConfiguration|here]] for configuration of PHP-FPM.

<<TableOfContents>>
Line 10: Line 13:
== Setup Directory == == Installation ==
Line 12: Line 15:
The recommendation is to either serve web content from: To install PHP-FPM on a system, use your local package to manager to grab all of the following: `php`, `php-fpm`, `fcgiwrap`, and `nginx`.
Line 14: Line 17:
 * a dedicated top-level directory (such as `/srv`) that can be ''easily'' separately-mounted with special settings (i.e. `ro`--the read-only fstab option)
 * the traditional web content directory, `/var/www`
Often `apache2-utils` (a.k.a. `apache-tools`, `httpd-utils`, etc... consult your package manager!) is also necessary, for creating `.htpasswd` files.
Line 17: Line 19:
Note that any directory can be a mounted device, but there are additional considerations. Many package managers expect standard directories to be writable.



=== Setup Test Script ===

Write the below to `cgi/test.php`, under whichever directory structure you prefer.

{{{
<?php phpinfo(); ?>
}}}

----



== Setup User ==

Linux permissions and restrictions are most easily done through users, groups, and umasks. The recommendation is to set a specific user and group for the web service. The common options are `www-data` (Apache) and `http` (PHP).

Depending on your ditro, these users and groups may already be created. See details on running `useradd` and `groupadd` in UserSetup.

The directory and files setup above should be owned by this user.

----



== Setup Software ==

At a minimum, we need: php, php-fpm, fcgi, fcgiwrap, and nginx.

Common additional tools include:
 * apache2-utils (a.k.a. apache-tools, httpd-utils, etc.) for creating .htpasswd files for basic restrictions
Upstream manages a Docker file with frequent security patching, as `bitnami/php-fpm:latest`. This will expose PHP-FPM on port 9000 and generally work out of the box.
Line 56: Line 25:
The primary configuration for PHP is found in `/etc/php/php.ini`. Some distributions carry two versions: PHP-FPM unsurprisingly runs in '''PHP''' and will require a working installation. The primary configuration for PHP is found at `/etc/php/php.ini`. Some distributions provide two versions: a hardened `php.ini-production` and a verbose `php.ini-development`.
Line 58: Line 27:
 * `php.ini-production` which is more secure
 * `php.ini-development` which is more backwards-compatible, and includes sensitive details in debugging messages
See [[PHPConfiguration|here]] for help in configuring PHP.
Line 61: Line 29:
Chuck the latter straight into the bin.

Some key directives to check:

{{{
; Block calls from crafted URLs (i.e., `example.com/something-malicious.php`)
cgi.force_redirect = On

; Disable access to filesystem
file_uploads = Off

; Disable remote data retrieval
allow_url_fopen = Off
allow_url_include = Off
}}}
The upstream Docker image bundles PHP internally, but it is ''possible'' to un-bundle it and force the use of an existing installation.
Line 81: Line 35:
PHP-FPM is configured by a system configuration (`/etc/php/php-fpm.conf`) and by pool configurations (`/etc/php/php-fpm.d/*.conf`).

For the most part, the system configuration works out of the box.
For the most part, distributed configuration for PHP-FPM work out of the box.
Line 93: Line 45:
The pool configuration will need to be adjusted according to the user that was setup above.

{{{
; User/group of processes
user = www-data
group = www-data

; Socket file
listen = /run/php-fpm/php-fpm.pid

; User/group of sockets
listen.owner = www-data
listen.group = www-data

; Restrictions on file extensions
security.limit_extensions = .cgi .php

; Access log
access.log = /var/log/php-fpm/access.log
}}}
Line 116: Line 48:
=== FastCGI and FCGIWrap === === FCGIWrap ===
Line 118: Line 50:
FastCGI takes a large number of parameters within NGINX configurations, so it is commonly 'configured' with `/etc/nginx/fastcgi_params`. This file should be created by default and should work by default. '''FCGIWrap''' is, as the name implies, a wrapper script. It manages the configuration of FastCGI through PHP-FPM so that all you need to do is point NGINX at `/run/fcgiwrap.sock`.
Line 120: Line 52:
FCGIWrap is, as the name implies, a wrapper around FastCGI. It will work without configuration. At the same time, it is ''entirely'' optional. The upstream Docker image does not include it. Not using '''FCGIWrap''' will require more attention on the [[PHPFPMConfiguration|configuration of PHP-FPM]], however.
Line 161: Line 93:
---- === Test Script ===
Line 163: Line 95:
A minimal test script to validate the PHP installation.
Line 164: Line 97:

== Startup ==
{{{
<?php phpinfo(); ?>
}}}
Line 171: Line 105:
== Maintenance == == Security ==

=== Work Directory ===

PHP applications can be placed anywhere on the web root and they will work as expected. This is because PHP-FPM defaults to working in the current work directory.

However, it is ''recommended'' to isolate PHP-FPM by running it in a different work directory. This is accomplished by configuring PHP-FPM on a pool level, which you can read more about [[PHPFPMConfiguration#PoolConfiguration|here]]. What needs to be addressed up-front is how a web server will interact with an isolated FastCGI environment.

The NGINX `try_files` command, as shown below, checks for existence of files. This will cause issues if PHP applications are actually living in a different directory (or a different server). However, without checking for the existence of an executable, you can run into difficult-to-debug errors and security issues regarding embedded PHP in ordinary files.

The workaround is to set the key FastCGI parameters for the target server and check the URI against local null files.

{{{
location ~ \.php(/|$) {
    fastcgi_split_path_info ^(.+?\.php)(/.*)$;
    fastcgi_param SCRIPT_FILENAME /remote/path/to/work/directory/$fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;

    try_files $uri =404;

    fastcgi_pass 192.168.86.1:9000;
    include fastcgi_params;
}
}}}

Note that `try_files` is called ''strictly after'' path info has been pulled out. Try files will, on success, overwrite `$uri` with the matched local URI.



=== HTTPoxy ===

{{{
location ~ \.php(/|$) {
    # Mitigate https://httpoxy.org/ vulnerabilities
    fastcgi_param HTTP_PROXY "";
}
}}}

PHP-FPM Setup

PHP-FPM is a PHP implementation of the FastCGI, an enhancement of the earlier Common Gateway Interface (CGI). It works especially well with NGINX.

See here for configuration of PHP-FPM.


Installation

To install PHP-FPM on a system, use your local package to manager to grab all of the following: php, php-fpm, fcgiwrap, and nginx.

Often apache2-utils (a.k.a. apache-tools, httpd-utils, etc... consult your package manager!) is also necessary, for creating .htpasswd files.

Upstream manages a Docker file with frequent security patching, as bitnami/php-fpm:latest. This will expose PHP-FPM on port 9000 and generally work out of the box.

PHP

PHP-FPM unsurprisingly runs in PHP and will require a working installation. The primary configuration for PHP is found at /etc/php/php.ini. Some distributions provide two versions: a hardened php.ini-production and a verbose php.ini-development.

See here for help in configuring PHP.

The upstream Docker image bundles PHP internally, but it is possible to un-bundle it and force the use of an existing installation.

PHP-FPM

For the most part, distributed configuration for PHP-FPM work out of the box.

; Pid file
pid = /run/php-fpm/php-fpm.pid

; Error log
error_log = /var/log/php-fpm.log

FCGIWrap

FCGIWrap is, as the name implies, a wrapper script. It manages the configuration of FastCGI through PHP-FPM so that all you need to do is point NGINX at /run/fcgiwrap.sock.

At the same time, it is entirely optional. The upstream Docker image does not include it. Not using FCGIWrap will require more attention on the configuration of PHP-FPM, however.

NGINX

For more details on NGINX configuration, see this walkthrough. A basic configuration for FastCGI would be:

user www-data www-data;
http {
  include mime.types;
  default_type application/mime.types;

  sendfile on;
  keepalive_timeout 65;
  gzip on;

  server {
    listen 80;
    server_name example.com;
    access_log /var/log/nginx/example.com/access.log;
    error_log /var/log/nginx/example.com/error.log;

    root /var/www;
    try_files $uri @cgi;

    location @cgi {
      include fastcgi_params;
      fastcgi_param SCRIPT_FILENAME $realpath_root/my-cgi-script.cgi;
      fastcgi_param PATH_INFO $uri;
      fastcgi_param QUERY_STRING $args;
      fastcgi_param HTTP_HOST $server_name;
      fastcgi_pass unix:/run/fcgiwrap.sock;
    }
  }
}

Test Script

A minimal test script to validate the PHP installation.

<?php phpinfo(); ?>


Security

Work Directory

PHP applications can be placed anywhere on the web root and they will work as expected. This is because PHP-FPM defaults to working in the current work directory.

However, it is recommended to isolate PHP-FPM by running it in a different work directory. This is accomplished by configuring PHP-FPM on a pool level, which you can read more about here. What needs to be addressed up-front is how a web server will interact with an isolated FastCGI environment.

The NGINX try_files command, as shown below, checks for existence of files. This will cause issues if PHP applications are actually living in a different directory (or a different server). However, without checking for the existence of an executable, you can run into difficult-to-debug errors and security issues regarding embedded PHP in ordinary files.

The workaround is to set the key FastCGI parameters for the target server and check the URI against local null files.

location ~ \.php(/|$) {
    fastcgi_split_path_info ^(.+?\.php)(/.*)$;
    fastcgi_param SCRIPT_FILENAME /remote/path/to/work/directory/$fastcgi_script_name;
    fastcgi_param PATH_INFO       $fastcgi_path_info;

    try_files $uri =404;

    fastcgi_pass 192.168.86.1:9000;
    include fastcgi_params;
}

Note that try_files is called strictly after path info has been pulled out. Try files will, on success, overwrite $uri with the matched local URI.

HTTPoxy

location ~ \.php(/|$) {
    # Mitigate https://httpoxy.org/ vulnerabilities
    fastcgi_param HTTP_PROXY "";
}


CategoryRicottone

PHP/FPM (last edited 2023-05-25 17:00:50 by DominicRicottone)