Difference between revisions of "Install PHP"

From UNPM.org Wiki
Jump to navigation Jump to search
Line 32: Line 32:
  
 
Add:
 
Add:
<syntaxhighlight lang="bash">
+
 
apc.shm_size = 128M
+
apc.shm_size = 128M
</syntaxhighlight>
 
  
 
==== www.conf ====
 
==== www.conf ====
Line 43: Line 42:
  
 
Change:
 
Change:
<syntaxhighlight lang="bash">
+
 
request_terminate_timeout = 300
+
request_terminate_timeout = 300
</syntaxhighlight>
 
  
 
==== php.ini ====
 
==== php.ini ====
Line 52: Line 50:
  
 
Change:
 
Change:
<syntaxhighlight lang="bash">
 
post_max_size = 20M
 
</syntaxhighlight>
 
  
<syntaxhighlight lang="bash">
+
post_max_size = 20M
cgi.fix_pathinfo = 0
 
</syntaxhighlight>
 
  
<syntaxhighlight lang="bash">
+
cgi.fix_pathinfo = 0
max_execution_time = 300
 
</syntaxhighlight>
 
  
<syntaxhighlight lang="bash">
+
max_execution_time = 300
upload_max_filesize = 20M
 
</syntaxhighlight>
 
  
<syntaxhighlight lang="bash">
+
upload_max_filesize = 20M
session.save_handler = memcache
 
</syntaxhighlight>
 
  
<syntaxhighlight lang="bash">
+
session.save_handler = memcache
session.save_path = unix:/tmp/memcached.sock
+
 
</syntaxhighlight>
+
session.save_path = unix:/tmp/memcached.sock
  
 
While editing the file, it isn't a bad idea to turn off <code>expose_php</code>, which reports the version of PHP being used, however, this is not perfect protection from revealing such information, but easy enough to do.
 
While editing the file, it isn't a bad idea to turn off <code>expose_php</code>, which reports the version of PHP being used, however, this is not perfect protection from revealing such information, but easy enough to do.
Line 91: Line 78:
  
 
Change:
 
Change:
<syntaxhighlight lang="bash">
 
# -p 11211
 
</syntaxhighlight>
 
  
 +
# -p 11211
 +
 +
# -l 127.0.0.1
  
<syntaxhighlight lang="bash">
 
# -l 127.0.0.1
 
</syntaxhighlight>
 
 
At the bottom, add:
 
At the bottom, add:
<syntaxhighlight lang="bash">
+
 
-s /tmp/memcached.sock
+
-s /tmp/memcached.sock
-a 666
+
-a 666
</syntaxhighlight>
 
  
 
=== Configure nginx ===
 
=== Configure nginx ===
Line 112: Line 95:
  
 
Add to the file:
 
Add to the file:
<syntaxhighlight lang="bash">
 
upstream php5.6-fpm-sock {
 
    server unix:/run/php/php5.6-fpm.sock;
 
}
 
  
</syntaxhighlight>
+
upstream php5.6-fpm-sock {
 +
    server unix:/run/php/php5.6-fpm.sock;
 +
}
  
 
Adding some new settings to the <code>fastcgi_params</code> can prevent problems that occur with some web applications:
 
Adding some new settings to the <code>fastcgi_params</code> can prevent problems that occur with some web applications:
Line 124: Line 105:
  
 
Add to the bottom of the file:
 
Add to the bottom of the file:
<syntaxhighlight lang="bash">
+
 
fastcgi_buffer_size 128k;
+
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
+
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
+
fastcgi_busy_buffers_size 256k;
</syntaxhighlight>
+
 
  
 
Now nginx will need to know to look for PHP index files.
 
Now nginx will need to know to look for PHP index files.
Line 135: Line 116:
  
 
Change:
 
Change:
<syntaxhighlight lang="bash">
+
 
index index.html index.htm index.php;
+
index index.html index.htm index.php;
</syntaxhighlight>
+
 
  
 
==== Telling nginx to pass PHP files ====
 
==== Telling nginx to pass PHP files ====
Line 146: Line 127:
  
 
===== Least secure: =====
 
===== Least secure: =====
<syntaxhighlight lang="bash">
+
 
