Back to top

Add new comment

Build Nginx + PHP-FPM + APC + Memcache + Drupal 7 on a bare-bone Ubuntu 10.04 or Debian 5 server

I am not hosting administration expert, nor intent to make this tutorial post as generic as it would work for everybody. Since the stack: Nginx + PHP-FPM + APC + Memcache + Drupal 7 is quite on the cutting edge at the moment (Oct.2010), and there is not many 'master' tutorials available. Therefore, I am writing down my notes here for sharing.

This note is also reviewed and improved by Eric E Moore from Brandorr Inc

I got a bare-bone Debian 5 from, then, here is how it goes:

1.) Configure SSH and accounts to make it more secure; login as root (This step is optional). I used this source

aptitude update
aptitude upgrade
aptitude install locales
dpkg-reconfigure locales (# then select en_US.UTF8)
aptitude install build-essential
adduser admin

The visudo command will open up the /etc/sudoers file. All you need to do to grant sudo privileges to admin is to add a line beneath root’s, so that it looks like this:

# User privilege specification
root ALL=(ALL) ALL
admin ALL=(ALL) ALL

Now exit your SSH connection as root, and re-login as admin

Turn off root login

sudo nano /etc/ssh/sshd_config
# Authentication:
PermitRootLogin no

Now go ahead and restart ssh.

sudo /etc/init.d/ssh restart

we’ll go ahead and secure the firewall in your iptables by adding rules:

sudo nano /etc/iptables.rules

Add the rules seen in the example below so that your /etc/iptables.rules looks just like it. These rules state that outgoing connections are just fine, but all incoming traffic to any port other than 80, 443, 22 or 21 is blocked — unless it’s already been established legitimately.


# Allow loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use the lo0 interface
-A INPUT -i lo -j ACCEPT
-A INPUT -i ! lo -d -j REJECT

# Accept established inbound connections

# Allow all outbound traffic

# Allow HTTP and HTTPS connections
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT

# Allow SSH/SFTP
# Change the value 22 if you are using a non-standard port
-A INPUT -p tcp -m state --state NEW --dport 22 -j ACCEPT

# Allow FTP
# Purely optional, but required for WordPress to install its own plugins or update itself.
-A INPUT -p tcp -m state --state NEW --dport 21 -j ACCEPT

# Allow PING
# Again, optional. Some disallow this altogether.
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT

# Reject ALL other inbound

Now, load the rules:

sudo iptables-restore < /etc/iptables.rules
sudo iptables-save < /etc/iptables.rules

Last step make sure they’re saved and reloaded at bootup:
For Ubuntu 10.04

sudo nano /etc/network/interfaces.template

For Debian 5

sudo nano /etc/network/interfaces

Insert “pre-up iptables-restore < /etc/iptables.rules" as the third line in the file so it looks like this:

auto lo
iface lo inet loopback
pre-up iptables-restore < /etc/iptables.rules
up ip route replace dev lo

Now reboot the server.

sudo reboot

2.) Install dependencies:

(There is a great tutorial written in 2008, based on that, I have updated a few steps, and added a few things for Drupal 7:)

sudo aptitude install make bison flex gcc patch autoconf locate libxml2-dev libbz2-dev libpcre3-dev libssl-dev zlib1g-dev libmcrypt-dev libmhash-dev libmhash2 libcurl4-openssl-dev libpng3-dev libjpeg-dev libxslt-dev libmysqlclient15-dev libfreetype6 libfreetype6-dev

3.) Compile PHP from source with PHP-FPM patches:
Because Drupal 7 still has compatibility issue with PHP.5.3.x at the moment. So, we will use the latest 5.2.x version. At the time that this blog was written, the latest version was 5.2.17

cd /usr/local/src/
sudo wget
sudo tar -xvzf php-5.2.17.tar.gz
sudo wget
sudo gzip -cd php-5.2.17-fpm-0.5.14.diff.gz | sudo patch -d php-5.2.17 -p1
cd php-5.2.17
sudo ./configure --enable-fastcgi --enable-fpm --with-mcrypt --with-zlib --enable-mbstring --enable-pdo --with-curl --disable-debug --with-pic --disable-rpath --enable-inline-optimization --with-bz2 --enable-xml --with-zlib --enable-sockets --enable-sysvsem --enable-sysvshm --enable-pcntl --enable-mbregex --with-mhash --with-xsl --enable-zip --with-pcre-regex --with-gd --without-pdo-sqlite --with-pdo-mysql --without-sqlite --with-jpeg-dir=/usr/lib --with-png-dir=/usr/lib --with-freetype-dir=/usr/lib --with-mysql --with-mysqli
sudo make all install
sudo strip /usr/local/bin/php-cgi
sudo cp sapi/cgi/fpm/php-fpm /etc/init.d/
sudo chmod +x /etc/init.d/php-fpm
4.) Install Memcache and APC
Please note when you build the APC extension, make sure you turn off the option to compile for apache, since we will be using Nginx.

