MEMP: PHP 5.3 with FPM and nginx via MacPorts

I’ve been considering diving into nginx for a bit now. Rumors of it’s speed and Cyrillic error messages have intrigued me. With recent forays into node.js apps and their requirement for a free port, I wanted to find a nice solution that complimented the evented speed of node.js without exposing a port publicly for each app. As it turns out Nginx is suited quite nicely to this. But that wasn’t where it ended. I found nginx to have a much more interesting and dynamic config language. And even beyond that it gave me a good excuse to learn more about running PHP as a FastCGI process and how PHP-FPM (baked in as of 5.3.3) fits into the picture. Not sure if MEMP is the correct acronym, but since I’ve seen talk of LEMP servers, I’ll run with it.

MacPorts. If you’re not already familiar with it, I recommend reading up before proceeding.

Since I already have MySQL set up and configured I won’t bother covering it here. It’s pretty well documented around the webs. The main focus here is going to be getting nginx installed and setting up PHP as a service to it with an emphasis on local development. No need to tweak this for production on my Macbook Pro.

PHP 5.3.3 introduced PHP-FPM (FastCGI Process Manager) to the codebase. Building it requires a few extra config flags and generates a php-fpm binary. The binary will manage spawning cgi processes and handling the FastCGI passthru from nginx. Currently MacPorts does not have an option to build PHP with PHP-FPM. After some hacking on the current Portfile I arrived at a working solution. It includes the correct flags, a dependency on libevent, and a startup item.

First things first.

sudo port selfupdate

# recommended but probably not a requirement
sudo port upgrade outdated
sudo port uninstall inactive

(If you’ve already got the php5 package installed, uninstall it and it’s cohorts to ensure a clean install process going forward.)

This is a bit of a hack and there’s probably a better way, like submitting a proper patch to MacPorts, but this will get the job done for today.

# replace this file with the Portfile from the gist below
/opt/local/var/macports/sources/rsync.macports.org/release/ports/lang/php5/Portfile

https://gist.github.com/724449

Then run the regular port install.

sudo port install nginx php5 +fastcgi php5-apc php5-mysql +mysqlnd

Next we’ll need to set up the configs. There’s two basic configs that require attention. First is the nginx config. Since this is just for a local development env we can be pretty lean on what we need.

# /opt/local/etc/nginx/nginx.conf

worker_processes  1;

error_log  /var/log/nginx/error.log;

events {
    worker_connections  1024;
}

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

    sendfile           on;
    keepalive_timeout  65;

    server {
      listen 80;
      server_name   ~^local\.(?.+?)\.com$;
      root  /Users/jason/Sites/$site/web;
      index  index.php index.html;

      location = /favicon.ico {
        log_not_found off;
      }

      location ~ \.php$ {
         fastcgi_pass   unix:/tmp/php-fpm.sock;
         fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
         include        fastcgi_params;
      }
    }
}

This is the config that I’m currently using as my generic site config. It has a few nice features. First the server name is matched against a regular expression. So any site that matches local.xxxx.com will be parsed and use the xxxx as a sub-directory in my Sites folder. This is nice. So I only need to create a new directory and add my local.xxxx.com domain to /etc/hosts pointed at 127.0.0.1 and I can immediately begin developing. Gone are the days of creating a new v-hosts file, enabling it, and restarting apache every time I want to play with a new site’s code. The other nicety here is we’re using a unix socket for the fastcgi passthru. This is unnoticeably faster on my Mac, but again frees up the need to be concerned with another open port on my system.

It’s worth noting that any fastcgi_param that you define in this config is available within PHP as a $_SERVER variable.

The second config is the FPM config. Copy /opt/local/etc/php-fpm.conf.default to /opt/local/etc/php-fpm.conf and open it up. Here are the important ones to modify:

pid = /opt/local/var/run/php-fpm.pid
error_log = /opt/local/var/log/php-fpm.log
listen = /tmp/php-fpm.sock
listen.owner = _www
listen.group = _www
pm.max_children = 1
pm.start_servers = 1
pm.min_spare_servers = 1
pm.max_spare_servers = 1
pm.max_requests = 500
slowlog = /opt/local/var/log/php-fpm.log.slow

It’s pretty straight-forward. Lean cus we can. Save and continue.

At this point we’ve got all the pieces in place. We just need a way to start/stop/restart nginx and FPM. I looked for a cleaner way to accomplish this but in the end it came down to a handful of aliases. Add these to your ~/.profile.

# nginx
alias nginx_start='sudo launchctl load /Library/LaunchDaemons/org.macports.nginx.plist' 
alias nginx_stop='sudo launchctl unload /Library/LaunchDaemons/org.macports.nginx.plist' 
alias nginx_restart='nginx_stop; nginx_start;' 

# php-fpm
alias fpm_start='sudo launchctl load /Library/LaunchDaemons/org.macports.php-fpm.plist'
alias fpm_stop='sudo launchctl unload /Library/LaunchDaemons/org.macports.php-fpm.plist'
alias fpm_restart='fpm_stop; fpm_start'

Reopen the Terminal window to enable the new aliases. Start or restart nginx and FPM as the case may be.

