Thursday, March 7, 2013

Install nginx / PHP / MySQL on Mac OS X Mountain Lion with Homebrew

UPDATE: If you're looking how to install just nginx on Mac OS 10.10 (Yosemite), see this newer post about that.

Last time I wiped my Macbook Pro, I used Macports to install my web development environment. Doing it that way was really hard compared to using Homebrew. I now fully recommend Homebrew for all Mac package management needs. This is much easier than the Macports way. Trust me.

Here's how to install nginx, PHP, and MySQL using Homebrew on your Mac. It's actually quite easy. I did it on Mountain Lion (10.8) but it probably works for Lion too. I followed the tutorial here on EZUnix.org, but my version fixes some typos and explains some steps along the way.

Disclaimer: This blog is a memo to self for when I need to do this again. If you encounter any errors, I may or may not be able to help...



Estimated Time: 10-20 minutes



Got Command Line Developer Tools?


You're gonna need them. Finally, Apple provides the command line tools without needing to install the nearly-2GB-Xcode from the App Store. Go to their Developers Downloads page and download the latest "Command Line Tools" for your version of OS X, then install them.


Install Homebrew


In case you haven't already, install Homebrew by following the instructions at the bottom of this page.

Homebrew's most legit PHP "tap" (package source) is by Jose Gonzalez. Make sure to install it:

$ brew tap josegonzalez/homebrew-php

We also need a tap for a PHP 5.4 dependency, zlib:

$ brew tap homebrew/dupes

Install MySQL

$ brew install mysql

It'll chew on that for a few minutes, then we need to get it to run as our user account:

$ unset TMPDIR
$ mysql_install_db --verbose --user=`whoami` --basedir="$(brew --prefix mysql)" --datadir=/usr/local/var/mysql --tmpdir=/tmp

I got a "Warning" during this operation, and while I don't think it's critical, I did this and things have seemed to work fine... if you got a warning during the last step, then you could do this:

$ sudo mv /usr/local/opt/mysql/my-new.cnf /usr/local/opt/mysql/my.cnf

Then, to launch MySQL at startup:

$ cp `brew --prefix mysql`/homebrew.mxcl.mysql.plist ~/Library/LaunchAgents/
$ launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.mysql.plist

Done! Next: the web server.


Install nginx

$ brew install nginx

Let that stew, then run this commands to have nginx run as root at startup (so we can listen on port 80, the default, instead of 8080 which is less convenient for development):

$ sudo cp `brew --prefix nginx`/homebrew.mxcl.nginx.plist /Library/LaunchDaemons/

