Installing PHP7 with nginx and MySQL on Debian 8 - Part 2

Table of Contents

  1. Before starting
  2. Configuring PHP7 and FPM
  3. Securing MySQL
  4. Configuring nginx

Before starting

Before we start you should take a read of my previous article on setting up the basic PHP7, nginx and MySQL on Debian 8 so that you can jump straight into getting it all configured from this article.

You can catch up by going here: Part 1 of Installing PHP7 with nginx and MySQL

Configure php7 and fpm

Theres a few things I like to do before getting to configuring nginx, so I will start with configuring a few PHP variables and a setting up PHP-FPM.

First off I am going to change a few variables in php.ini, most of the time you will only change these to match you or your clients needs i.e. for Wordpress sites you may want to have a higher upload limit for images etc.

Tip: if you want to search using nano, use Ctrl + W

sudo nano /etc/php/7.0/fpm/php.ini

Changed the following:

upload_max_filesize = 2M
memory_limit = 128M

To:

upload_max_filesize = 5M
memory_limit = 256M 

I changed the memory limit to half of my VPS memory limit to allow for extra usage, lower this depending on how much memory you have or wish to allocate to allow for scripts.

We are also changing the following in the php.ini:

post_max_size = 8M
allow_url_fopen = On

To:

post_max_size = 12M
allow_url_fopen = Off

This allows your scripts to post a larger amount of data and will also disallow fopen to open urls such as http, https or ftp style locations. This is called Remote File Inclusion and we don't want this to be a security vulnerability.

Now we can configure FPM. To configure FPM you will need to edit or add files to the /etc/php/7.0/fpm/pool.d/ folder. For us there should be a file called www.conf. For this example I will edit this file.

sudo nano /etc/php/7.0/fpm/pool.d/www.conf

Most of this file is well commented but the main lines we need to deal with are the user, group and listen lines.

Firstly the user should match the user we will use for nginx, I'm going to stick with www-data for the user and for the group as this is who I will run nginx as.

Now we need to configure the listen parameter. Listen is how the FPM will listen. The choice is down to you as to how you wish to setup the FPM to listen. I will change from the socket to a TCP connection for this example but I will include how to use a socket too.

listen = 127.0.0.1:9000
listen = /run/php/php7.0-fpm.sock

I'm not going to go into depth with the rest of the configurations you will need to change those based on your specific tasks required.

Now we can start up the FPM using the following command:

sudo service php7.0-fpm start

This starts the service for us but we may want this service to start automatically on boot so run the following command:

sudo systemctl enable php7.0-fpm

This adds php7.0-fpm to boot up with sysvinit using the update-rc.d but all we need to know is that it will run on reboot should our server crash.

If you want to check the status of fpm you can run:

sudo service php7.0-fpm status

It will give you the service status and tell you a few pieces of information.

Now we can setup MySQL.

Securing MySQL

Securing the MySQL service is important as you will be holding data here that could be important such as user data and passwords. In Part 1 we locked down root to only be used on localhost, here we will create two accounts; one for accessing the server using a MySQL client like Sequel Pro or Benchmark and one account for your application.

Lets get logged into the MySQL server:

mysql -u root -p

Pop in your password and let’s begin. First get an account for us to use in a client.

CREATE USER 'myuser'@'mypublicip' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON *.* TO 'myuser'@'mypublicip';

You will need to change 'myuser' to a username for your account and 'mypublicip' to either your public ip or use '%' to allow from all (not recommended but necessary if you have a dynamic ip address from your ISP) and also you will need supply your own 'password'.

The grant all will give your account permissions to all on all, meaning you will have access to all tables on all databases.

Next lets create an account for your application:

CREATE DATABASE myapp;
CREATE USER 'myapp'@'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON myapp.* TO 'myuser'@'mypublicip';

This creates the user 'myapp' for localhost access only with a 'password' and grants them access to only use the new database we created. Change these as appropriate.

Now that you have your users you can setup your database as you need.

Configuring nginx

I really like nginx, its fast and lightweight and I find it easier to use than apache.

In this setup I am going to create a server configuration for a test php application.

First things first we going to create a folder in /var called www this folder we will use to store all of the websites by domain name. So the first one we will create is mytestsite.com.

You should do the following:

sudo mkdir /var/www
sudo mkdir /var/www/mytestsite.com
ls -l /var/www/

Response looks like:

total 8
drwxr-xr-x  2   root    root    4096    May 12  13:00   html
drwxr-xr-x  2   root    root    4096    May 12  13:05   mytestsite.com

