Drupal 6 Hosting With nginx And PHP-FastCGI On Ubuntu 9.10

Drupal is a great CMS but is a bit hefty when you host it on bargain-basement shared hosting, and virtual private servers are great but memory-constrained at the low-end. Apache can be a big offender when it comes to resource usage, so a nice alternative is nginx, a fast, light-weight and efficient http server that supports PHP via PHP-FastCGI. So this is a pretty slick setup for hosting Drupal, and I've taken a few different howtos and forum posts to put together this guide, which should have all you need in one stop, including a working URL rewrite config.

If you're on a VPS, your hosting provider will do the operating system and OpenSSH server installation. For those who are doing this on your own computer or VM, rather than re-hash Falko's excellent server installation guide, I'm going to send you there first for steps 1 through 3:

The Perfect Server - Ubuntu 9.10 [ISPConfig 3]

Ok, so the next thing we're going to do is become root. Type:

sudo su -l

Next, we're going to remove the requirement to type your password each time you use sudo. Feel free to skip this step if you like:


If it asks, I use nano as a text editor, and I'll continue to use it. Feel free to replace this with your own text editor of choice.

Change the line:

%admin ALL=(ALL): ALL



And save and exit with Ctrl-w and Ctrl-x.

Next we're going to install the requisite software. Install the following packages with the command:

aptitude install openssh-server nginx mysql-client mysql-server imagemagick php5 php5-cgi php5-cli php5-common spawn-fcgi php5-gd php5-imagick php5-imap php5-mysql

The installation is going to bring up a window asking you to create root password for MySQL. Enter it here. We'll need to use that password towards the end of this howto.

There are a few other packages you may want as well, for additional PHP features. You can install them with:

aptitude install php-auth php-pear php5-curl php5-idn php5-mcrypt php5-memcache php5-mhash php5-ming php5-pspell php5-recode php5-snmp php5-sqlite php5-tidy php5-xmlrpc php5-xsl mcrypt

Now, the default settings for these programs are pretty good, but there's a few changes we should make. First is nginx:

nano /etc/nginx/nginx.conf

And modify the following lines to start with:

worker_processes  3;
keepalive_timeout 10; ...

You as you get a bit more familiar with the the load and resources, you'll want to refine these further. Let's also modify the memory usage of PHP. When you're uploading images or especially video in Drupal, your upload size, execution time, and memory usage may prevent your uploads. So we're going to increase these sizes. Ideal values depend entirely on the memory available on your server. This is what I used on my VPS with 340MB RAM.

nano /etc/php5/cgi/php.ini

; Maximum allowed size for uploaded files.
upload_max_filesize = 50M
; Maximum size of POST data that PHP will accept.
post_max_size = 50M
; Resource Limits ;
max_execution_time = 120     ; Maximum execution time of each script, in seconds
max_input_time = 60 ; Maximum amount of time each script may spend parsing request data
;max_input_nesting_level = 64 ; Maximum input variable nesting level
memory_limit = 128M      ; Maximum amount of memory a script may consume (16MB)

Nginx passes php files to PHP-FastCGI for execution, so we need to create a couple scripts to launch PHP-FastCGI. To do so, type the following:

nano /usr/bin/php-fastcgi

and paste the following script:

/usr/bin/spawn-fcgi -a -p 9000 -u www-data -f /usr/bin/php5-cgi

Next, we need to make the script executable:

chmod a+x /usr/bin/php-fastcgi

The second script is an init script to call our previous script on boot. Type:

nano /etc/init.d/php-fastcgi

and paste the following script:

case "$1" in
      killall -9 php
      killall -9 php
      echo "Usage: php-fastcgi {start|stop|restart}"
      exit 1
exit $RETVAL

We need to set this as executable as well, and set it to execute on startup.

chmod 755 /etc/init.d/php-fastcgi
update-rc.d php-fastcgi defaults
service php-fastcgi start

Next let's create the home folders for your websites and set a few permissions. I prefer the /srv to /var/www but this is entirely a matter of preference. From here on, whenever you see example.com, update it to your settings.

