Install PHP

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 a UNPM server.

Most of the article will require root privileges.

username@servername:~$ sudo /bin/bash

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/php5 && aptitude update

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 php5-fpm php5-gd php5-mcrypt php5-cli php5-curl memcached php5-memcache php5-dev php-pear php-apc make libpcre3-dev

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

root@servername:~# mkdir /etc/php5/conf.d/ root@servername:~# nano /etc/php5/conf.d/apc.ini

Add:

extension=apc.so apc.shm_size = 128M

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

Change:

expose_php = Off

post_max_size = 20M

cgi.fix_pathinfo = 0

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, which reports the version of PHP being used, however, this is not perfect protection from revealing such information, but easy enough to do.

The  setting in   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  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  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.

The  and   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.

Run PHP on a Unix socket
root@servername:~# nano /etc/php5/fpm/pool.d/www.conf

If necessary, change:

listen = /var/run/php5-fpm.sock listen.owner = www-data listen.group = www-data

Configure memcached
Some changes must be made to the memcached configuration file.

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

Change:
 * 1) -p 11211
 * 2) -l 127.0.0.1

At the bottom, add: -s /tmp/memcached.sock -a 666

Configure nginx
Create a new file in the nginx  directory for PHP.

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

Add to the file: upstream php5-fpm-sock { server unix:/var/run/php5-fpm.sock; }

Adding some new settings to the  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  file is not configured to be passed to the PHP interpreter, then nginx will treat this file as any other and serve it as 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  files to the PHP interpreter:

Least secure:
server { ...    location ~ \.php$ {  } }

This is most insecure because it passes all  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$ {  } }

This configuration is often provided with some specific  blocks with   and   statements. Although more secure than allowing all  files in the site's root directory be passed to the PHP interpreter, it still leaves the vulnerability of any   file altered or added to the   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  is in fact the site's root directory.

Very secure:
server { ...    location = /directoryname/file.php$ { ; }    location /directoryname/ { location ~ \.php$ { deny all; } } }

Or:

server { ...    location /directoryname/ { location ~ (filename1|filename1|filename3).*\.php$ { ; }        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  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  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  for errors will reveal such causes.

Both examples have a  statement to block access to all other   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 are 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_pass php5-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_pass php5-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 HTTP server block: location ~ phpinfo.php { include global-configs/php.conf; }

In the HTTPS server block: location ~ phpinfo.php { include global-configs/php_https.conf; }

For the actual  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 HTTP server block, add: location ~ phpinfo.php { include /etc/nginx/global-configs/php.conf; }

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: 

Navigating to  http://www.example.com/phpinfo.php  and  https://www.example.com/phpinfo.php  should bring up the long list of PHP settings.

It is good practice to comment out the  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  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.

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