server {
+
server {
    ...
+
    ...
    location ~ \.php$ {
+
    location ~ \.php$ {
        <PHP configuration>
+
        <PHP configuration>
    }
+
    }
}
+
}
</syntaxhighlight>
 
  
 
This is most insecure because it passes all <code>.php</code> files in the site's directory to the PHP interpreter unless a location is specifically denied. If a hacker is able to write or rewrite any file in the site's directory, then the hacker can navigate to <tt>www.example.com/hackedfile.php</tt> and run the malicious code.
 
This is most insecure because it passes all <code>.php</code> files in the site's directory to the PHP interpreter unless a location is specifically denied. If a hacker is able to write or rewrite any file in the site's directory, then the hacker can navigate to <tt>www.example.com/hackedfile.php</tt> and run the malicious code.
  
 
===== Improved, but still vulnerable: =====
 
===== Improved, but still vulnerable: =====
<syntaxhighlight lang="bash">
+
 
server {
+
server {
    ...
+
    ...
    location ~ /subdirectory/.*\.php$ {
+
    location ~ /subdirectory/.*\.php$ {
        <PHP configuration>
+
        <PHP configuration>
    }
+
    }
}
+
}
</syntaxhighlight>
 
  
 
This configuration is often provided with some specific <code>location</code> blocks with <code>deny all</code> and <code>default_type text/plain</code> statements. Although more secure than allowing all <code>.php</code> files in the site's root directory be passed to the PHP interpreter, it still leaves the vulnerability of any <code>.php</code> file altered or added to the <code>/subdirectory/</code> as being a vector for attack. It is also impossible to use this method when installing a PHP package as a site's home page, since the <code>/subdirectory/</code> is in fact the site's root directory.
 
This configuration is often provided with some specific <code>location</code> blocks with <code>deny all</code> and <code>default_type text/plain</code> statements. Although more secure than allowing all <code>.php</code> files in the site's root directory be passed to the PHP interpreter, it still leaves the vulnerability of any <code>.php</code> file altered or added to the <code>/subdirectory/</code> as being a vector for attack. It is also impossible to use this method when installing a PHP package as a site's home page, since the <code>/subdirectory/</code> is in fact the site's root directory.
  
 
===== Very secure: =====
 
===== Very secure: =====
<syntaxhighlight lang="bash">
 
server {
 
    ...
 
    location = /directoryname/file.php$ {
 
        <PHP configuration>;
 
    }
 
  
    location /directoryname/ {
+
server {
        location ~ \.php$ { deny all; }
+
    ...
    }
+
    location = /directoryname/file.php$ {
}
+
        <PHP configuration>;
</syntaxhighlight>
+
    }
 +
 +
    location /directoryname/ {
 +
        location ~ \.php$ { deny all; }
 +
    }
 +
}
  
 
Or:
 
Or:
<syntaxhighlight lang="bash">
+
 
server {
+
server {
    ...
+
    ...
    location /directoryname/ {
+
    location /directoryname/ {
        location ~ (filename1|filename2|filename3).*\.php$ {
+
        location ~ (filename1|filename2|filename3).*\.php$ {
            <PHP configuration>;
+
            <PHP configuration>;
        }
+
        }
        location ~ \.php$ { deny all; }
+
        location ~ \.php$ { deny all; }
    }
+
    }
}
+
}
</syntaxhighlight>
 
  
 
These configurations pass only specific files to the PHP interpreter, thus a hacker will have to change those specific files to pass malicious code.
 
These configurations pass only specific files to the PHP interpreter, thus a hacker will have to change those specific files to pass malicious code.
Line 215: Line 192:
  
 
Add:
 
Add:
<syntaxhighlight lang="bash">
+
 
try_files $uri =404;
+
try_files $uri =404;
include fastcgi_params;
+
include fastcgi_params;
fastcgi_read_timeout 300;
+
fastcgi_read_timeout 300;
fastcgi_pass php5.6-fpm-sock;
+
fastcgi_pass php5.6-fpm-sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_intercept_errors on;
+
fastcgi_intercept_errors on;
</syntaxhighlight>
 
  
 
And create the HTTPS file:
 
And create the HTTPS file:
Line 228: Line 204:
  
 
Add:
 
Add:
<syntaxhighlight lang="bash">
+
 
