Skip to content

Ubuntu: nginx+php-cgi on a socket

Moving our PHP application into the cloud, means for us that we are leaving FreeBSD for Linux. Not the best move (IMHO), but I shall elaborate on this in a future blog post.

Once we decided on Ubuntu as the Linux of our choice, I started by moving our development server to an instance on Slicehost. Point taken, Slicehost is not the cloud (as in Amazon EC2, Rackspace, Flexiscale or GoGrid) yet, but Linux on Slicehost and Linux on Amazon EC2 will be alike (or so I hope :-)) and a getting a small slice versus getting a small EC2 instance is an economical decision in the end.


The following is the start script for my php-cgi processes, which I ported from FreeBSD (I previously blogged about it here).

The advantages of this script are:

  1. php-cgi runs on a unix domain socket — no need for tcp/ip on localhost.
  2. No need for the infamous spawn-fcgi script, which never worked for me anyway, and on Ubuntu requires you to install lighttpd (if you don't happen to be on Karmic Koala).
  3. You can setup different websites with different instances of php-cgi. This is great for virtual hosting, especially on a development server where the different workspaces may have different PHP settings and you want to run versions in parallel without sharing settings and therefore maybe affecting each other.
  4. Icing on the cake: we could even add a custom php.ini to the start call for each instance (-c option) to customize it even further.

Start script

The setup is simple, just put the following into a php-fcgid file in /etc/init.d/, chmod +x it and don't forget it to use update-rc.d php-fcgid defaults in case you want to start the processes when the server boots up:

# Author: Till Klampaeckel <[email protected]>
# Credits
#  * original script:
#  * improved:
#  * all linux start script fu inspired by CouchDB's start script (by Noah Slater)


DESCRIPTION="php-fcgi super-duper-control thing"
SCRIPT_NAME=$(basename $0)


phpfcgid_users="johndoe jandoe"

log_daemon_msg () {
    echo [email protected]

log_end_msg () {
    # Dummy function to be replaced by LSB library.

    if test "$1" != "0"; then
        echo "Error with $DESCRIPTION: $NAME"
    return $1

phpfcgid_start() {
    echo "Starting $NAME with $phpfcgid_children children (req: $phpfcgid_requests)."

    export PHP_FCGI_CHILDREN=$phpfcgid_children
    export PHP_FCGI_MAX_REQUESTS=$phpfcgid_requests

    for user in ${phpfcgid_users}; do
        mkdir -p ${socketdir}
        chown ${user}:${WWW_GROUP} ${socketdir}
        chmod 0750 ${socketdir}
        su -m ${user} -c "${PHP_CGI} -b ${socketdir}/socket&"

phpfcgid_stop() {
    echo "Stopping $NAME."
    pids=`pgrep php-cgi`
    pkill php-cgi

phpfcgid_status() {
    log_daemon_msg "To be implemented: status"
    log_end_msg $SCRIPT_ERROR

parse_script_option_list () {

    case "$1" in
            log_daemon_msg "Starting $DESCRIPTION" $NAME
            if phpfcgid_start; then
                log_end_msg $SCRIPT_OK
                log_end_msg $SCRIPT_ERROR
            log_daemon_msg "Stopping $DESCRIPTION" $NAME
            if phpfcgid_stop; then
                log_end_msg $SCRIPT_OK
                log_end_msg $SCRIPT_ERROR
            log_daemon_msg "Restarting $DESCRIPTION" $NAME
            if phpfcgid_stop; then
                if phpfcgid_start; then
                    log_end_msg $SCRIPT_OK
                    log_end_msg $SCRIPT_ERROR
                log_end_msg $SCRIPT_ERROR
            cat << EOF >&2
Usage: $SCRIPT_NAME {start|stop|restart|force-reload|status}
            exit $SCRIPT_ERROR

parse_script_option_list [email protected]

General PHP Installation

The required steps in order to get the php installation:

  • apt-get update
  • apt-get install php5-cgi
  • apt-get install nginx

(These steps are working on Ubuntu Jaunty (aka 9.04), but they should work on virtually any other Ubuntu or Debian installation.)

Nginx configuration

This is a simple virtualhost for nginx:

server {
    listen   80;

    access_log  /var/log/nginx/;
    error_log off;

    location / {
        root   /var/www/;
        index  index.php index.html index.htm;

    location ~ .php {
        include fastcgi_params;

        fastcgi_pass  unix:/tmp/.fastcgi.johndoe/socket;
        fastcgi_index index.php;

        fastcgi_param SCRIPT_FILENAME /var/www/$fastcgi_script_name;

Place the above into /etc/nginx/sites-available and symlink it from /etc/nginx/sites-enabled.

One thing to note is that you may have to adjust the line with fastcgi_pass. Depending on which user the socket belongs to.


There really isn't one. ;-) It just works for me, and I hope it helps someone out there.

I also created a repository on github where I'll keep this script, manage changes and open source my other findings on my journey with Ubuntu.

If you happen to have an addition, please fork and contribute. One of the things for the start script that I'd like to do (aka I have to figure them out) is install it through a package and create a configuration file in /etc/defaults so I don't have to edit the start script when I add a user or change the parameters passed on to the php-cgi process.


No Trackbacks


No comments

The author does not allow comments to this entry