At this point you should be able to create a site directory, add a domain to /etc/hosts and drop in an index.php with phpinfo(); to verify that PHP is working.

Hopefully this will be of some use to other aspiring MEMP devs out there. I found it intensely fun. :)

Tags: , , , ,

12 Responses to “MEMP: PHP 5.3 with FPM and nginx via MacPorts”

  1. eljam Says:

    hi,

    The php-fpm is not loaded, launchctl said that there is nothing to load. Any guess for this error ?

  2. eljam Says:

    and nothing for nginx, i’ve use the sudo port load nginx and it does the work.

  3. Jason Mooberry Says:

    Hi @eljam. Not sure. Is it possible you did the install without sudo? Otherwise there should be a symlink to the launchctl plist in /Libraray/LaunchDaemons. This is just the basic MacPorts startup item install. Nothing that I did manually.

  4. eljam Says:

    hi jason, i did the install with sudo. But it’s really weird that the launchctl failed manually and not with port load, because it does the same as your command right ?
    For the plist, i already did the changes for the path. Really weird behavior, i’m gonna try something else, i’ll keep you update if i find the problem.

  5. Jason Mooberry Says:

    Hey eljam. I just came across this error while doing a fresh install. The fix seems to be using the -w switch on launchctl the first time you load. After that, no errors.

    sudo launchctl -w load /Library/LaunchDaemons/org.macports.php-fpm.plist

  6. webPragmatist Says:

    See https://trac.macports.org/ticket/26039 for a more official patch for fpm in macports.

  7. Shane Says:

    I got a new error now. Has a recent update broken this?

    $ sudo port install nginx php5 +fastcgi php5-apc php5-mysql +mysqlnd
    —> Computing dependencies for nginx
    —> Fetching nginx
    —> Attempting to fetch nginx-0.8.53.tar.gz from http://ykf.ca.distfiles.macports.org/MacPorts/mpdistfiles/nginx
    —> Verifying checksum(s) for nginx
    —> Extracting nginx
    —> Applying patches to nginx
    —> Configuring nginx
    —> Building nginx
    —> Staging nginx into destroot
    —> Creating launchd control script
    ###########################################################
    # A startup item has been generated that will aid in
    # starting nginx with launchd. It is disabled
    # by default. Execute the following command to start it,
    # and to cause it to launch at startup:
    #
    # sudo port load nginx
    ###########################################################
    Warning: violation by /opt/local/html
    Warning: nginx violates the layout of the ports-filesystems!
    Warning: Please fix or indicate this misbehavior (if it is intended), it will be an error in future releases!
    —> Installing nginx @0.8.53_0
    —> Activating nginx @0.8.53_0
    —> Cleaning nginx
    —> Computing dependencies for php5
    —> Fetching php5
    —> Attempting to fetch patch-ext-mysqlnd-mysqlnd.h.diff from http://us.php.net/distributions/
    —> Verifying checksum(s) for php5
    Error: No checksum set for patch-ext-mysqlnd-mysqlnd.h.diff
    Error: Target org.macports.checksum returned: Unable to verify file checksums
    Log for php5 is at: /opt/local/var/macports/logs/_opt_local_var_macports_sources_rsync.macports.org_release_ports_lang_php5/main.log
    Error: Status 1 encountered during processing.
    To report a bug, see

  8. Jason Mooberry Says:

    Yeah it was a dead ticket for a while but it looks like it’s getting some action now. Seems like it will be added in the next release. :)

  9. Andrés Botero Says:

    Hello there!

    For some reason I’m getting (in PHP-FPM logs): [pool www] ‘user’ directive is ignored.

    The thing is, if I comment it out, I will get an error. Do you know why might this be related? I noticed you don’t use ‘user’ in your config, but then why am I getting the error?

    Thanks in advance!

  10. Andrés Says:

    Hello there!

    I’m currently setting nginx + PHP-FPM using Homebrew, but I’ve found something weird with PHP-FPM. Whenever I start the process, I get a “WARNING: [pool www] ‘user’ directive is ignored” message, but if I comment it out in the configuration file, I get an error saying ‘user’ is mandatory, and then PHP-FPM won’t even start. I even tried setting it as “_www” and my own username (instead of “nobody”), to no avail.

    Perhaps you know what might be going on here? Thanks in advance!

  11. indy Says:

    @Shane for php 5.3.8 just use another source for Portfile https://gist.github.com/1170592/f9e6691ae46b8e9fbdc54760fd585d2b3fb59a88

    for php 5.3.9 I changed

    10,11c10,11
    < version 5.3.8
    version 5.3.9
    > revision 1
    33,34c33,34
    < rmd160 f18a18e2dfd7ea7885760eec2a05b3c4a15ad9db \
    rmd160 428ed51982637f092c43369cf5cfb284d58da3f6 \
    > sha256 4bc54e1aa9010f09d2c6597844c984adecf9e1153c913a853c7725905ddb4dd7

  12. doup Says:

    To avoid the “nothing found to load” error, add “-w” AFTER load, not before.

    sudo launchctl load -w /Library/LaunchDaemons/org.macports.php-fpm.plist

Leave a Reply