That takes care of the startup part; make your .plist file look like this to run as root (if it doesn't work for you, then the path in ProgramArguments may need adjustment):

<?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>Label</key>
    <string>homebrew.mxcl.nginx</string>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <false/>
    <key>UserName</key>
    <string>root</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/opt/nginx/bin/nginx</string>
        <string>-g</string>
        <string>daemon off;</string>
    </array>
    <key>WorkingDirectory</key>
    <string>/usr/local</string>
  </dict>
</plist>


Then create a log file... this allows us to view server logs in the Mac Console, which is really convenient, but isn't required:

$ sudo mkdir /var/log/nginx/

(Don't forget to tell nginx to put the log file there in nginx.conf: error_log  /var/log/nginx/error.log;)

Done! Next up: PHP.


Install PHP

$ brew install --without-apache --with-fpm --with-mysql php54

Make sure to change "php54" to whatever version you want. At time of writing, PHP 5.4 is the latest stable, but PHP 5.5 is in alpha. I assume 5.5 would be php55, etc. Be sure to adjust any following commands with the proper version number.


Quick note: Yes, OS X does come with PHP pre-installed. But we don't want to use that. We need an install we can use with nginx and FastCGI Process Manager (fpm). Plus, we want the latest version, and I'm just not that into compiling from source.

To run php-fpm at startup:

$ sudo cp `brew --prefix php54`/homebrew-php.josegonzalez.php54.plist  /Library/LaunchAgents/
$ sudo launchctl load -w /Library/LaunchAgents/homebrew-php.josegonzalez.php54.plist

Done! Next up: configuration.



Finishing up

I want all php commands to be using the latest version, not the default PHP binary. So I use this little trick to create a symlink from the default PHP binary to the new one... I do this for both php and php-fpm. If you're confused about which versions are where, use the "whereis" command, like: "whereis php".


$ php-fpm -v
$ sudo mv /usr/sbin/php-fpm /usr/sbin/php-fpm.bak
$ sudo ln -s /usr/local/Cellar/php54/5.4.11/sbin/php-fpm /usr/sbin/php-fpm
$ php-fpm -v

Notice that the version went from 5.3 to 5.4 (in my case). Now for the php binary:

$ php -v
$ sudo mv /usr/bin/php /usr/bin/php.bak
$ sudo ln -s /usr/local/bin/php /usr/bin/php
$ php -v

I also added /usr/local/sbin to the PATH by adding that directory to the /etc/paths file, then restarting Terminal. You can see your current PATH by typing echo $PATH.

Important config files:

/usr/local/etc/nginx/nginx.conf
/usr/local/etc/php/5.4/php.ini
/usr/local/etc/nginx/fastcgi_params

You'll probably want to change these for your own system.

The nice thing about Homebrew installations is that you generally don't need sudo to use or manage these services, since they're in /usr/local.

Alright. Well that did it for me. Enjoy your new dev environment!

You can stop nginx with nginx -s stop, and start it again with just nginx. You can also just reload the conf file with nginx -s reload.

I installed MySQL Workbench and was able to make a connection to the localhost MySQL server by adding a connection to host "localhost" with no password. The only thing I typed was that hostname and everything worked like a charm.

I did use my nginx.conf file from my previous install; you can view a sample conf file if you need it, in my other post about using Macports to do this (link at top of this post).

17 comments:

  1. I am getting "-bash: nginx: command not found" when i try "nginx start"

    ReplyDelete
    Replies
    1. I'm not sure why. Did you get any errors during installation?

      Delete
    2. i get it worked at localhost:8080, but i am totally unaware of hosting a new site in it.. Can you help ?

      Delete
    3. In this tutorial I didn't cover how to configure your nginx.conf file, mainly because every need is so different. But make sure nginx is listening on 80, not 8080.

      You probably don't want to host a production website on your local machine, though. Why not opt for an affordable and reliable web host?

      Delete
  2. And how can i run my new php website ?

    ReplyDelete
    Replies
    1. If you follow these instructions to the end, it should be working.... at least, this did it for me. Where are you having troubles at?

      Delete
  3. I am having troubles getting PHP files to appear. All I am seeing is "File Not Found" on any PHP based file.

    Do you have any suggestions?

    - Jacob

    ReplyDelete
    Replies
    1. Could be a few things... first, make sure nginx is pointing to the right document root. (I just realized that my post, as it currently stands, has an unfinished sentence that is important. I'll fix that this weekend.) That'd be the line in the .conf file that starts with "root". Also, make sure the "server" directive has something like this in it:

      location / {
      try_files $uri $uri/ /index.php;
      }

      location ~ \.php$ {
      fastcgi_split_path_info ^(.+\.php)(.*)$;
      fastcgi_index index.php;
      include fastcgi.conf;
      if (-f $request_filename) {
      # Only throw it at PHP-FPM if the file exists (prevents some PHP exploits)
      fastcgi_pass 127.0.0.1:9000;
      }
      }

      try_files $uri $uri.php $uri.html =404;


      (The actual content may vary for you -- but I just used the default config that it gave me.) The first block ensures that requests that don't specify a file are handled. The next block says that for any PHP file, to forward it into FastCGI to execute the PHP code. The final try_files line tries a few combinations of the URL as given, then finally bails with a 404 if it can't find it.

      Does that help?

      Delete
  4. When running the php-fpm -v command im getting a command not found error, I know I followed all these steps. Any help?

    ReplyDelete
    Replies
    1. Hm. What happens when you try "php5-fpm -v" instead?

      Delete
    2. Unfortunately the same error occurs, "command not found"

      Delete
    3. How did the install of php54 go with brew, using the --with-fpm and --without-apache options? Are you sure there were no errors? What happens when you run "php" from the command line? Is php-fpm located in /usr/sbin or /usr/local/sbin or /usr/bin or /usr/local/bin?

      Delete
  5. Running "php" puts me into php land to enter php code.

    Running the "php -v" I get:

    PHP 5.4.15 (cli) (built: May 14 2013 11:30:07)
    Copyright (c) 1997-2013 The PHP Group
    Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies

    I did a brew uninstall php54, then reinstalled:

    $ brew install --without-apache --with-fpm --with-mysql php54
    ==> Downloading http://www.php.net/get/php-5.4.15.tar.bz2/from/this/mirror
    Already downloaded: /Library/Caches/Homebrew/php54-5.4.15
    Warning: Backing up all known pear.conf and .pearrc files
    Warning: If you have a pre-existing pear install outside
    of homebrew-php, or you are using a non-standard
    pear.conf location, installation may fail.
    ==> ./configure --prefix=/usr/local/Cellar/php54/5.4.15 --localstatedir=/usr/local/var --sysconfdir=/usr/local/etc/php/5.4 --with-conf
    ==> make
    ==> make install
    ==> /usr/local/Cellar/php54/5.4.15/bin/pear config-set php_ini /usr/local/etc/php/5.4/php.ini
    ==> Caveats
    The php.ini file can be found in:
    /usr/local/etc/php/5.4/php.ini

    ✩✩✩✩ PEAR ✩✩✩✩

    If PEAR complains about permissions, 'fix' the default PEAR permissions and config:
    chmod -R ug+w /usr/local/Cellar/php54/5.4.15/lib/php
    pear config-set php_ini /usr/local/etc/php/5.4/php.ini

    ✩✩✩✩ Extensions ✩✩✩✩

    If you are having issues with custom extension compiling, ensure that this php is
    in your PATH:
    PATH="$(brew --prefix josegonzalez/php/php54)/bin:$PATH"

    PHP54 Extensions will always be compiled against this PHP. Please install them
    using --without-homebrew-php to enable compiling against system PHP.

    ✩✩✩✩ FPM ✩✩✩✩

    To launch php-fpm on startup:
    * If this is your first install:
    mkdir -p ~/Library/LaunchAgents
    cp /usr/local/Cellar/php54/5.4.15/homebrew-php.josegonzalez.php54.plist ~/Library/LaunchAgents/
    launchctl load -w ~/Library/LaunchAgents/homebrew-php.josegonzalez.php54.plist

    * If this is an upgrade and you already have the homebrew-php.josegonzalez.php54.plist loaded:
    launchctl unload -w ~/Library/LaunchAgents/homebrew-php.josegonzalez.php54.plist
    cp /usr/local/Cellar/php54/5.4.15/homebrew-php.josegonzalez.php54.plist ~/Library/LaunchAgents/
    launchctl load -w ~/Library/LaunchAgents/homebrew-php.josegonzalez.php54.plist

    The control script is located at /usr/local/Cellar/php54/5.4.15/sbin/php54-fpm

    You may also need to edit the plist to use the correct "UserName".

    Please note that the plist was called 'org.php-fpm.plist' in old versions
    of this formula.

    To have launchd start php54 at login:
    ln -sfv /usr/local/opt/php54/*.plist ~/Library/LaunchAgents
    Then to load php54 now:
    launchctl load ~/Library/LaunchAgents/homebrew.mxcl.php54.plist
    Warning: /usr/local/sbin is not in your PATH
    You can amend this by altering your ~/.bashrc file
    ==> Summary
    🍺 /usr/local/Cellar/php54/5.4.15: 490 files, 38M, built in 2.6 minutes


    Next I followed your steps and ran (with no errors):

    $ sudo cp `brew --prefix php54`/homebrew-php.josegonzalez.php54.plist /Library/LaunchAgents/
    $ sudo launchctl load -w /Library/LaunchAgents/homebrew-php.josegonzalez.php54.plist


    php-fpm is not located in /usr/bin, there is an alias file for php-fpm in /usr/sbin, its not in /usr/local/bin, in /usr/local/sbin there is a php-fpm alias exec file and a php54-fpm alias file.

    ReplyDelete
    Replies
    1. There is this one warning in your output that might be the culprit: "Warning: /usr/local/sbin is not in your PATH. You can amend this by altering your ~/.bashrc file" -- try adding that to your PATH, restarting the terminal or maybe even logging out then back in (I always get confused as to how .bashrc works), then see if the command is found.

      Delete
  6. Awesome, progress!

    I added that to my $PATH, not sure how I missed that, woops.

    Running php-fpm gives me :
    $ php-fpm -vPHP 5.4.15 (fpm-fcgi) (built: May 15 2013 09:19:09)
    Copyright (c) 1997-2013 The PHP Group
    Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies

    But running just php-fpm gives me (potentially due to not setting up the config for nginx?):

    $ php-fpm
    [15-May-2013 10:10:58] NOTICE: [pool www] 'user' directive is ignored when FPM is not running as root
    [15-May-2013 10:10:58] NOTICE: [pool www] 'group' directive is ignored when FPM is not running as root
    [15-May-2013 10:10:58] ERROR: unable to bind listening socket for address '127.0.0.1:9000': Address already in use (48)
    [15-May-2013 10:10:58] ERROR: FPM initialization failed

    Also, thanks a lot for your help and this guide, really appreciate it :)

    ReplyDelete
  7. I think that means that php-fpm is already running and listening on port 9000, which is the pass-thru port that nginx will send PHP requests to so that php-fpm can handle it.

    ReplyDelete
  8. Yeah running ps aux | grep fpm showed running php-fpm processes listing on those ports. Thanks again for your help and quick responses. Cheers!

    ReplyDelete