Installing and Configuring Nginx with PHP-fpm + MySQL on Debian Jessie

What's up fellas, here we'll take a look how to configure the Nginx with PHP and Mysql on Debian Jessie.

Fell free to use the following script to adjust your environment: http://wiki.douglasqsantos.com.br/doku.php/confinicialjessie_en

Let's update the repositories and let's upgrade the system.

aptitude update && aptitude dist-upgrade -y

Let's install the PHP, MySQL, Nginx and some extension of PHP

aptitude install php5 php5-fpm php-pear php5-common php5-mcrypt php5-mysql php5-cli php5-gd mysql-server nginx-extras -y

Note: Needs to set up the MySQL root password

Now we need to make a change to enable the Nginx to work with PHP

vi /etc/php5/fpm/pool.d/www.conf
[...]
;listen = /var/run/php5-fpm.sock #line 38
listen = 127.0.0.1:9000
[...]

Now we need to restart the php-fpm

systemctl restart php5-fpm.service

Agora vamos verificar se a porta 9000 está escutando

netstat -tulanp | egrep 9000
tcp        0      0 127.0.0.1:9000          0.0.0.0:*               LISTEN      14582/php-fpm.conf)

Now let's create a backup of the nginx configuration file.

cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bkp

Now let's create our configuration as follows.

vim /etc/nginx/nginx.conf
#/etc/nginx/nginx.conf
## User that the server runs as
user www-data;
## how many nginx instances actually run
worker_processes 4;
## Where it stores the process ID of the master process.
pid /run/nginx.pid;

## defines how the daemon incoming requests at the system level
events {
        ## how many connections a sinble worker thread is allowed to process
        worker_connections 768;
        ## keep accepting connections even though the server hasn't finished handeling incoming connections.
        # multi_accept on;
}