try_files $uri =404;
+
try_files $uri =404;
include fastcgi_params;
+
include fastcgi_params;
fastcgi_read_timeout 300;
+
fastcgi_read_timeout 300;
fastcgi_pass php5.6-fpm-sock;
+
fastcgi_pass php5.6-fpm-sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_intercept_errors on;
+
fastcgi_intercept_errors on;
fastcgi_param HTTPS on;
+
fastcgi_param HTTPS on;
</syntaxhighlight>
 
  
 
===== Configure PHP test & info location =====
 
===== Configure PHP test & info location =====
Line 245: Line 220:
  
 
In the HTTPS server block:
 
In the HTTPS server block:
<syntaxhighlight lang="bash">
+
 
    location ~ phpinfo.php {
+
    location ~ phpinfo.php {
        include global-configs/php_https.conf;
+
        include global-configs/php_https.conf;
    }
+
    }
</syntaxhighlight>
 
  
 
For the actual <code>phpinfo.php</code> entries, it may be more convenient to enter everything on one line, this way the entry can be easily commented or uncommented for various testing purposes.
 
For the actual <code>phpinfo.php</code> entries, it may be more convenient to enter everything on one line, this way the entry can be easily commented or uncommented for various testing purposes.
  
 
In the HTTPS server block, add:
 
In the HTTPS server block, add:
<syntaxhighlight lang="bash">
+
 
    location ~ phpinfo.php { include /etc/nginx/global-configs/php_https.conf; }
+
    location ~ phpinfo.php { include /etc/nginx/global-configs/php_https.conf; }
</syntaxhighlight>
+
 
  
 
Reboot the server.
 
Reboot the server.
Line 272: Line 246:
  
 
Add the following line:
 
Add the following line:
<syntaxhighlight lang="php">
+
 
<?php phpinfo(); ?>
+
<?php phpinfo(); ?>
</syntaxhighlight>
 
  
 
Navigate to <tt><nowiki>http://www.example.com/phpinfo.php</nowiki></tt> and <tt><nowiki>https://www.example.com/phpinfo.php</nowiki></tt>, which should bring up the long list of PHP settings. Testing both is necessary to verify everything is working properly.
 
Navigate to <tt><nowiki>http://www.example.com/phpinfo.php</nowiki></tt> and <tt><nowiki>https://www.example.com/phpinfo.php</nowiki></tt>, which should bring up the long list of PHP settings. Testing both is necessary to verify everything is working properly.

Revision as of 23:40, 21 November 2018

PHP is a common scripting language and a staple in modern web servers. Nearly all popular web applications are written in PHP.

This article will install PHP onto an Ubuntu 16.04 server that has been configured per the previous articles in this series.

Most of the article will require root privileges.

username@servername:~$ sudo -i

Install and configure PHP

To get the latest version of PHP, install the following PPA and run an update:

root@servername:~# add-apt-repository ppa:ondrej/php && aptitude update && aptitude upgrade

Note that this PPA will be updated much more frequently than the official repositories are updated. Each time the PHP packages are updated by the owner of the PPA, the update will want to replace several of the PHP files modified below, but will ask what to do before completing the update. The best way to handle this is to look at the difference between the installed files and the new files. If the changes the update makes are only to replace the user modified settings and change settings that are commented out (annotated with ;), then it may be easier to keep the installed version instead of allowing the update to replace them and then making the changes again.

Install the packages for PHP and memcached. Memcached is used to make PHP sites load faster while consuming less resources. This set of PHP packages provides for a baseline install of PHP. Some software packages may require additional PHP packages.

root@servername:~# aptitude install libpcre3-dev make memcached php-apcu php-apcu-bc php-memcache php5.6-fpm php5.6-bz2 php5.6-curl php5.6-dev php5.6-gd php5.6-mbstring php5.6-mcrypt php5.6-xml php5.6-zip

Package dependencies will force php7.1-cli and associated packages to be installed. This will make 7.1 the default for command line. To change this to 5.6, run the following command:

root@servername:~# update-alternatives --set php /usr/bin/php5.6

Configure PHP

apc.ini

Increase the amount of RAM PHP can use by editing apcu.ini. Depending on available system RAM, this number can be higher or lower, but 128 MB is generally a good place to start.

root@servername:~# nano /etc/php/5.6/mods-available/apcu.ini

Add:

