Wednesday, October 15, 2014

Nginx, SSL & php5-fpm on Debian Wheezy

http://www.iodigitalsec.com/nginx-ssl-php5-fpm-on-debian-wheezy

I decided to take a break from my love affair with Apache and set up a recent development project on Nginx. I’ve seen nothing but good things in terms of speed and performance from Nginx. I decided to set up a LEMP server (Linux, Nginx, MySQL, PHP), minus the MySQL as it’s already installed on my VM host server, and plus SSL. Here’s the full setup tutorial on Debian Wheezy:

Step #1 – Installing the packages

1
2
apt-get install nginx-extras mysql-client
apt-get install php5-fpm php5-gd php5-mysql php-apc php-pear php5-cli php5-common php5-curl php5-mcrypt php5-cgi php5-memcached
MySQL can be installed into the mix with a simple:
1
apt-get install mysql-server

Step #2 – Configure php5-fpm

Open /etc/php5/fpm/php.ini and set:
1
cgi.fix_pathinfo=0
Now edit /etc/php5/fpm/pool.d/www.conf and ensure that the listen directive is set as follows:
1
listen = /var/run/php5-fpm.sock
This is already the case on Debian Wheezy, however may be set to 127.0.0.1 or other values on other versions. Lastly, restart php5-fpm with:
1
/etc/init.d/php5-fpm restart

Step #3 – Configure Nginx and SSL

First, create a web content directory:
1
mkdir /var/www
Next, edit /etc/nginx/sites-available/default to set the first site’s configuration. The directives are reasonably self explanatory:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
server {
        listen 80;
        root /var/www;
        index index.php index.html index.htm;
        server_name my.test.server.com;
        location / {
                try_files $uri $uri/ /index.html;
        }
        error_page 404 /404.html;
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
              root /var/www;
        }
        # pass the PHP scripts to FastCGI server listening on the php-fpm socket
        location ~ \.php$ {
                try_files $uri =404;
                fastcgi_pass unix:/var/run/php5-fpm.sock;
                fastcgi_index index.php;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                include fastcgi_params;
        }
}
I’ve extended this configuration to meet my requirements. My configuration is intended to:
  • Redirect all port HTTP requests to HTTPS
  • Serve HTTPS with a reasonable secure configuration and cipher suite
  • Enable the .php file extension, and pass PHP scripts to php5-fpm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
server {
       listen         80;
       server_name    my.test.server.com;
       return         301 https://$server_name$request_uri;
}
 
# HTTPS server
server {
        listen 443;
        root /var/www;
        index index.php index.html index.htm;
        server_name my.test.server.com;
        location / {
                try_files $uri $uri/ /index.html;
        }
        error_page 404 /404.html;
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
              root /var/www;
        }
        # pass PHP to php5-fpm
        location ~ \.php$ {
                try_files $uri =404;
                fastcgi_pass unix:/var/run/php5-fpm.sock;
                fastcgi_index index.php;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                include fastcgi_params;
        }
        ssl on;
        ssl_certificate /etc/ssl/test.chain.crt;
        ssl_certificate_key /etc/ssl/test.key;
        ssl_session_timeout 5m;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK';
        ssl_prefer_server_ciphers on;
}
Now whereas Apache2 has a SSLCertificateChainFile directive for specifying a certificate chain, Nginx does not. In this case, the server certificate and any chained certificates are all placed into a single file, starting with my server certificate, and followed by two certificates in the chain:
1
2
3
4
5
6
7
8
9
10
11
12
-----BEGIN CERTIFICATE-----
MIIFejCCBGKgAwIBAgIQTHWks9xOahzb+5+AyIO3jjANBgkqhkiG9w0BAQsFADCB
(...)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFdDCCBFygAwIBAgIQJ2buVutJ846r13Ci/ITeIjANBgkqhkiG9w0BAQwFADBv
(...)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIGCDCCA/CgAwIBAgIQKy5u6tl1NmwUim7bo3yMBzANBgkqhkiG9w0BAQwFADCB
(...)
-----END CERTIFICATE-----
An in depth SSL tester is provided by Qualys here: https://www.ssllabs.com/ssltest/
Now test the configuration and assuming no errors, restart Nginx:
1
2
/etc/init.d/nginx configtest
/etc/init.d/nginx restart

Lastly, test that PHP is functioning as expected by editing /var/www/index.php:
1
2
3
$a = 5; $b = 10;
echo "$a + $b = " . ($a+$b) . "
\n"
;
?>
Then access index.php. In my case, I’ve used curl to verify. If the code is interpreted and evaluated successfully, the output will show:
nginx-php-success
If PHP has not been installed correctly, the script may be delivered as-is:
nginx-php-fail
In this case, go back and verify the installation and configuration as above, ensuring that Nginx and php5-fpm were both restarted after configuration changes were made.

No comments:

Post a Comment