Nginx with PHP-FPM on Ubuntu 14.04 for Drupal

Last modified
Monday, February 6, 2017 - 01:04

Another good option to run Drupal sites nowadays is Nginx. Nginx is a Proxy/Web Server not as complex as Apache and is well known for is security, responsiveness and speed when handling PHP apps together with PHP-FMP. On this this post I will introduce you on how to manually install and run Nginx and PHP-FPM so you can host any Drupal site with SSL support.

Recommended posts:

The suggested installation instructions by drupal.org: https://www.drupal.org/node/2310819
Perusio Nginx suggested Drupal Configuration https://github.com/perusio/drupal-with-nginx/tree/D7#installation
Perusio PHP-FPM suggested configuration https://github.com/perusio/php-fpm-example-config
Nginx recomendation for Drupal http://wiki.nginx.org/Drupal

Tutorials on attempts to install Perusio on Ubuntu 14.04:

http://komelin.com/en/5tips/right-nginx-configuration-drupal-ubuntu
https://www.drupal.org/node/2310819
Bad Gateway error 502 https://github.com/perusio/drupal-with-nginx/issues/160

Installing Nginx for Drupal is not an easy task and requires some configuration steps in order to have a full Drupal install running with mostly no issues. On this tutorial I will show you a way to install Perusio's suggested directives which after expending several hours researching the web and testing other recommendations, is the most reliable solution.

Alright, let's begin:

Install required packages

$sudo apt-get install nginx-extras php5-fpm php5-mysql php5-gd php5-curl php5-json

Configure PHP-FMP:

  • just a quick security tweak to prevent php to execute the closest file it can find if a PHP file does not match exactly. This basically would allow users to perform requests in a way that would allow them to execute scripts that they shouldn't be allowed to run, edit the following file:
    $sudo nano /etc/php5/fpm/php.ini
  • look for the line "#cgi.fix_pathinfo=0" uncoment it and switch the value 0 to 1 so the final result looks like this:
    cgi.fix_pathinfo=1
  • Follow Perusio's guide to configure PHP-FMP 
  • I found a few issues with the steps proposed by Perusio so I'm describing the steps i took in order to configure php-fpm.
  • clone the php-fpm repo on you home folder, make sure you are on the UNIX branch.
    • $cd ~/
    • $git clone https://github.com/perusio/php-fpm-example-config.git php-conf
    • $cd php-conf
    • git checkout unix
  • Replace the default php-fmp.conf file with the ones that comes with the repo
    • $sudo mv /etc/php5/fpm/php-fpm.conf /etc/php5/fpm/php-fpm.back
    • $sudo cp ~/php-conf/fpm/php5-fpm.conf /etc/php5/fpm/php-fpm.conf
  • Remove the default pool.d/folder and move the pool.d/ folder from the repo the php5/ folder so you can have the pre-configured pools by Perusio running.
    • $sudo rm -rf /etc/php5/fpm/pool.d
    • $sudo cp -a ~/php-conf/fpm/pool.d /etc/php5/fpm
  • The pool config files, www0.conf, www1.conf and www2.conf by default are defining a variable chdir with value = /var/www On a fresh Ubuntu install this folder does not exist and so it might trigger an error when running php-fpm, you can either modify the chdir value on each *.conf file to point to the default Nginx html folder /usr/share/nginx or you can create the missing directory.

you can now securely restart php-fpm:

$sudo service php5-fpm restart

by typing the following command you should see the sockets created by this configuration running:

$sudo ls -lah /var/run/ | grep php

this will output something similar to:

[[{"fid":"187","view_mode":"media_original","fields":{"format":"media_original","field_file_image_alt_text[und][0][value]":"","field_file_image_title_text[und][0][value]":""},"type":"media","attributes":{"height":"70","width":"784","class":"media-element file-media-original"}}]]