sudo pecl install memcache
sudo pecl install apc

5.) Copy & Paste configuration files

sudo cp /usr/local/src/php-5.2.17/php.ini-recommended /usr/local/lib/php.ini
sudo mkdir /etc/php/
sudo ln -s /usr/local/lib/php.ini /etc/php/php.ini
sudo ln -s /usr/local/etc/php-fpm.conf /etc/php/php-fpm.conf

6.) Update Permission for PHP-FPM at /etc/php/php-fpm.conf

<value name="owner">www-data</value>
<value name="group">www-data</value>
<value name="user">www-data</value>
<value name="group">www-data</value>

7.) Compile Nginx from source:
Altough Nginx is already available in the Ubuntu third-party module repositories, the version is updated. Therefore, we are going to complie nginx from the latest stable version. Please go to to find the lastest stable version:

cd ..
sudo wget
sudo tar -zxvf nginx-1.0.5.tar.gz
cd nginx-1.0.5.tar.gz
sudo ./configure --sbin-path=/usr/local/sbin --with-http_ssl_module --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module --with-http_stub_status_module
sudo make && sudo make install

8.) Edit Nginx configuration at /usr/local/nginx/conf/nginx.conf, please change the lines blew:

user www-data;
worker_processes 6;
events {
worker_connections 1024;

http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 10 10;

gzip on;
gzip_comp_level 1;
gzip_proxied any;
gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;

log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx_access.log main;
error_log /var/log/nginx_error.log debug;
include /usr/local/nginx/sites-enabled/*;
9.) Concatenate the parameters below to /usr/local/nginx/conf/fastcgi_params

fastcgi_connect_timeout 60;
fastcgi_send_timeout 180;
fastcgi_read_timeout 180;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;

10.) create a SystemV style init script and store it in /etc/init.d/nginx. You can download the script from , and make it executable sudo chmod +x /etc/init.d/nginx

11.) Set Up Your Site, here I use as an example:
First, we’re going to prep the directory where your sites will reside by adding them to the www-data group (the server’s). We’ll add your main user to the same group first, to make things run more smoothly.

sudo mkdir -p /srv/www/{public_html,logs}
sudo usermod -a -G www-data admin
sudo chown -R www-data:www-data /srv/www
sudo chmod -R 775 /srv/www
sudo mkdir -p /usr/local/nginx/{sites-available,sites-enabled}
sudo nano /usr/local/nginx/sites-available/

server {
root /srv/www/; ## <-- Your only path $
access_log /srv/www/;
error_log /srv/www/;

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

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

# This matters if you use drush
location = /backup {
deny all;

# Very rarely should these ever be accessed outside of your lan
location ~* \.(txt|log)$ {
deny all;

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

location / {
# This is cool because no php is touched for static content
try_files $uri @rewrite;

location @rewrite {
# Some modules enforce no slash (/) at the end of the URL
# Else this rewrite block wouldn't be needed (GlobalRedirect)
rewrite ^/(.*)$ /index.php?q=$1;

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 $document_root$fastcgi_script_name;

# Fighting with ImageCache? This little gem is amazing.
location ~ ^/sites/.*/files/styles/ {
try_files $uri @rewrite;

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

12.) Install MySQL

sudo aptitude install mysql-server
sudo mysql_secure_installation

13.) Install Drupal 7

cd /srv/www/
sudo wget
sudo tar -xvzf drupal-7.0.tar.gz
sudo cp drupal-7.0/* public_html/ -R
sudo chown www-data:www-data public_html -R

13.1. (Optional) Now create a database table, and install Drupal 7. It might be helpful to install phpmyadmin. The detail is no longer the main focus of this blog.

sudo aptitude install phpmyadmin

Hit ESC when the installation prompts you for auto-configuration, because there is no option for Nginx.

sudo ln -s /usr/share/phpmyadmin/ /srv/www/

14.) Update php.ini file to include three extensions:

sudo ln -s /usr/local/lib/php/extensions/no-debug-non-zts-20060613/ /usr/lib/php5/20060613+lfs/
sudo ln -s /usr/local/lib/php/extensions/no-debug-non-zts-20060613/ /usr/lib/php5/20060613+lfs/
sudo chmod +x /etc/init.d/php-fpm
sudo nano /etc/php/php.ini

Make the changes below:

extension_dir = "/usr/lib/php5/20060613+lfs/"

15.) Start It Up

cd /etc/rc2.d
* sudo rm S91apache2 if apache2 is installed by phpmyadmin
* sudo /etc/init.d/apache2 stop
sudo ln -s ../init.d/nginx S30nginx
sudo ln -s ../init.d/php-fpm S20php-fpm
sudo ln -s /usr/local/nginx/sites-available/ /usr/local/nginx/sites-enabled/
sudo php-fpm start
sudo /etc/init.d/nginx start