mkdir -p /srv/www/www.example.com/public_html
mkdir /srv/www/www.example.com/logs
chown -R www-data:www-data /srv/www/www.example.com

Next, we create an nginx configuration for out site.

nano /etc/nginx/sites-available/www.example.com

And paste:

server {
    listen   80;
#   server_name _   # catch-all
    server_name example.com www.example.com;
    access_log /srv/www/www.example.com/logs/access.log;
    error_log /srv/www/www.example.com/logs/error.log;
    root   /srv/www/www.example.com/public_html;
    index  index.php;
    location / {
        if (!-e $request_filename) {
            rewrite ^/(.*)$ /index.php?q=$1 last;
    # serve static files directly
    location ~* ^.+\.(jpg|jpeg|gif|css|png|js|ico)$ {
        rewrite ^/favicon.ico$ /sites/default/themes/mytheme/favicon.ico break;
        access_log        off;
        expires           30d;
    # If you use the Imagecache module, you'll need to update the location and enable this directive
    #location ^~ /sites/default/files/imagecache/ {
    #    index  index.php index.html;
    #    # assume a clean URL is requested, and rewrite to index.php
    #    if (!-e $request_filename) {
    #        rewrite  ^/(.*)$  /index.php?q=$1  last;
    #        break;
    #    }
    location ~ \.php$ {
        include /etc/nginx/fastcgi_params;
        fastcgi_index index.php;
        fastcgi_param  SCRIPT_FILENAME  /srv/www/www.example.com/public_html$fastcgi_script_name;

Next, we enable the configuration:

cd /etc/nginx/sites-enabled/
ln -s /etc/nginx/sites-available/www.example.com

And lets reload nginx.

service nginx restart

Before going further, let's test out nginx and PHP.

nano /srv/www/www.example.com/public_html/index.php

Paste in the following code:

<? echo phpinfo(); ?>

And let's browse to your site. If your DNS isn't set up yet, you could add    example.com www.example.com

to your /etc/hosts on your Linux or OS X host, or to your c:\windows\system32\drivers\etc\hosts file in Windows, which will allow you to access your server by domain name.

So browse to http://www.example.com and ensure it works. If it does, we'll go on to install Drupal.

First thing we do is download and untar the files. This was the most recent when I downloaded it. Make sure you get the latest version 6.

cd /srv/www/www.example.com/public_html
wget http://ftp.drupal.org/files/projects/drupal-6.16.tar.gz
tar zxvf drupal-6.16.tar.gz

And let's move them into the right place and clean up a bit.

mv drupal-6.16/* .
rm -r drupal-6.16 drupal-6.16.tar.gz

Next, we have to set up a configuration file, as well as create a files directory.

cd sites/default/
cp default.settings.php settings.php
chown www-data:www-data settings.php
chmod 775 settings.php
mkdir files
chown www-data:www-data files
chmod 775 files

Drupal needs a MySQL database as well, so let's create one here:

mysql -u root -p

GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER ON drupaldb.* TO 'drupaluser'@'localhost' IDENTIFIED BY 'password';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER ON drupaldb.* TO 'drupaluser'@'localhost.localdomain' IDENTIFIED BY 'password';

Now browse to http://www.example.com

Choose Install Drupal in English

Then enter the information for the database you just created.

Step through, name your site and create the Administrator account.

Drupal uses a cron entry to perform maintenance and check for updates. Let's add that while we're at the terminal.

crontab -e

And add the following entry:

0   *   *   *   *   wget -O - -q -t 1 http://www.example.com/cron.php

Now, no Drupal setup is complete without at least the Admin Menu module.

cd /srv/www/www.example.com/public_html/sites/all
mkdir modules
cd modules
wget http://ftp.drupal.org/files/projects/admin_menu-6.x-1.5.tar.gz
tar zxvf admin_menu-6.x-1.5.tar.gz

You can then enable the module in the Modules menu. And there you go, you've got a Drupal installation working.

Now, there's a few more things to do that I'm not going to detail in this howto, but ought to be done. The first thing missing is any sort of e-mail setup. The second is locking down the server for production use. Otherwise, you're good to go.



Share this page:

7 Comment(s)

Add comment


From: Micheas at: 2010-04-13 10:00:51

Overall, a nice howto, but whether you see gains will depend on the particulars of the traffic and server configuration.

Most of the "apache" vs "nginx" are really mod_php vs fast-cgi.

 The gain you are getting by using fast-cgi is that you are not loading php to handle static files such as images, .txt and html files.

 mod_php is generally faster than fast-cgi for serving php files due to the apache module design (but fast-cgi is normally within 5%)

 However, the reduced memory foot print of not using mod_php while serving static files, means that you are less likely to start using swap, which is the noticible performance killer.

 Nginx is generally faster than apache with mod_php when serving static files (generally about 2-10%) and uses less memory.

 I like nginx and lighttpd, especially their non-blocking nature, but apache is an amazingly flexible webserver, that can be pushed to be competitive with nginx and lighttpd in the low end, and on the high end it may well be worth using both nginx or lighttpd and apache.

One other thing you might mention is that many people find that they have to restart their fast-cgi server periodically due to poorly written php programs, that show memory leaks over time.

 I restart mine weekly, but a few people have /etc/init.d/php-fastcgi restart in their daily crontab.

 One other comment, this howto configures nginx for clean urls without index.php in them. so you can just enable them in drupal.

From: Anonymous at: 2010-05-15 11:28:58

Thanks for your tutorial, really helpfull. Everything works correctly on my dev computer. Just wanted to test ngninx stuff. It will really help me to make website faster. I really see the difference in loading time on my personnal computer.

But I have an error that I really don't know how to resolve, I'm really a new to linux configuration...

In my admin reports status of my drupal website: 

GD Image Filtering Low Quality / Poor Performance
The installed version of PHP GD does not support image filtering(desaturate, blur, negate, etc). It was probably compiled using the official GD libraries from http://www.libgd.org instead of the GD library bundled with PHP. You should recompile PHP --with-gd using the bundled GD library. See http://www.php.net/manual/en/image.setup.php. An implementation of imagefilter in PHP will be used in the interim.
GD Image Rotation Low Quality / Poor Performance

The installed version of PHP GD does not support image rotations. It was probably compiled using the official GD libraries from http://www.libgd.org instead of the GD library bundled with PHP. You should recompile PHP --with-gd using the bundled GD library. See: http://www.php.net/manual/en/image.setup.php. An implementation of imagerotate in PHP will used in the interim.

How I could resolve this dependencies. I'm on Ubuntu 9.10. 

Thansk for your help.


From: komin at: 2010-05-31 10:52:34

I appreciate the work that you have put in this page. Really good, Thanks.

From: leonyang.tech at: 2010-09-01 21:38:18

Thanks for this great tutorial, but I am having problem with LDAP, i tried adding the extension=ldap.so to the php.ini but the phpinfo(); still does not show any information about ldap.

 Any helps are appreciated, thx.

From: Anonymous at: 2011-05-29 07:26:31

still working on figuring out my problem but the infamous nginx 502 gateway error appears, randomly

From: Anonymous at: 2011-05-31 00:29:55

apparently apt-get update / upgrade fixed the issue

From: Anonymous at: 2011-06-03 00:04:06

and the final comment from me in this thread. After getting the lates updates and upgrades the 502 error became less frequent, but it would still appear if i did something resource intensive and javascript, it would appear every time i worked with views module for a while. Finally i was able to completely resolve this issue.

In the nginx.conf i made sure to increase the worker processes to 4, worker_connections to 2048, comment out the multi accept, set keepalive to 0. Now i have ran sever loadimpact tests, bunch of views added, etc and the 502 issue has not reappeared. So i think the increasing the workers and worker connections is what finally did it. Obviously i am not a professional, but for someone who is banging their head on the wall over the "nginx 502 bad gateway" with drupal and fastcgi error i recommend this solution.