Now let's start with Nginx:

  • Follow Perusio's guide on how to checkout the D7 branch of the drupal-and-nginx files, checkout the files and move them to /etc/ folder
    • $cd ~/
    • $git clone https://github.com/perusio/drupal-with-nginx.git nginx
    • $cd nginx
    • $git checkout D7
    • $sudo rm -rf /etc/nginx
    • $sudo mv ~/nginx /etc/nginx
  • Open /etc/nginx/nginx.conf and comment out the line:
    • #include upstream_phpcgi_tcp.conf;
  • In the same file, uncomment:
    • include upstream_phpcgi_unix.conf;
    • variables_hash_max_size 1024;
    • include php_fpm_status_allowed_hosts.conf;
    • include nginx_status_allowed_hosts.conf;
    • include apps/drupal/cron_allowed_hosts.conf;
  • Comment out the AIO directive, this Input/Output module does not come bundled on the ubuntu nginx-extras package an so it will trigger an error when trying to run the vhost, we need to comment out the aio support in order to avoid the warning or you could try installing Nginx by compiling it. We need to edit the drupal.conf file inside the apps/ folder
    • $sudo nano /etc/nginx/apps/drupal/drupal.conf
    • find the directive aio on; and comment it out
    • #aio on; (lines 149, 160)
  • At the time of writing of this post, there is a bug reported on Perusio's github issue queue that describes a Bad Gateway error due to a misconfiguration on one of the provided files, in order to fix it, you need to comment out the conflicting line, open and edit:
    • $sudo nano /etc/nginx/upstream_phpcgi_unix.conf
    • comment out the line that says keepalive 5
    • # keepalive 5;

SSL Support, create Self Signed Certificates for Nginx in the folder /etc/nginx/ssl (testing only)

$sudo mkdir /etc/nginx/ssl
$cd /etc/nginx/ssl
$sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt

Create folder required for microcaching:

$sudo mkdir -p /var/cache/nginx/microcache

Create you Virtual Host definition file:

$sudo nano /etc/nginx/sites-available/myvhost.com.conf

This is a sample configuration of a virtual host based on the example.com.conf provided by Perusio, you can modify it according to your needs:


# -*- mode: nginx; mode: flyspell-prog;  ispell-current-dictionary: american -*-
### Configuration for myvhost.com.

## HTTP server.
server {
    listen 80; # IPv4
    ## Replace the IPv6 address by your own address. The address below
    ## was stolen from the wikipedia page on IPv6.
    #listen [fe80::202:b3ff:fe1e:8330]:80 ipv6only=on;

    server_name myvhost.com;
    limit_conn arbeit 32;

    ## Access and error logs.
    access_log /var/log/nginx/myvhost.com_access.log;
    error_log /var/log/nginx/myvhost.com_error.log;

    ## See the blacklist.conf file at the parent dir: /etc/nginx.
    ## Deny access based on the User-Agent header.
    if ($bad_bot) {
        return 444;
    }
    ## Deny access based on the Referer header.
    if ($bad_referer) {
        return 444;
    }

    ## Protection against illegal HTTP methods. Out of the box only HEAD,
    ## GET and POST are allowed.
    if ($not_allowed_method) {
        return 405;
    }

    ## Filesystem root of the site and index.
    root /usr/share/nginx/myvhost;
    index index.php;

    ## If you're using a Nginx version greater or equal to 1.1.4 then
    ## you can use keep alive connections to the upstream be it
    ## FastCGI or Apache. If that's not the case comment out the line below.
    fastcgi_keep_conn on; # keep alive to the FCGI upstream

    ## Uncomment if you're proxying to Apache for handling PHP.
    #proxy_http_version 1.1; # keep alive to the Apache upstream

    ################################################################
    ### Generic configuration: for most Drupal 7 sites.
    ################################################################
    include apps/drupal/drupal.conf;

    ################################################################
    ### Configuration for Drupal 7 sites to serve URIs that need
    ### to be **escaped**
    ################################################################
    #include apps/drupal/drupal_escaped.conf;

    #################################################################
    ### Configuration for Drupal 7 sites that use boost.
    #################################################################
    #include apps/drupal/drupal_boost.conf;

    #################################################################
    ### Configuration for Drupal 7 sites that use boost if having
    ### to serve URIs that need to be **escaped**
    #################################################################
    #include apps/drupal/drupal_boost_escaped.conf;

    #################################################################
    ### Configuration for updating the site via update.php and running
    ### cron externally. If you don't use drush for running cron use
    ### the configuration below.
    #################################################################
    include apps/drupal/drupal_cron_update.conf;

    ################################################################
    ### Installation handling. This should be commented out after
    ### installation if on an already installed site there's no need
    ### to touch it. If on a yet to be installed site. Uncomment the
    ### line below and comment out after installation. Note that
    ### there's a basic auth in front as secondary ligne of defense.
    ################################################################
    #include apps/drupal/drupal_install.conf;

    #################################################################
    ### Support for upload progress bar. Configurations differ for
    ### Drupal 6 and Drupal 7.
    #################################################################
    include apps/drupal/drupal_upload_progress.conf;

    ## Including the php-fpm status and ping pages config.
    ## Uncomment to enable if you're running php-fpm.
    #include php_fpm_status_vhost.conf;

    ## Including the Nginx stub status page for having stats about
    ## Nginx activity: http://wiki.nginx.org/HttpStubStatusModule.
    include nginx_status_vhost.conf;

} # HTTP server