As you can see the folder is owned by root and group root, we need to change this to www-data user and group as this was the user we had specified for php-fpm and the user we will specify for nginx.

sudo chown -R www-data:www-data /var/www

The command above will change the directory and subdirectories to be owned by www-data and group www-data.

Now the bashls -l /var/www will show:

total 8
drwxr-xr-x  2   www-data    www-data    4096    May 12  13:00   html
drwxr-xr-x  2   www-data    www-data    4096    May 12  13:05   mytestsite.com

Good so now we have the structure.

If you try to start nginx using:

sudo service nginx start

You will get an error about it being masked, this is because the service has been set to not be altered while in operation. So you can unmask it from systemctl with:

sudo systemctl unmask nginx

This will now allow you to run the start nginx. We will mask it once we are completed configuring and testing.

Before beginning this section if you cannot access your server through the public ip or local ip you will need to sudo apt-get install curl to use the curl command.

If you run a curl command now to test the server, you should see an error:

curl -I 127.0.0.1:80

You should get a HTTP/1.1 403 Forbidden header.

sudo nano /etc/nginx/nginx.conf

The line you will need to change is:

user    nginx

To:

user    www-data

Now you can restart your server using:

sudo service nginx restart

Now notice you still get the same issue with permissions if you do the wget command again. This is because the default server is setup to read from /usr/share/nginx/html which is owned by root! Now the server cannot access this because it does not have root privilges so lets change the permissions of that folder to allow www-data to access it.

sudo chown -R www-data:www-data /usr/share/nginx/html

Now a curl should show a 200 ok header! Great nginx is now configured with a default server. This means if you directly access your servers IP address you should be given the default nginx index page.

So we will need to configure our server for a new site. To do this we will take advantage of sites-enabled and site-available, these folders are located within /etc/nginx. The way we want this to work is, we will set a configuration up inside the sites-available folder and then in sites-enabled we will create a symlink to the configuration inside sites-available. We will then get nginx to load everything inside sites-enabled as servers.

Keeping them separate will make it easier to deal with multiple site configurations.

So first step is to configure nginx to load sites in sites-enabled automatically. Luckily for us we already have a snippet available from the conf.d auto loading in nginx.conf. So lets edit the file:

sudo nano /etc/nginx/nginx.conf

And change:

include  /etc/nginx/conf.d/*.conf;

To:

include  /etc/nginx/conf.d/*.conf;
include  /etc/nginx/sites-enabled/*;

Now lets create our first configuration by adding sudo nano /etc/nginx/sites-available/mysite.com.conf and adding the following to the file:

server {
  listen 80;
  server_name mysite.com;

  return 301 $scheme://www.mysite.com$request_uri;
}

server {
  listen 80;
  server_name www.mysite.com;

  root /var/www/mysite.com/public_html;
  access_log /var/log/nginx/mysite.com.access.log;
  error_log /var/log/nginx/mysite.com.error.log;

  charset utf-8;

  #error_page 404 /404.html; 
  #error_page 500 501 502 503 /50x.html; <--- add these yourself at a later date

  location ~ \.php$ {
    include fastcgi_params;
    try_files $uri =404;
    fastcgi_index index.php;
    fastcgi_pass 127.0.0.1:9000
    # fastcgi_pass unix:/run/php/php7.0-fpm.sock <--- this is if you want to use sockets
    fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
  }

}

Now the file is created lets add the symlink for it:

sudo ln -s /etc/nginx/sites-available/mysite.com.conf /etc/nginx/sites-enabled/mysite.com.conf

Now reboot your services:

sudo service nginx restart
sudo service php7.0-fpm restart

Quickly create a php file to test that fastcgi and php are working as intended:

sudo mkdir /var/www/mysite.com/public_html
sudo touch /var/www/mysite.com/public_html/info.php
sudo nano /var/www/mysite.com/public_html/info.php

And add:

<?php
    phpinfo();
?>

Then run:

sudo chown -R www-data:www-data /var/www/mysite.com
sudo chmod 644 /var/www/mysite.com/public_html/info.php

Once completed if you run the command:

curl -H "Host: www.mysite.com" http://127.0.0.1/info.php

You should see the html being spat out in the command line. Now if you view in your browser you should be able to see all of the php 7 information.

Conclusion

For now you are complete with PHP 7, nginx and MySQL. Next part we will install an SSL certificate to the server using letsencrypt.

Have a tinker with your settings of you server, maybe try to make multiple servers within nginx using the sites-available and sites-enabled and see how things work out.

Next we will get an SSL setup and do some advanced security settings.

Posted in DevOps, Out of date on May 16, 2016