apc.shm_size = 128M

www.conf

Prevent 504 gateway timeouts

root@servername:~# nano /etc/php/5.6/fpm/pool.d/www.conf

Change:

request_terminate_timeout = 300

php.ini

root@servername:~# nano /etc/php/5.6/fpm/php.ini

Change:

post_max_size = 20M
cgi.fix_pathinfo = 0
max_execution_time = 300
upload_max_filesize = 20M
session.save_handler = memcache
session.save_path = unix:/tmp/memcached.sock

While editing the file, it isn't a bad idea to turn off expose_php, which reports the version of PHP being used, however, this is not perfect protection from revealing such information, but easy enough to do.

The post_max_size setting in /etc/php5/fpm/php.ini limits the maximum size POST (total data being uploaded - can be multiple files in one upload) through a PHP application. The default setting is 8 MB. This is different from the upload_max_filesize setting which determines the largest size for each file, which has a default setting of 2 MB. Many applications will have their own settings for maximum upload size, but administrators should keep in mind that both nginx and PHP have configurable limits. Some applications require larger sizes to run properly, particularly true for phpMyAdmin when uploading and installing databases. For this reason this guide recommends higher limits than default.

Changing cgi.fix_pathinfo = 0 forces the PHP interpreter to only process the literal file path. This is an important security issue because otherwise an uploaded file that contains malicious code may be run.[1]

The session.save_handler and session.save_path settings can be configured to allow memcached to manage sessions. This means that user sessions will be served from RAM instead of the hard drive. In the event of a reboot of memcached, all session data will be lost. However, using memcached will increase the performance of the server.

Configure memcached

Some changes must be made to the memcached configuration file.

root@servername:~# nano /etc/memcached.conf

Change:

# -p 11211
# -l 127.0.0.1

At the bottom, add:

-s /tmp/memcached.sock
-a 666

Configure nginx

Create a new file in the nginx /conf.d/ directory for PHP.

root@servername:~# nano /etc/nginx/conf.d/php-sock.conf

Add to the file:

upstream php5.6-fpm-sock {
    server unix:/run/php/php5.6-fpm.sock;
}

Adding some new settings to the fastcgi_params can prevent problems that occur with some web applications:

root@servername:~# nano /etc/nginx/fastcgi_params

Add to the bottom of the file:

fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;


Now nginx will need to know to look for PHP index files.

root@servername:~# nano /etc/nginx/nginx.conf

Change:

index index.html index.htm index.php;


Telling nginx to pass PHP files

For PHP to work, nginx must be configured to pass a given file to the PHP interpreter. This presents a security risk in the event that a PHP package has a security exploit or a server is incorrectly configured. Additionally, if a .php file is not configured to be passed to the PHP interpreter, then nginx will treat this file as any other and serve it as a download. Some of these files can be used to determine server configurations as well as find information such as database passwords, administrator passwords and other bits of information that a hacker may use to break into a server.

There are commonly three ways that are used to pass .php files to the PHP interpreter:

Least secure:
server {
    ...
    location ~ \.php$ {
        <PHP configuration>
    }
}

This is most insecure because it passes all .php files in the site's directory to the PHP interpreter unless a location is specifically denied. If a hacker is able to write or rewrite any file in the site's directory, then the hacker can navigate to www.example.com/hackedfile.php and run the malicious code.

Improved, but still vulnerable:
server {
    ...
    location ~ /subdirectory/.*\.php$ {
        <PHP configuration>
    }
}

This configuration is often provided with some specific location blocks with deny all and default_type text/plain statements. Although more secure than allowing all .php files in the site's root directory be passed to the PHP interpreter, it still leaves the vulnerability of any .php file altered or added to the /subdirectory/ as being a vector for attack. It is also impossible to use this method when installing a PHP package as a site's home page, since the /subdirectory/ is in fact the site's root directory.

Very secure:
server {
    ...
    location = /directoryname/file.php$ {
        <PHP configuration>;
    }

    location /directoryname/ {
        location ~ \.php$ { deny all; }
    }
}

Or:

server {
    ...
    location /directoryname/ {
        location ~ (filename1|filename2|filename3).*\.php$ {
            <PHP configuration>;
        }
        location ~ \.php$ { deny all; }
    }
}

