Here we go, after months of standby a new post that I think can be useful for some of you wanting to install nginx (http server) and compile PHP with fastcgi (you have to run PHP as a CGI with nginx).

So first why nginx? You can find the answer here or here.
Now, to install our server we first need to install homebrew. For those who don’t know homebrew it’s like macports but faster. I personally use homebrew after having trouble with macports.

1. Install homebrew

So to install homebrew, first you need Xcode for Lion that you can download here, it’s free.
You also need Java installed.

Once you’ve installed those components (it will take a while, I think xCode is something like 3.5GB to download, don’t forget to install xCode after downloading it) you have to install homebrew , opening a terminal a typing the following command (we’ll use the terminal from now):

$ sudo /usr/bin/ruby -e "$(curl -fsSL https://raw.github.com/gist/323731)"

Once homebrew is install we’ll use it to install wget to download all the packages we need

$ brew install wget

2. Install Nginx

$ brew install nginx
$ cp /usr/local/Cellar/nginx/1.0.6/org.nginx.nginx.plist ~/Library/LaunchAgents/
$ launchctl load -w ~/Library/LaunchAgents/org.nginx.nginx.plist
$ vi /usr/local/etc/nginx/nginx.conf

Search for “8080″ and replace it by “80″, save and exit (:wq)

3. Install MySQL

http://dev.mysql.com/downloads/mysql/

$ cd /usr/local
$ mkdir src
$ cd src
$ wget http://mysql.mirrors.ilisys.com.au/Downloads/MySQL-5.5/mysql-5.5.16-osx10.6-x86_64.tar.gz
$ tar -xzf mysql-5.5.16-osx10.6-x86_64.tar.gz

Once you’ve done that you can create a mysql folder and copy the source in it:

