Skip to content

Running Drupal on Nginx with Memcached

Drupal is a great CMS system for deploying websites quickly and managing them easily. Traditionally Drupal was run on a LAMP stack, but this configuration does not necessarily offer the best performance for the system. These days you can squeeze more performance out of Drupal by running it on a LEMP (Linux-Nginx-MySQL-PHP) stack in which Apache is replaced by the Nginx reverse-proxy. Further performance improvement can be gained by hooking up memcached to handle cacheing. This article explains how you can prepare a professional LEMP server for your Drupal sites.

Prerequisites

I assume you have a server available on which you have root privileges. I am using a server running Debian 7, so everything here should work the same on an Ubuntu server or other Debian-based distribution. If you're using an RPM-based distro (such as CentOS), you will need to replace the apt-get commands by their yum counterparts.

If you don't have a server to play with, I would recommend the inexpensive VPS servers offered by Digital Ocean. If you click through this link when signing up, you'll pay a bit of my server bill :)

I'm also assuming you configured your DNS to point a domain at the server's IP. In this text, I assume it's example.com

Update your system

It'a always a good idea to keep every part of your system up-to-date and since APT makes is so simple, let's start with an update of the APT cache and a system upgrade (installing up-to-date versions of all packages).

$ sudo apt-get update
$ sudo apt-get upgrade

Install MySQL

$ sudo apt-get install mysql-server

During the installation process you will be asked for a password for the root user. If you don't set it during installation, you can set it later using the following command (substitute a password for NEWPASSWORD).

$ mysqladmin -u root password NEWPASSWORD

Install Nginx

$ sudo apt-get install nginx

$ sudo service nginx start

You can navigate to your server (http://example.com) with your browser and Nginx should greet you with the words "Welcome to nginx!".

Install PHP-FPM

Under Apache PHP code is executed by the web server (via mod_php). The Nginx philosophy is somewhat different. It's a reverse proxy rather then a server, so it's not running any code itself. Instead it can serve (proxy) data generated by CGI applications running on your system.

For PHP this is PHP-FPM (FastCGI Process Manager). This is a daemon process which waits for incoming requests to execute PHP code, runs the scripts and returns their output. More information can be found on the PGP-FPM site.

sudo apt-get install php5-fpm

Configure PHP-FPM

Edit the /etc/php5/fpm/php.ini and change cgi.fix_pathinfo to 0.

sudo vim /etc/php5/fpm/php.ini
; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI.  PHP's
; previous behavior was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok
; what PATH_INFO is.  For more information on PATH_INFO, see the cgi specs.  Setting
; this to 1 will cause PHP CGI to fix its paths to conform to the spec.  A setting
; of zero causes PHP to behave as before.  Default is 1.  You should fix your scripts
; to use SCRIPT_FILENAME rather than PATH_TRANSLATED.
; http://php.net/cgi.fix-pathinfo
cgi.fix_pathinfo=0

Now check the php5-fpm configuration file /etc/php5/fpm/pool.d/www.conf and make sure that php5-fpm communicates with the outside world through a socket file:

listen = /var/run/php5-fpm.sock

Restart the php-fpm service:

sudo service php5-fpm restart

Install Drush and Drupal

Install Drupal dependencies

$ sudo apt-get install php5-mysql
$ sudo apt-get install php5-gd

Create a MySQL database and user for Drupal.

$ mysql -u root -p

mysql> CREATE DATABASE example;
mysql> GRANT ALL PRIVILEGES ON example.* TO example@localhost IDENTIFIED BY 'hskd7e345kfi';

Install Drush

$ sudo apt-get install drush

Install Drupal in any way you prefer, for instance using Drush like this:

$ cd /webapps/ # Or wherever you want to keep your sites
$ drush dl drupal-7.22
$ mv drupal-7.22/ example-drupal
$ cd example-drupal
$ drush site-install standard --account-name=admin --account-pass=admin --db-url=mysql://example:hskd7e345kfi@localhost/example

Create an Nginx virtual server configuration for Drupal

Each Nginx virtual server should be described in a file in the /etc/nginx/sites-available directory. You select which sites you want to enable by making symbolic links to those in the /etc/nginx/sites-enabled directory.

Create a new nginx server configuration file for your Drupal site running on example.com in /etc/nginx/sites-available/example-drupal. The file should contain something along the following lines. A good explanation can be found on the Nginx wiki.

example-drupal.nginxconf
server {
        server_name example.com;       ## <-- Your domain.
        root /webapps/example-drupal;  ## <-- Path to your Drupal files.

        # Enable compression, this will help if you have for instance advagg module
        # by serving Gzip versions of the files.
        gzip_static on;

        location / {
                try_files $uri @rewrite;
        }

        location @rewrite {
                rewrite ^ /index.php;
        }

        location ~ \.php$ {
                fastcgi_split_path_info ^(.+\.php)(/.+)$;
                #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
                include fastcgi_params;
                fastcgi_param SCRIPT_FILENAME $request_filename;
                fastcgi_intercept_errors on;
                fastcgi_pass unix:/var/run/php5-fpm.sock; ## <-- location of the PHP-FPM socket
        }

        location = /favicon.ico {
                log_not_found off;
                access_log off;
        }

        location = /robots.txt {
                allow all;
                log_not_found off;
                access_log off;
        }

        location ~ \..*/.*\.php$ {
                return 403;
        }

        # No no for private
        location ~ ^/sites/.*/private/ {
                return 403;
        }

        # Block access to "hidden" files and directories whose names begin with a
        # period. This includes directories used by version control systems such
        # as Subversion or Git to store control files.
        location ~ (^|/)\. {
                return 403;
        }

        location ~ ^/sites/.*/files/styles/ {
                try_files $uri @rewrite;
        }

        location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
                expires max;
                log_not_found off;
        }
}

Restart Nginx:

$ sudo service nginx restart

You can now visit your Drupal site at http://example.com and log in as admin with the password admin. Remember to change your password.

Add memcached as Drupal's cache backend

Install memcached and the memcache PHP extension.

$ sudo apt-get install memcached
$ sudo apt-get install php5-memcached

Edit the php.ini file to enable the extension and configure memcache. At minimum add the following lines:

extension=memcached.so
memcache.hash_strategy="consistent"

In order to enable memcached-based cacheing on your Drupal site, you will need to download and enable the memcache module:

$ cd /webapps/example-drupal
$ drush dl memcache
$ drush en memcache

You will also need to add cache_backends configuration to your settings.php file.

$ vim sites/default/settings.php

Add the following lines:

$conf['cache_backends'][] = 'sites/all/modules/memcache/memcache.inc';
$conf['cache_default_class'] = 'MemCacheDrupal';
$conf['cache_class_cache_form'] = 'DrupalDatabaseCache';

Your site is now cached using memcache. You can enable a module which installed along memcache, which will display a summary of how many memcache hits or misses were executed during the generation of every page in the admin.

$ drush en memcache_admin

That's it, I hope it helps. If you have any problems or see areas which could be improved, feel free to leave me a comment or send me a message.