These configurations pass only specific files to the PHP interpreter, thus a hacker will have to change those specific files to pass malicious code.

The first example uses the location = directive, which tells nginx to stop all searching and run this location, which is faster. However, as written, this configuration will only work with PHP packages using MVC framework.

The second example requires identifying every single .php file a package requires a user to have publicly accessible. This can be difficult as plugins and upgrades to the package may remove the requirement for some files while adding others, requiring testing of every single link and function every time there is an upgrade to the package. If a package is behaving unexpectedly, it may be because of the PHP configuration. Checking /var/www/example.com/logs/error.log for errors will reveal such causes.

Both examples have a deny all statement to block access to all other .php locations. Since nginx processes directives in the order stated, this should generally be the last directive for locations that contain PHP packages.

Sites-available configuration

It is good practice to use a configuration file to manage PHP. When security holes or configuration issues are discovered, they can be easily fixed for all passing of PHP on the server by editing only one or two files, plus the sites-available files will be smaller and easier to manage by cleaning up the file and reducing the opportunity for syntax errors.

Create the global-configs files

There will be two files, one for use in HTTP server blocks and the other for use in HTTPS server blocks.

root@servername:~# nano /etc/nginx/global-configs/php.conf

Add:

try_files $uri =404;
include fastcgi_params;
fastcgi_read_timeout 300;
fastcgi_pass php5.6-fpm-sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_intercept_errors on;

And create the HTTPS file:

root@servername:~# nano /etc/nginx/global-configs/php_https.conf

Add:

try_files $uri =404;
include fastcgi_params;
fastcgi_read_timeout 300;
fastcgi_pass php5.6-fpm-sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_intercept_errors on;
fastcgi_param HTTPS on;
Configure PHP test & info location
root@servername:~# nano /etc/nginx/sites-available/example.com

There is a standard notation used that makes human reading of configuration files a little easier. In the examples below, this format is used.

In the HTTPS server block:

    location ~ phpinfo.php {
        include global-configs/php_https.conf;
    }

For the actual phpinfo.php entries, it may be more convenient to enter everything on one line, this way the entry can be easily commented or uncommented for various testing purposes.

In the HTTPS server block, add:

    location ~ phpinfo.php { include /etc/nginx/global-configs/php_https.conf; }


Reboot the server.

root@servername:~# reboot

Verify installation

PHP can display its current settings by creating a PHP file and running it in a browser.

username@servername:~$ touch /var/www/example.com/public/phpinfo.php
username@servername:~$ chmod 664 /var/www/example.com/public/phpinfo.php
username@servername:~$ sudo chown www-data /var/www/example.com/public/phpinfo.php
username@servername:~$ nano /var/www/example.com/public/phpinfo.php

Add the following line:

<?php phpinfo(); ?>

Navigate to http://www.example.com/phpinfo.php and https://www.example.com/phpinfo.php, which should bring up the long list of PHP settings. Testing both is necessary to verify everything is working properly.

It is good practice to comment out the phpinfo.php location blocks in the sites-available file when they are not needed.

A quick way to view the PHP configuration without passing it through nginx is to run it directly through command line, though this will not reveal if there are any issues with nginx and PHP:

username@servername:~$ php /var/www/example.com/public/phpinfo.php > phpinfo.txt
username@servername:~$ nano phpinfo.txt

Supporting PHP mail() function

Many popular PHP packages make use of the PHP mail() function to send emails for various purposes. For this function to work properly, an MTA must be installed in the server. A simple workaround for those not planning to install a mail server is to configure an SMTP mail server, such as Gmail, to manage the mail. (However, note that Google does not like Gmail to be used for transactional mail and will likely disable the account for 24 hour periods upon detection.) Most of the popular PHP packages will either have this option built-in to the package or plugins will be available. When using an SMTP mail server, be sure to note the maximum message limits. These services will also commonly have bandwidth limitations, but so long as the messages do not include images it is highly unlikely that bandwidth limits will be reached before hitting the message limits.

Another option is to configure the server be a transactional mail server.

Next step

And now, for the final step in completing the UNPM Server: Install MariaDB.

References

External links

PHP: Hypertext Preprocessor

Ondřej Surý maintains several PPAs through Launchpad

Sury.org wiki on GitHub

Bolting on PHP with PHP-FPM | Ars Technica