$ mkdir /usr/local/mysql
$ cd /usr/local/mysql
$ cp -R /usr/local/src/mysql-5.5.16-osx10.6-x86_64/* ./

Now you have to create the basic tables for the server:

$ cd /usr/local/mysql
$ sudo ./scripts/mysql_install_db --user=mysql

Wait for a little while, time for the server to create all the table, open the socket, etc…

$ cd /usr/local/mysql
$ sudo ./bin/mysqld_safe &
$ ps -ef | grep mysql
$ cd /usr/local/src
$ vi com.mysql.server.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>Label</key>
        <string>com.mysql.server</string>
        <key>KeepAlive</key>
        <true/>
        <key>ProgramArguments</key>
        <array>
            <string>/usr/local/mysql/bin/mysqld_safe</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
    </dict>
</plist>
$ cp com.mysql.server.plist ~/Library/LaunchAgents/
$ launchctl load -w ~/Library/LaunchAgents/com.mysql.server.plist

You should see mysql running in the processes. Now will create a symlink to the mysql socket

$ mkdir /var/mysql
$ sudo ln -s /tmp/mysql.sock /var/mysql/mysql.sock

Now we set the admin password for mysql

$ cd /usr/local/mysql
$ sudo ./bin/mysqladmin -u root password 'mycomplexpassword'

And done! mysql is installed…

4. Download & Compile PHP 5.3.8

Here I had a couple of issues that I can share with you. First the hardware configuration I have is a Macbook Pro from late 2009, it’s a dual core so I will install php x86_64.
What you need to do is to download the source here.

$ cd /usr/local/src
$ wget http://au.php.net/distributions/php-5.3.8.tar.gz
$ tar -xzf php-5.3.8.tar.gz

This is done we need to configure the installation. What you ned to do first is to set some variables that will indicate that you want to install the 64bit version of PHP.

$ MACOSX_DEPLOYMENT_TARGET=10.7
$ CFLAGS="-arch x86_64 -g -Os -pipe -no-cpp-precomp"
$ CCFLAGS="-arch x86_64 -g -Os -pipe"
$ CXXFLAGS="-arch x86_64 -g -Os -pipe"
$ LDFLAGS="-arch x86_64 -bind_at_load"
$ export CFLAGS CXXFLAGS LDFLAGS CCFLAGS MACOSX_DEPLOYMENT_TARGET


We are done with that, now we need to configurate the options for PHP. We are going to install PHP with the support for gd so we need to install few libs before to do so. The first lib is jpeg, we’ll also need libxml2 and iconv.

$ brew install jpeg
$ brew install libxml2
$ brew install libiconv

Here we go we are ready… Let’s configure the installation:

./configure \
--prefix=/usr/local \
--with-ldap=/usr \
--enable-cli \
--with-zlib-dir=/usr \
--enable-exif \
--enable-ftp \
--enable-mbstring \
--enable-mbregex \
--enable-sockets \
--with-iodbc=/usr \
--with-curl=/usr \
--with-config-file-path=/etc \
--with-mysql-sock=/var/mysql \
--with-mysqli=/usr/local/mysql/bin/mysql_config \
--with-mysql=/usr/local/mysql \
--with-openssl=/usr \
--with-xmlrpc \
--with-xsl=/usr \
--with-libxml-dir=/usr \
--with-iconv=/usr/local \
--with-pdo-mysql=/usr/local/mysql/bin/mysql_config \
--with-gd \
--with-jpeg-dir=/opt/local \
--with-png-dir=/usr/X11 \
--with-freetype-dir=/usr/X11 \
--with-mcrypt=/usr/X11

As libpng and freetype are already install by default you need to specify the OSX dir for those one. Now we need to modify the Makefile file from the php source folder.

$ vi Makefile

You need to change this line:

$(CC) $(MH_BUNDLE_FLAGS) $(CFLAGS_CLEAN) $(EXTRA_CFLAGS) $(LDFLAGS) $(EXTRA_LDFLAGS) $(PHP_GLOBAL_OBJS:.lo=.o) $(PHP_SAPI_OBJS:.lo=.o) $(PHP_FRAMEWORKS) $(EXTRA_LIBS) $(ZEND_EXTRA_LIBS) -o $@ && cp $@ libs/libphp$(PHP_MAJOR_VERSION).so

By this one:

$(CC) $(CFLAGS_CLEAN) $(EXTRA_CFLAGS) $(LDFLAGS) $(EXTRA_LDFLAGS) $(PHP_GLOBAL_OBJS:.lo=.o) $(PHP_SAPI_OBJS:.lo=.o) $(PHP_FRAMEWORKS) $(EXTRA_LIBS) $(ZEND_EXTRA_LIBS) $(MH_BUNDLE_FLAGS) -o $@ && cp $@ libs/libphp$(PHP_MAJOR_VERSION).so


You need to add -lresolv to the EXTRA_LIBS:

EXTRA_LIBS = -lexslt -liodbc -lmysqlclient -lmcrypt -lltdl -lldap -llber -liconv -liconv -lfreetype -lpng -lz -ljpeg -lcrypto -lssl -lcrypto -lcurl -lz -lcrypto -lssl -lcrypto -lm -lxml2 -lz -licucore -lm -lcurl -lxml2 -lz -licucore -lm -lmysqlclient -liodbc -lmysqlclient -lxml2 -lz -licucore -lm -lxml2 -lz -licucore -lm -lxml2 -lz -licucore -lm -lxml2 -lz -licucore -lm -lxml2 -lz -licucore -lm -lxslt -lxml2 -lz -licucore -lm -lresolv

Save and close the file (:wq)


Before do continue we also need to change the path of the mysql lib which is pointing to a wrong place at the moment. To do so:

$ sudo install_name_tool -change libmysqlclient.18.dylib /usr/local/mysql/lib/libmysqlclient.18.dylib /usr/local/src/php-5.3.8/sapi/cli/php

Now we can do:

$ sudo make
$ sudo make install

And done! PHP is installed :)

If you get the following errors:

configure: error: png.h not found.
You need to specify the png dir with the option "--with-png-dir=/usr/X11", make sure you specify /usr/X11 and not /usr/X11/lib, cf. here

dyld: Library not loaded: libmysqlclient.18.dylib
You need to change the path of the mysql lib, like the following

Undefined symbols for architecture x86_64:
"_res_9_init", referenced from:
You need to add -lresolv to the EXTRA_LIBS, like here.

If you go in /usr/local/bin/ you should see 2 files: php-cgi.dSYM and php.dSYM
If you want to know why there is this extension on the file, it’s here.
you need to rename it as followed:

$ mv /usr/local/bin/php-cgi.dSYM /usr/local/bin/php-cgi
$ mv /usr/local/bin/php.dSYM /usr/local/bin/php

Then you need to correct the library path in php-cgi:

$ sudo install_name_tool -change libmysqlclient.18.dylib /usr/local/mysql/lib/libmysqlclient.18.dylib /usr/local/bin/php-cgi

Create the plist file to start php-cgi at startup

$ vi ~/Library/LaunchAgents/com.phpfcgi.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>Debug</key>
        <false/>
        <key>EnvironmentVariables</key>
        <dict>
            <key>PHP_FCGI_CHILDREN</key>
            <string>2</string>
            <key>PHP_FCGI_MAX_REQUESTS</key>
            <string>1000</string>
        </dict>
        <key>Label</key>
        <string>com.phpfcgi</string>
        <key>OnDemand</key>
        <false/>
        <key>ProgramArguments</key>
        <array>
            <string>/usr/local/bin/php-cgi</string>
            <string>-b127.0.0.1:9000</string>
            <string>-q</string>
        </array>
        <key>RunAtLoad</key>
        <false/>
    </dict>
</plist>

And load the plist

$ launchctl load -w ~/Library/LaunchAgents/com.phpfcgi.plist

Well I think I’ve covered most of the issue that you can encountered while compiling PHP. If you have more issue or if you want to add something to the process feel free to post a comment.

5. Configure Nginx with VirtualHosts

First you need to add the domain you want to use in the hosts file

$ sudo vi /private/etc/hosts
...
127.0.0.1 localhost
127.0.0.1 myfirstdomain.local
127.0.0.1 myseconddomain.local
...

Then you need to flush the cache of the DNS

$ sudo dscacheutil -flushcache

Create the log folder and edit nginx.conf

$ sudo mkdir -p /usr/local/var/log/nginx/
$ vi /usr/local/etc/nginx/nginx.conf
worker_processes  1;

error_log  /usr/local/var/log/nginx/error.log info;
pid        /usr/local/var/run/nginx.pid;

events {
    worker_connections  256;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    access_log  /usr/local/var/log/nginx/access.log;
    sendfile        on;
    keepalive_timeout  65;
    gzip  on;

    # HTTP server
    include /usr/local/etc/nginx/vhosts.conf;
}

Now we create the vhost file:

$ mkdir -p /usr/local/share/nginx/html/myfirstdomain/www
$ mkdir -p /usr/local/share/nginx/html/myseconddomain/www
$ vi /usr/local/etc/nginx/vhosts.conf
server {
    listen 8080;
    server_name myfirstdomain.local;
    root   /usr/local/share/nginx/html/myfirstdomain/www;
    index  index.html index.htm index.php;

    access_log  /usr/local/var/log/nginx/myfirstdomain.access.log;

    #error_page  404  /404.html;

    location ~ html|css|js|jpg|png$ {
        try_files $uri index.php
        break;
    }

    # redirect server error pages to the static page /50x.html
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/local/share/nginx/html;
    }

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    location ~ \.php$ {
        fastcgi_pass  127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include       /usr/local/etc/nginx/fastcgi.conf;
        break;
    }
}

server {
    listen 8080;
    server_name myseconddomain.local;
    root   /usr/local/share/nginx/html/myseconddomain/www;
    index  index.html index.htm index.php;

    access_log  /usr/local/var/log/nginx/myseconddomain.access.log;

    #error_page  404  /404.html;

    location ~ html|css|js|jpg|png$ {
        try_files $uri index.php
        break;
    }

    # redirect server error pages to the static page /50x.html
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/local/share/nginx/html;
    }

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    location ~ \.php$ {
        fastcgi_pass  127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include       /usr/local/etc/nginx/fastcgi.conf;
        break;
    }
}

Here we go we are done normally… but let’s check few stuff to make sure everything will start correctly

6. Check the config and restart

We check that all the plist are loaded:

$ launchctl list | grep php
$ launchctl list | grep nginx
$ launchctl list | grep mysql

You should see the plist file name if it’s loaded, if you don’t see anything it’s because you forgot to load it, read above and make sure you load the plist file.

Let’s restart and check it!

$ sudo reboot

Open a browser and check http://myfirstdomain.local:8080 and http://myseconddomain.local:8080

Everything should work, at least it’s working for me :P
If you have any trouble comment it please, I’ll try to help you and update the tuto.

Have fun!