After some time with node.js I recently decided to move to nginx + php-fpm + node.js for my future servers. Here we will be installing:

  • Nginx as a fast HTTP server with reverse proxy to node.js
  • php-fpm for running PHP scripts. The php-fpm (PHP FastCGI sapi) is built into the PHP core but only since 5.3.3, so we need a recent version of PHP.
  • node.js for handling comet and high-concurrency/persistent connections.
  • Monit is used to restart node.js in case of errors.

For all the packages other than node.js (obviously, since it's new/actively changing), you can get the most recent version without to patching/compiling anything anymore.

Start by updating your packages and uninstalling httpd if you had it installed:

yum update
yum remove httpd

Add repositories for nginx and PHP-fpm

Just add the EPEL and Remi repos: bash rpm -Uvh rpm -Uvh

Install nginx and PHP-fpm

Remi has the php-fpm package (php 5.3.4); EPEL has nginx:

yum --enablerepo=remi install php-fpm nginx

Some other common packages:

yum --enablerepo=remi install mysql mysql-server php-mysql php-common php-gd php-mbstring php-mcrypt php-xml php-gd php-bcmath

PHPunit and PHPdocumentor:

yum --enablerepo=remi install php-channel-phpunit php-pear-PhpDocumentor php-phpunit-PHPUnit

Create a test application

mkdir /var/www/

In /var/www/index.php:


Configure nginx

In /etc/nginx/nginx.conf:

server {
   listen       80;
   servername  ;
   access_log  logs/host.access.log  main;
   root   /var/www;
   index  index.php index.html index.htm;
   location ~ .php$ {
      # Security: must set cgi.fixpathinfo to 0 in php.ini!
      fastcgi_split_path_info ^(.+.php)(/.+)$;
      fastcgi_index index.php;
      fastcgi_param SCRIPT_FILENAME          $document_root$fastcgi_script_name;
      fastcgi_param PATH_INFO $fastcgi_path_info;
      include /etc/nginx/fastcgi_params;

Default fastcgi_params

I start the php location by including /etc/nginx/fastcgi_params. This is because I want to use those as defaults, then override them individually afterwards. It is also recommended to have one root directive per server.

PHP path

I use fastcgi_split_path_info which became available in 0.7.31 to pass PATH_INFO.

Security settings

IMPORTANT: Change cgi.fix_pathinfo to 0 in php.ini to prevent a security issue which arises with the default PHP configuration when PHP incorrectly tries to guess which file you want for URLS specifying nonexistent files. Setting cgi.fix_pathinfo=0 causes PHP to only try the literal path given. Alternatively check that the file exists: if (!-f $request_filename) { return 404; }

See also: Nginx pitfalls.

Start/restart and test

service php-fpm start
service nginx restart

Test by going to your server root, it should show you your phpinfo().

Prepare to install node.js

Excellent post: Add a user for node.js: bash groupadd -r node useradd -r --shell /bin/bash --comment 'User for running node.js' -g node --home /var/lib/node node I prefer using /var/lib/node rather than /home/node because this is more in line with how other server daemon users are defined (e.g. nginx, mysql). -r is for --system, --comment is for --gecos.

Install node.js

yum install gcc-c++ openssl-devel
wget --no-check-certificate
tar -xzvf ry-node-v0.3.3-0-g57544ba.tar.gz
cd ry-node-v0.3.3-0-g57544bac1
make install
mkdir /var/node

Create a test application

For node.js apps, I prefer to keep the www and node trees separate. Also note that I am running unstable 0.3.3 not 0.2.x, so the example is slightly different. Create the example file /var/node/hello_world/example.js:

var sys = require("sys"),
   http = require("http");
http.createServer(function (request, response) {
  response.writeHead(200, {"Content-Type": "text/plain"});
  response.end("Hello Worldn");
sys.puts("Server running at");

Configure nginx for node.js (subdirectory approach)

In /etc/nginx/nginx.conf (after the server definition has started): bash location /node { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-NginX-Proxy true; proxy_pass; proxy_redirect off; }

Install monit

yum install monit

Create monit script

/etc/monit.d/hello_world content: bash check host hello_world with address start program = "/usr/local/bin/node /var/node/hello_world/example.js" as uid node and gid node stop program = "/usr/bin/pkill -f 'node /var/node/hello_world/example.js'" if failed port 8000 protocol HTTP request / with timeout 10 seconds then restart

Start/restart and test

service monit start
service nginx restart

Test by going to /node on your server.

Also, run ps -Af to verify that node is running with the uid node.

The reboot test

Finally, test everything by restarting your server. A friendly reminder:

chkconfig nginx on

chkconfig monit on

chkconfig php-fpm on

chkconfig mysqld on

chkconfig --list


Andy: Great write up, still works on CentOS 6. Thanks!

Chris Abernethy: Agreed, this is a great writeup on a good alternative to the standard apache stack.

If you're interested in also managing node.js with RPM, check out my post on that here:

dim: Hi, thx for this post, i am trying to do something similar on ubuntu, and he question i have is:

Does your setup works with simple websocket server written in nodejs (with socket io for example).

And 2nd question: what version of nginx do you use?


thanks !

nico: Hi... recently i read this, mmm... it's really faster than previous configuration?