## This is where most of your tuning will take place
http {
        ## GLOBAL
        ## Enabling this will increase the speed that nginx can cache, and retreive from cache
        sendfile on;
        ## This option causes nginx to attempt to send it's HTTP response headers in one packet.
        tcp_nopush on;
        ## This disables a buffer that when used with keep-alive connections, can slow things down
        tcp_nodelay on;
        ## Defines the maximum time between keepalive requests from client browsers.
        keepalive_timeout 65;
        ## Defines the maximum size of hash tables. This directly influences cache performance. Higher numbers use more memory, and offer potentially higher performance.
        types_hash_max_size 2048;
        ## Sets the maximum allowed size of the client request body, specified in the “Content-Length” request header field.
        client_max_body_size 20M;
        ## Sets buffer size for reading client request body.
        client_body_buffer_size 128k;
        ## Enables or disables emitting nginx version in error messages and in the “Server” response header field.
        server_tokens off;
        ## Sets the bucket size for the server names hash tables.
        # server_names_hash_bucket_size 64;
        ## Enables or disables the use of the primary server name, specified by the server_name directive, in redirects issued by nginx.
        # server_name_in_redirect off;
        ## Includes mime.types configuration file
        include /etc/nginx/mime.types;
        ## Defines the default MIME type of a response. Mapping of file name extensions to MIME types can be set with the types directive.
        default_type application/octet-stream;

        ## Logging Settings
        access_log /var/log/nginx/access.log combined;
        error_log /var/log/nginx/error.log;

        ## Gzip Settings
        ## Enables or disables gzipping of responses. 
        gzip on;
        ## Disables gzipping of responses for requests with “User-Agent” header fields matching any of the specified regular expressions.
        gzip_disable "msie6";
        ## Enables or disables inserting the “Vary: Accept-Encoding” response header field if the directives gzip, gzip_static, or gunzip are active
        gzip_vary on;
        ## Enables or disables gzipping of responses for proxied requests depending on the request and response.
        gzip_proxied any;
        ## Sets a gzip compression level of a response. Acceptable values are in the range from 1 to 9. 
        gzip_comp_level 6;
        ## Sets the number and size of buffers used to compress a response. By default, the buffer size is equal to one memory page.
        gzip_buffers 16 8k;
        ## Sets the minimum HTTP version of a request required to compress a response.
        gzip_http_version 1.1;
        ##  Enables gzipping of responses for the specified MIME types in addition to “text/html”.
        gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;


        ## Virtual Host Configs
        include /etc/nginx/conf.d/*.conf;
        include /etc/nginx/sites-enabled/*;
}

Now we need to disable the default virtual Host

unlink /etc/nginx/sites-enabled/default

Now we need to create our new Virtual Host

vim /etc/nginx/sites-available/www.douglasqsantos.com.br
#/etc/nginx/sites-available/www.douglasqsantos.com.br
## Sets configuration for a virtual server.
server {
                ## Sets the address and port for IP, or the path for a UNIX-domain socket on which the server will accept requests. 
                listen 80;
                ## Sets names of a virtual server
                server_name douglasqsantos.com.br www.douglasqsantos.com.br;
    ## Enables or disables emitting nginx version in error messages and in the “Server” response header field.
          server_tokens off;
                ## Logging 
                access_log /var/log/nginx/www.douglasqsantos.com.br.access.log combined;
                error_log /var/log/nginx/www.douglasqsantos.com.br.error.log;
                ## Sets the root directory for requests
                root /var/www/www.douglasqsantos.com.br;
    ## Sets configuration depending on a request URI.
          location / {
                ## Checks the existence of files in the specified order and uses the first found file for request processing
      try_files $uri $uri/ /index.php;
    }
                ## Defines files that will be used as an index.
                index index.php index.htm index.html;
                ## Sets configuration for PHP files
                location ~ \.php$ {
                  ## Sets the address of a FastCGI server.
                  fastcgi_pass   127.0.0.1:9000;
                  ## Sets a file name that will be appended after a URI that ends with a slash, in the value of the $fastcgi_script_name variable.
                  fastcgi_index  index.php;
                  ## Sets a parameter that should be passed to the FastCGI server.
                  fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
                  ## Include the fastcig_params file.
                  include fastcgi_params;
               }
}

Now we need to create the document root to our virtual host

mkdir -p /var/www/www.douglasqsantos.com.br

Now we need to set up the permissions

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

Let's create the index.php to test the php configuration

echo "<?php phpinfo(); ?>" > /var/www/www.douglasqsantos.com.br/index.php

Now let's create the php file to test the mysql module for php

vim /var/www/www.douglasqsantos.com.br/mysql.php
<?php
$link = mysql_connect('localhost', 'root', 'senha');
if (!$link) {
    die('Could not connect: ' . mysql_error());
}
echo 'Connected successfully';
mysql_close($link);
?>

Now we need to enable the new virtual host

ln -sf /etc/nginx/sites-available/www.douglasqsantos.com.br /etc/nginx/sites-enabled/www.douglasqsantos.com.br

Now we need to restart the nginx to reload the new configurations.

systemctl restart nginx

Now we can run a test accessing PHP http://www.douglasqsantos.com.br/ or http://ip_servidor/ with you did not configure the DNS

Now we can run a test access http://www.douglasqsantos.com.br/mysql.php to test php with MySQL or http://ip_servidor/mysql.php with you did not configure the DNS

Working with HTTPS

Now let's enable the https

Let's create the directory to store the certificates

mkdir /etc/nginx/ssl

Let's access the directory

cd /etc/nginx/ssl

Let's create the certificate key

openssl genrsa -des3 -out server.key 1024
Generating RSA private key, 1024 bit long modulus
..............................++++++
.++++++
e is 65537 (0x10001)
Enter pass phrase for server.key: #senha
Verifying - Enter pass phrase for server.key: #senha

Now we need to create the certificate sign request

openssl req -new -key server.key -out server.csr
Enter pass phrase for server.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) []:BR
State or Province Name (full name) []:Parana
Locality Name (eg, city) []:Curitiba
Organization Name (eg, company) []:Douglas
Organizational Unit Name (eg, section) []:IT
Common Name (eg, fully qualified host name) []:www.douglasqsantos.com.br
Email Address []:douglas.q.santos@gmail.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:Douglas

Now we need to change the certificate permissions

chmod 0400 server.*
cp server.key server.key.orig

Now we need to auto sign the certificate

openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt
Signature ok
subject=/C=BR/ST=Parana/L=Curitiba/O=Douglas/OU=Douglas/CN=www.douglasqsantos.com.br/emailAddress=douglas.q.santos@gmail.com
Getting Private key
Enter pass phrase for server.key: senha

Now let's remove the password from our certificate, otherwise we need to put the password every nginx start.

openssl rsa -in server.key.orig -out server.key
Enter pass phrase for server.key.orig: senha
writing RSA key

Let's change the certificates permissions.

chmod 0400 /etc/nginx/ssl/* 

Agora vamos ajustar o nosso virtualhost

vim /etc/nginx/sites-available/www.douglasqsantos.com.br
#/etc/nginx/sites-available/www.douglasqsantos.com.br
## Sets configuration for a virtual server.
server {
                ## Sets the address and port for IP, or the path for a UNIX-domain socket on which the server will accept requests.
                listen 80;
                ## Sets names of a virtual server
                server_name douglasqsantos.com.br www.douglasqsantos.com.br;
    ## Enables or disables emitting nginx version in error messages and in the “Server” response header field.
          server_tokens off;
                ## Logging
                access_log /var/log/nginx/www.douglasqsantos.com.br.access.log combined;
                error_log /var/log/nginx/www.douglasqsantos.com.br.error.log;
                ## Sets the root directory for requests
                root /var/www/www.douglasqsantos.com.br;
    ## Sets configuration depending on a request URI.
          location / {
                ## Checks the existence of files in the specified order and uses the first found file for request processing
      try_files $uri $uri/ /index.html;
    }
                ## Defines files that will be used as an index.
                index index.php index.htm index.html;
                ## Sets configuration for PHP files
                location ~ \.php$ {
                  ## Sets the address of a FastCGI server.
                  fastcgi_pass   127.0.0.1:9000;
                  ## Sets a file name that will be appended after a URI that ends with a slash, in the value of the $fastcgi_script_name variable.
                  fastcgi_index  index.php;
                  ## Sets a parameter that should be passed to the FastCGI server.
                  fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
                  ## Include the fastcig_params file.
                  include fastcgi_params;
               }
}

## Sets configuration for a virtual server.
server {
                ## Sets the address and port for IP, or the path for a UNIX-domain socket on which the server will accept requests.
                listen 443;
          ## Enables the HTTPS protocol for the given virtual server.
                ssl on;
                ## Specifies a file with the certificate in the PEM format for the given virtual server.
                ssl_certificate /etc/nginx/ssl/server.crt;
          ## Specifies a file with the secret key in the PEM format for the given virtual server.
                ssl_certificate_key /etc/nginx/ssl/server.key;
    ## Specifies the enabled ciphers
    ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
    ## Specifies that server ciphers should be preferred over client ciphers when using the SSLv3 and TLS protocols
    ssl_prefer_server_ciphers on;
    ## Specifies the enabled ciphers
    ssl_ciphers HIGH:!aNULL:!MD5;
                ## Sets names of a virtual server
                server_name douglasqsantos.com.br www.douglasqsantos.com.br;
    ## Enables or disables emitting nginx version in error messages and in the “Server” response header field.
          server_tokens off;
                ## Logging
                access_log /var/log/nginx/www.douglasqsantos.com.br-ssl.access.log combined;
                error_log /var/log/nginx/www.douglasqsantos.com.br-ssl.error.log;
                ## Sets the root directory for requests
                root /var/www/www.douglasqsantos.com.br;
    ## Sets configuration depending on a request URI.
          location / {
                ## Checks the existence of files in the specified order and uses the first found file for request processing
      try_files $uri $uri/ /index.php;
    }
                ## Defines files that will be used as an index.
                index index.php index.htm index.html;
                ## Sets configuration for PHP files
                location ~ \.php$ {
                  ## Sets the address of a FastCGI server.
                  fastcgi_pass   127.0.0.1:9000;
                  ## Sets a file name that will be appended after a URI that ends with a slash, in the value of the $fastcgi_script_name variable.
                  fastcgi_index  index.php;
                  ## Sets a parameter that should be passed to the FastCGI server.
                  fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
                  ## Include the fastcig_params file.
                  include fastcgi_params;
               }
}

Now we need to restart the nginx

systemctl restart nginx

Now we can run a test accessing PHP https://www.douglasqsantos.com.br/ or https://ip_servidor/ with you did not configure the DNS

Now we can run a test access https://www.douglasqsantos.com.br/mysql.php to test php with MySQL or https://ip_servidor/mysql.php with you did not configure the DNS

Restricting Access

Access can be allowed or denied by the IP address of a client or by using the HTTP basic authentication. To allow or deny access from a certain set of addresses, or all addresses, use the allow and deny directives:

location / {
    allow 192.168.1.1/24;
    allow 127.0.0.1;
    deny 192.168.1.2;
    deny all;
}

To enable authentication, use the auth_basic directive. A user will have to enter the valid user name and password to get access to the website. The user names and passwords should be listed in the file that is specified through the auth_basic_user_file directive.

server {
    ...
    auth_basic "closed website";
    auth_basic_user_file conf/htpasswd;
}

The auth_basic directive with the off parameter cancels the effect from the outer configuration level. For example, access to the whole site can be limited, but some locations can be publicly available:

server {
    ...
    auth_basic "closed website";
    auth_basic_user_file conf/htpasswd;

    location /public/ {
        auth_basic off;
    }
}

To combine restriction by IP address and authentication, use the satisfy directive. By default, it is set to all, so a client should satisfy both types of conditions to be granted access. If the satisfy directive is set to any access is granted if at least one condition is satisfied. Thus, an unauthenticated user gets access if its IP address is among the allowed IP addresses. Otherwise users from IP addresses to which access is denied can access the website only if they enter valid user names and passwords. The example below shows how to combine the two methods of restricting access to a location:

location / {
    satisfy any;

    allow 192.168.1.0/24;
    deny  all;

    auth_basic           "closed site";
    auth_basic_user_file conf/htpasswd;
}

Now let's create the directories to test the access restriction

mkdir /var/www/www.douglasqsantos.com.br/{public,restrict,password}

Now let's install the apache-utils to get the htpasswd command line

aptitude install apache2-utils -y

Now let's create the directory that will store the password file

mkdir /etc/nginx/password/

Now let's create the index files to new directories

echo "<center><h1>Public</h1></center>" > /var/www/www.douglasqsantos.com.br/public/index.php 
echo "<center><h1>Restrict</h1></center>" > /var/www/www.douglasqsantos.com.br/restrict/index.php
echo "<center><h1>Password Required</h1></center>" > /var/www/www.douglasqsantos.com.br/password/index.php

Now let's create the password file as follows

htpasswd -cs /etc/nginx/password/htpasswd douglas
New password: 
Re-type new password: 
Adding password for user douglas

Now we need to change the virtual host file as follows

cat /etc/nginx/sites-available/www.douglasqsantos.com.br 
#/etc/nginx/sites-available/www.douglasqsantos.com.br
## Sets configuration for a virtual server.
server {
                ## Sets the address and port for IP, or the path for a UNIX-domain socket on which the server will accept requests.
                listen 80;
                ## Sets names of a virtual server
                server_name douglasqsantos.com.br www.douglasqsantos.com.br;
    ## Enables or disables emitting nginx version in error messages and in the “Server” response header field.
          server_tokens off;
                ## Logging
                access_log /var/log/nginx/www.douglasqsantos.com.br.access.log combined;
                error_log /var/log/nginx/www.douglasqsantos.com.br.error.log;
                ## Sets the root directory for requests
                root /var/www/www.douglasqsantos.com.br;
    ## Sets configuration depending on a request URI.
          location / {
                ## Checks the existence of files in the specified order and uses the first found file for request processing
      try_files $uri $uri/ /index.php;
    }
                ## Defines files that will be used as an index.
                index index.php index.htm index.html;
                ## Sets configuration for PHP files
                location ~ \.php$ {
                  ## Sets the address of a FastCGI server.
                  fastcgi_pass   127.0.0.1:9000;
                  ## Sets a file name that will be appended after a URI that ends with a slash, in the value of the $fastcgi_script_name variable.
                  fastcgi_index  index.php;
                  ## Sets a parameter that should be passed to the FastCGI server.
                  fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
                  ## Include the fastcig_params file.
                  include fastcgi_params;
               }
               
               ## Restricting Access allow by default
            location /public {
                   ## Everyone can access this folder
       allow all;
    }

               ## Restricting Access by IP
    location /restrict {
                   ## Allow the ip 192.168.1.254 access this folder
       allow 192.168.1.254/32;
                   ## Allow the ip 127.0.0.1 access this folder
       allow 127.0.0.1;
                   ## Deny any other client to access this folder
       deny all;
    }
               ## Restriction By auth_basic 
    location /password {
                   ## Message box that will be show to the client
       auth_basic "closed website";
                   ## Password File Path 
       auth_basic_user_file /etc/nginx/password/htpasswd;
    }

}

Now we need to restart the nginx

systemctl restart nginx

To run a test access http://ip_server/public, http://ip_server/restrict, http://ip_server/password

Limiting Access

It is possible to limit:

  • The number of connections per key value (for example, per IP address)
  • The request rate per key value (the number of requests that are allowed to be processed during a second or minute)
  • The download speed for a connection

Note: That IP addresses can be shared behind NAT devices so limiting by IP address should be used judiciously

To limit the number of connections, first use the limit_conn_zone directive to define the key and set the parameters of the shared memory zone (the worker processes will use this zone to share counters for key values). As the first parameter, specify the expression evaluated as a key. In the second parameter zone, specify the name of the zone and its size.

limit_conn_zone $binary_remote_address zone=addr:10m;

Second, use the limit_conn directive to apply the limit within a location, a virtual server, or the whole http context. Specify the name of the shared memory zone as the first parameter, and the number of allowed connection per key as the second.

location /download/ {
    limit_conn addr 1;
}

Here, the number of connections is limited on an IP address basis because the $binary_remote_address variable is used as a key. The number of connections for a given server can be limited by using the $server_name variable:

http {
    limit_conn_zone $server_name zone=servers:10m;

    server {
        limit_conn servers 1000;
    }
}

Link: http://nginx.org/en/docs/http/ngx_http_limit_conn_module.html#limit_conn_zone

To limit the request rate ,first set up the key and the shared memory zone to keep the counters by using the limit_req_zone directive.

limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

The key is specified in the same manner as for limit_conn_zone. The rate parameter can be specified in requests per second (r/s) or requests per minute (r/m). The latter is used to specify a rate less than one request per second. For example, to get the rate of half of a request per second set the parameter to 30r/m. Once the shared memory zone is defined, use the limit_req directive in a virtual server or a location (or globally, if required) to limit the request rate:

location /search/ {
    limit_req zone=one burst=5;
}

Here, NGINX will process no more than one request a second in this location. If the rate is exceeded the requests above the limit are put into a queue and processing is delayed in such a way that the overall rate is not greater than specified. The burst parameter sets the maximum number of requests that await to be processed. For requests above the burst limit NGINX will respond with a 503 error. If delaying is not desired during a burst, add the nodelay flag.

limit_req zone=one burst=5 nodelay;

To limit the bandwidth per connection, use the limit_rate directive:

location /download/ {
    limit_rate 50k;
}

With this setting a client will be able to download content through a single connection at a maximum speed of 50 kilobytes per second. However, the client can open several connections. So if the goal is to prevent a speed of downloading greater than the specified value, the number of connections should also be limited. For example, one connection per IP address (if the shared memory zone specified above is used):

location /download/ {
    limit_conn addr 1;
    limit_rate 50k;
}

To impose the limit only after the client downloads a certain amount of data, use the limit_rate_after directive. It may be reasonable to allow a client to quickly download a certain amount of data (for example, a file header — film index) and limit the rate for downloading the rest of the data (to make users watch a film, not download).

limit_rate_after 500k;
limit_rate 20k;

The following example shows the combined configuration for limiting the number of connections and the bandwidth. The maximum allowed number of connections is set to 5 connections per client address, which fits most common cases since modern browsers typically open up to 3 connections at a time. Meanwhile the location that serves downloads allows only one connection:

http {
    limit_conn_zone $binary_remote_address zone=addr:10m

    server {
        root /www/data;
        limit_conn addr 5;

        location / {
        }

        location /download/ {
            limit_conn addr 1;
            limit_rate 1m;
            limit_rate 50k;
        }
    }
}

References