One of the questions arising during Apache to nginx migration is “How to run my PHP based applications?”. Nginx supports PHP only via FastCGI interface (which is the prefered way of running PHP for me anyway). There are dozens of HOWTOs for configuring nginx to direct .php files requests to FastCGI, but only a few covering the topic of running the PHP FastCGI backend. None of them covers the correct way, though.
Let me show you how to get it right…
PHP CGI binary is perfectly able running a FastCGI interface by itself. There is no need to run it with an external wrapper. No need to install anything more than the PHP itself.
Just install the php-cgi: aptitude install php5-cgi and run: php-cgi -b 127.0.0.1:9000. Done. You have PHP running FastCGI interface on localhost on port 9000. You can connect to it from nginx using fastcgi_pass 127.0.0.1:9000;.
php-cgi binary is configurable using environment variables. The most interesting ones are PHP_FCGI_CHILDREN telling how many child processes to launch and PHP_FCGI_MAX_REQUESTS telling how many requests each child need to process before termination (and launching another one).
I use this command (wrapped in a simple script) on my development machine. But server needs something to launch the PHP FastCGI processes on boot. Here is a simple init.d script to get the php-cgi running as a normal system service:
#!/bin/bash
BIND=127.0.0.1:9000
USER=www-data
PHP_FCGI_CHILDREN=15
PHP_FCGI_MAX_REQUESTS=1000
PHP_CGI=/usr/bin/php-cgi
PHP_CGI_NAME=`basename $PHP_CGI`
PHP_CGI_ARGS="- USER=$USER PATH=/usr/bin PHP_FCGI_CHILDREN=$PHP_FCGI_CHILDREN PHP_FCGI_MAX_REQUESTS=$PHP_FCGI_MAX_REQUESTS $PHP_CGI -b $BIND"
RETVAL=0
start() {
echo -n "Starting PHP FastCGI: "
start-stop-daemon --quiet --start --background --chuid "$USER" --exec /usr/bin/env -- $PHP_CGI_ARGS
RETVAL=$?
echo "$PHP_CGI_NAME."
}
stop() {
echo -n "Stopping PHP FastCGI: "
killall -q -w -u $USER $PHP_CGI
RETVAL=$?
echo "$PHP_CGI_NAME."
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
echo "Usage: php-fastcgi {start|stop|restart}"
exit 1
;;
esac
exit $RETVAL
Put it in /etc/init.d/php-fastcgi, make it executable chmod +x /etc/init.d/php-fastcgi, unleash the daemons /etc/init.d/php-fastcgi start and finally make it permanent update-rc.d php-fastcgi defaults.
May the nginx + php-cgi fastcgi serve you well.
P.S. Here’s a simple snippet of nginx configuration to make use of the described service:
server {
listen 80;
server_name example.com;
access_log /var/log/nginx/example.com.access_log;
error_log /var/log/nginx/example.com.error_log warn;
root /var/www/example.com/public;
index index.php index.html;
fastcgi_index index.php;
location ~ \.php {
include /etc/nginx/fastcgi_params;
keepalive_timeout 0;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass 127.0.0.1:9000;
}
}

Thanks for this article, I found it very helpful. I searched long for an Nginx + PHP method which doesn’t necessitate the use of something like php-apm or spawn-fcgi.
I don’t understand the infatuation of wrappers and poorly documented patches which seem to permeate the Nginx+PHP userbase. Oh well.
Thanks again!
Thanks so much for this guide. I have used spawn-fcgi previously and had a feeling there had to be a simpler solution. Thanks again
Thanks for this simple method.
I was doing this on my slicehost slice.
My only problem was start-stop-daemon: command not found
Just had to add /sbin/start-stop-daemon
if I run php5-cgi -b 127.0.0.1:9000 or php-cgi -b 127.0.0.1:9000 it just hangs indefinately util I crtl-c out. Was hoping to try your method, but kinda at a standstill now.
Thanks
What do you expect it to do? :D It’s a FastCGI server. Just connect your HTTP server to it’s 9000 port.
Thanks for this, it’s a lot simpler than other ‘recipes’ I’ve looked at in the past.
I added some lines to avoid passing nonexistent php files to fastcgi:
(...)
location ~ \.php {
if (!-e $request_filename) {
return 404;
}
(...)
the rest is as above
Thanks for this simple method., I found it very helpful. I searched long for an Nginx + PHP method
You rule! :)
Thank you, the documentation is the main problem with NginX. This article explains why there is no spawn-fcgi script in NginX.
Great tutorial. THis got me running PHP5 with nginx on Ubuntu on Slicehost. It’s a great combo, if you ask me.
Good method/
I can’t make it work… please help !
I keep getting the 404 page. Maybe my settings are wrong because no .php file can be found. I don’t understand what’s this line for
fastcgi_param SCRIPT_FILENAME /var/www/nginx-default$fastcgi_script_name;
should I have my site’s path instead ?
thanks!
There is nothing about “/var/www/nginx-default” in my article. Where did you get it from?
I meant:
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
anyhow.. I got something running because the common phpinfo.php works fine.
But I can’t load the mysql.so module… You seem to know a lot about this.. Can you help me please ?
You’re a legend! I’ve always wanted to setup nginx without using spawn-fcgi (from lighttpd).
Thanks for the awesome article! :)
Thanks!
You saved my day!
Worked for me. Thanks!
Thank you! I’m just separating PHP from Apache to run Apache in Worker MPM mode and this was a great help.
Like most people, I think, I found lots of more complicated ways to run PHP but this one’s fast, works, and is dead simple to set up.
Tomasz, I found your article very useful having come from an article which recommended the use of lighttpd spawn-cgi … for some reason I was getting 502 bad gateway errors after prolonged use of the nginx+php server (not quite sure why yet) … Can you expand on the CHILDREN and REQUESTS vars and their implications on memory usage, what should the laymen be aware of. Thanks a lot!