## HTTPS server.
server {
    ## Comment the line below if you're using SPDY.
    listen 443 ssl;
    ## Uncomment the line below if you're using SPDY.
    #listen 443 ssl spdy;
    ## Replace the IPv6 address by your own address. The address below
    ## was stolen from the wikipedia page on IPv6.

    ## Comment the line below if you're using SPDY.
    #listen [fe80::202:b3ff:fe1e:8330]:443 ssl ipv6only=on;
    ## Uncomment the line below if you're using SPDY.
    #listen [fe80::202:b3ff:fe1e:8330]:443 ssl spdy ipv6only=on;

    server_name myvhost.com;

    limit_conn arbeit 32;

    ## Access and error logs.
    access_log /var/log/nginx/myvhost.com_access.log;
    error_log /var/log/nginx/myvhost.com_error.log;

    ## Keep alive timeout set to a greater value for SSL/TLS.
    keepalive_timeout 75 75;

    ## See the keepalive_timeout directive in nginx.conf.
    ## Server certificate and key.
    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;

    ## Strict Transport Security header for enhanced security. See
    ## http://www.chromium.org/sts. I've set it to 2 hours; set it to
    ## whichever age you want.
    add_header Strict-Transport-Security "max-age=7200";

    root /usr/share/nginx/myvhost;
    index index.php;

    ## If you're using a Nginx version greater or equal to 1.1.4 then
    ## you can use keep alive connections to the upstream be it
    ## FastCGI or Apache. If that's not the case comment out the line below.
    fastcgi_keep_conn on; # keep alive to the FCGI upstream

    ## Uncomment if you're proxying to Apache for handling PHP.
    #proxy_http_version 1.1; # keep alive to the Apache upstream

    ## See the blacklist.conf file at the parent dir: /etc/nginx.
    ## Deny access based on the User-Agent header.
    if ($bad_bot) {
        return 444;
    }
    ## Deny access based on the Referer header.
    if ($bad_referer) {
        return 444;
    }

    ## Protection against illegal HTTP methods. Out of the box only HEAD,
    ## GET and POST are allowed.
    if ($not_allowed_method) {
        return 405;
    }

    ################################################################
    ### Generic configuration: for most Drupal 7 sites.
    ################################################################
    include apps/drupal/drupal.conf;

    ################################################################
    ### Configuration for Drupal 7 sites to serve URIs that need
    ### to be **escaped**
    ################################################################
    #include apps/drupal/drupal_escaped.conf;

    #################################################################
    ### Configuration for Drupal 7 sites that use boost.
    #################################################################
    #include apps/drupal/drupal_boost.conf;

    #################################################################
    ### Configuration for Drupal 7 sites that use boost if having
    ### to serve URIs that need to be **escaped**
    #################################################################
    #include apps/drupal/drupal_boost_escaped.conf;

    #################################################################
    ### Configuration for updating the site via update.php and running
    ### cron externally. If you don't use drush for running cron use
    ### the configuration below.
    #################################################################
    include apps/drupal/drupal_cron_update.conf;

    ################################################################
    ### Installation handling. This should be commented out after
    ### installation if on an already installed site there's no need
    ### to touch it. If on a yet to be installed site. Uncomment the
    ### line below and comment out after installation. Note that
    ### there's a basic auth in front as secondary ligne of defense.
    ################################################################
    #include apps/drupal/drupal_install.conf;

    #################################################################
    ### Support for upload progress bar. Configurations differ for
    ### Drupal 6 and Drupal 7.
    #################################################################
    include apps/drupal/drupal_upload_progress.conf;

    ## Including the php-fpm status and ping pages config.
    ## Uncomment to enable if you're running php-fpm.
    #include php_fpm_status_vhost.conf;

    ## Including the Nginx stub status page for having stats about
    ## Nginx activity: http://wiki.nginx.org/HttpStubStatusModule.
    include nginx_status_vhost.conf;

} # HTTPS server

Enable your Virtual Host, make sure the /etc/nginx/sites-enabled folder exists:

$sudo mkdir /etc/nginx/sites-enabled
$sudo ln -s /etc/nginx/sites-available/myvhost.com.conf /etc/nginx/sites-enabled/myvhost.com

Add the new site to the hosts file:

$sudo nano /etc/hosts

Enter the following:

127.0.0.1    myvhost.com

Restart Nginx so changes can take place:

$sudo service nginx restart

If restarting fails, you can try running Nginx as a command and it will output any errors

$sudo nginx

There you go! open you browser and go to http://myvhost.com and you should see the content of the drupal site.

Add new comment

This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.