Apacheless web-server on Debian Squeeze with nginx and php-fpm

Threre are tons of information on now to setup "parts" that making fully functional web server plaftorm, but usually without giving summary view. We're going to explain all steps on you how to get your LAMP web server up. Things you should have:

  1. Virtual or real personal (dedicated) server hosting. You'd better have 5Gb of disk space and 256 RAM. Not really enough for Apache but ok for Nginx
  2. Root (Administrator) access to server via Secure Shell (SSH)
  3. Domain name and control access to it (usually provided by domain name registration services)

We are going to setup web server to be able run Drupal7 (or any other PHP CMS/Website)

1. System Preparation

We will need to install php5-fpm package. For debian you may find it in repository. Add it to your /etc/apt/sources.list by following command:

$sudo echo "deb stable all" >> /etc/apt/sources.list

and import GPG key:

$sudo cat dotdeb.gpg | apt-key add -

then update apt indexes:

$sudo apt-get update

2. Install and Setup

Lets install all necessary

$sudo apt-get install nginx php5-cli php5-common php5-suhosin php5-cgi php5-fpm mysql-server php5-mysql php-gb

Then configure Nginx (/etc/nginx/nginx.conf) reffereing to this example:

user www-data;
worker_processes 1; # Set accoring to number of processor cores
pid /var/run/;
timer_resolution 100ms;
worker_rlimit_nofile 8192;
worker_priority -5; # Increase processes priority
error_log  /var/log/nginx/error.log;
events {
        worker_connections 1024;
        # multi_accept on;

http {
        # Basic Settings
        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;
        keepalive_timeout 65;

       types_hash_max_size 2048;
        server_tokens off; # hide server info on errors
        include /etc/nginx/mime.types;
        default_type application/octet-stream;
        # Gzip Settings
gzip on;
gzip_disable "msie6";
gzip_min_length 1100;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 4; 

gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
        # Virtual Host Configs
        include /etc/nginx/conf.d/*.conf;
        include /etc/nginx/sites-enabled/*;

This example differs from "out-of-box" config only a bit. But some options from default config like gzip_disable "msie6"; will certainly not work on old Nginx versions.

Now we should define FastCgi configuration parameters in file /etc/nginx/fastcgi_params as follows:

fastcgi_param   QUERY_STRING            $query_string;
fastcgi_param   REQUEST_METHOD          $request_method;
fastcgi_param   CONTENT_TYPE            $content_type;
fastcgi_param   CONTENT_LENGTH          $content_length;

fastcgi_param   SCRIPT_FILENAME         $request_filename;
fastcgi_param   SCRIPT_NAME             $fastcgi_script_name;
fastcgi_param   REQUEST_URI             $request_uri;
fastcgi_param   DOCUMENT_URI            $document_uri;
fastcgi_param   DOCUMENT_ROOT           $document_root;
fastcgi_param   SERVER_PROTOCOL         $server_protocol;

fastcgi_param   GATEWAY_INTERFACE       CGI/1.1;
fastcgi_param   SERVER_SOFTWARE         nginx/$nginx_version;

fastcgi_param   REMOTE_ADDR             $remote_addr;
fastcgi_param   REMOTE_PORT             $remote_port;
fastcgi_param   SERVER_ADDR             $server_addr;
fastcgi_param   SERVER_PORT             $server_port;
fastcgi_param   SERVER_NAME             $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param   REDIRECT_STATUS         200;

As we will possibly have a number of domains we should create one common configuration and include it in invididual configuration files

common configuration is stored in file /etc/nginx/template

#Drupal specific rewriting configuration
    location / {
        try_files $uri $uri/ /index.php?q=$uri&$args;

# pass php requests to php-fpm
    location ~ \.php$ {

# It's better to connect php script via socket as on some servers number of concurent TCP connections can be limited
#fastcgi_pass unix:/var/run/php-fpm/phpsock.sock;

        fastcgi_index  index.php;
        fastcgi_intercept_errors on; # display errors use only for testing
#Include params from /etc/nginx/fastcgi_param
        include fastcgi_params;
        fastcgi_ignore_client_abort     off;
#Do not allow to view  .htaccess and .htpassword
    location ~ /\.ht {
        deny  all;

Then remove file /etc/nginx/sites-enabled/default and create domain specific configuration files instead with contents similar to:

server {
        listen 80; # you may set domain name here e.g.
        server_name *
        rewrite ^(.*)$$1 permanent;
server {
        listen 80; 
        root /var/www/;
        index index.php;
        include template; #include common options
        # setup logging
        access_log /var/log/nginx/;
        error_log /var/log/nginx/;

Create directories for CMS/website files and set permissions:

$sudo chown www-data:www-data -R /var/www
$sudo chmod -R a-rwx,u+rwX,g+rX /var/www

Don't forget to restatr php5-fpm after any PHP settings modifications !

$sudo service nginx reload
$sudo service php5-fpm restart

3. Performance tweaks

We should make some performance tuning to make server less hungry with resources. If you have small abount of RAM and no swap then create it:

$sudo dd if=/dev/zero of=/swapfile bs=1M count=1024
$sudo mkswap /swapfile
$sudo swapon /swapfile
$sudo echo '/swapfile swap swap defaults 0 0' >> /etc/fstab

Now even if all your RAM is eaten server will no fall down

We should also set stack size usually it's set to 10 Megabytes and stack is not used, lets reduce stack to 1 Megabyte in file /etc/security/limits.conf:

*       soft    stack   1024

This means that our stack is more "soft" now.

Now lets tune MySQL. Install performance checker first:

$sudo apt-get install mysqltuner

run it and see the results. You can also disable InnoDB that is slower on queries, but gives you transactions and some other quite helpful stuff, google and decide what engine you want to use. To use MyISAM engine write skip-innodb option to [mysqld] section of file /etc/mysql/my.cnf

You can also install cache and accellerator for PHP:

$sudo apt-get install php-apc

It has lots of options but even byt default it can speed up PHP up to 1.5-2 times

Lets get back to php-fpm and add some more options to file /etc/php5/fpm/pool.d/www.conf

# dynamic process creation, the number of processes will depent on load level
pm = dynamic
# maximum number of process, 7 is for weak servers
pm.max_children = 7
# creating new process takes tim and we will run some on server start 
pm.start_servers = 3
# Minimum number of processes allowed for hold. Should be less than max 
#pm.start_servers =pm.min_spare_servers is ok for us
pm.min_spare_servers = 3
# Maximum number of process allowed on hold
#  should not be less than pm.min_spare_servers
pm.max_spare_servers = 4

You should rely on trying and testing with this option. For example the following configuration:

pm.max_children = 5000
pm.start_servers = 300
pm.min_spare_servers = 200
pm.max_spare_servers = 500

has eated up to 12 Gb of RAM and 2-3 Gb of swap. Keep your options actuall to your load level.

It's also helpful to install and setup log rotation (e.g. with package logrotate) as logs are grown very fast.


I've performed some testing and have the following thoughts:

  1. Apache eats less memory initially but usage growth fater, Nginx can eat more that Apache without load but will no increase usage so drammatically
  2. Don't know why but Nginx swaped more actively
  3. If load is extremely high Apache freezes but Nginx just starts to work slower
  4. Nginx is fater with freeing recources

To make your own tests and assumtions you cat use service that allows you to emulate up to concurent 50 users for free. There is also siege measurement utility it's quite simple to use.


This article was originally translated from: [RU]

Some examples where taket from:

Thanks also to all that helped to author in discussions



04-08-2011 07:32: swk
just wanted to say nice guide. It helped a lot ;)