Setting up a new Mac for Node.js and Drupal development

UPDATE: I am now of the opinion that you're probably better off installing homebrew with a prefix of somewhere inside your user directory, eg. ~/.homebrew/. I mention this below as an alternative, but now this would be my primary recommendation. Some parts, however, such as configuring the Apple-included Apache installation, and the custom DNS resolvers, are system-wide changes, so you might not want to couple them to a particular user account. Perhaps consider brew installing a user-local copy of Apache, but use a system level installation of dnsmasq.

Original article text follows:

So you've got a fresh, clean Mountain Lion install and you need to get up and running for local development. Recently I spent a day doing just that, so I thought I'd write it all down, to save me from having to look all this stuff up again.

Install Xcode Command Line Tools

Available from the Apple Developer downloads area. You'll need an Apple ID.

This package includes llvm-gcc, which is a (mostly) compatible replacement for gcc. It will work for most homebrew formulas which build with gcc.

Install homebrew

homebrew can be conveniently installed with one line in the Terminal. As with all curl-to-sh style install scripts, you should read the script first to make sure it's not going to do anything bad. Don't say I didn't warn you :)

ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)"

The most convenient approach to using homebrew is to make /usr/local writable to admin group, if you don’t mind a (sort of) security risk. Bear in mind, /Applications is writable by that group by default anyway, so unless you've locked that down also, this won't really make your system much more insecure than it already is.

sudo chmod -R g+w /usr/local

Unfortunately without doing this, homebrew doesn't work particularly well in its default install location. Alternatively install somewhere user-local like ~/homebrew if you're really concerned about security and locking down user permissions on your local machine.

Install Node.js

Node in particular is easier to install from the nodejs.org installer package, not homebrew. Due to some past disagreement between the maintainers of npm and homebrew, the homebrew formula for node doesn’t properly install npm. The official installer, however, works pretty well.

To get npm install -g working (without sudo) you may also want to change the global node_modules directory to have a group id of 'admin':

sudo chgrp -R admin /usr/local/lib/node_modules

You may also need to give g+w permissions to that directory tree, if you installed node after running the chmod command above. This comes with the same caveats as homebrew. If you're really security conscious, install node and npm somewhere in your user directory, rather than globally in /usr.

Install Redis & MongoDB (optional)

brew install redis
redis-server
brew install mongodb
mongod

Install MySQL

brew install mysql

Then follow the instructions depending on whether you want MySQL to run as your user account or a different one, where data should be stored and whether you want to start the daemon manually or run at login.

Eg. to set up databases to run as your user account, with data in /usr/local/var/mysql and running at login:

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

To have launchd start mysql at login:

ln -sfv /usr/local/opt/mysql/*.plist ~/Library/LaunchAgents

Then to load mysql now:

launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mysql.plist

Set up the root mysql account. Pick a better password than I have.

/usr/local/opt/mysql/bin/mysqladmin -u root password 123456

Install PHP 5.4 (optional)

PHP is not in the main homebrew packages, so you'll need to 'tap' some extra repos before you can install it.

brew tap homebrew/dupes
brew tap josegonzalez/homebrew-php

Update LoadModule directive in Apache config file to point to new PHP version

# /etc/apache2/httpd.conf
# Apple default:
# LoadModule php5_module libexec/apache2/libphp5.so
# This should be equivalent to $(brew --prefix php54)/libexec/apache2/libphp5.so
LoadModule php5_module /usr/local/opt/php54/libexec/apache2/libphp5.so

Add updated PHP version to the PATH in .bash_profile

# ~/.bash_profile
export PATH="$(brew --prefix php54)/bin:$PATH"

MySQL socket location & PHP PDO extension

When first running a PHP application which connects to MySQL, you may run in to errors relating to the socket through which PHP's PDO extension is attempting to connect to MySQL. This is because PDO is looking for the MySQL socket at /var/mysql/mysql.sock, but it's probably at /tmp/mysql.sock instead.

Some options you have include setting up a php.ini file:

sudo cp /etc/php.ini.default /etc/php.ini
sudo vi /etc/php.ini

and setting pdo_mysql.default_socket=/tmp/mysql.sock therein. If you go for the php.ini approach it might also be worth setting display_errors = On while you're there.

Or you could use a symbolic link to make PHP happy:

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

I'm not really sure which solution is best, but both seem to do the job.

Set up .dev TLD for local development using dnsmasq

No one likes having to go and edit your hosts file, or something similarly tedious, every single time they create a new local project. By setting up a special TLD and dynamic vhosts, we can avoid ever having to waste time with this stuff again.

brew install dnsmasq
mkdir -pv $(brew --prefix)/etc/

Configure dnsmasq

echo 'address=/.dev/127.0.0.1' > $(brew --prefix)/etc/dnsmasq.conf

Create LaunchDaemon so dnsmasq runs at startup

sudo cp -v $(brew --prefix dnsmasq)/homebrew.mxcl.dnsmasq.plist /Library/LaunchDaemons
sudo launchctl load -w /Library/LaunchDaemons/homebrew.mxcl.dnsmasq.plist

Set up a custom resolver to delegate resolution for .dev domains to dnsmasq

sudo mkdir -v /etc/resolver
sudo bash -c 'echo "nameserver 127.0.0.1" > /etc/resolver/dev'

Set up dynamically configured mass virtual hosting in Apache

Ideally, all you should need to do to spool up a new site for development is create a directory under /srv/www. This Apache config should let you do just that. Create /etc/apache2/other/mass-vhost.conf:

<Directory /srv/www>
  Order Deny,Allow
  Allow from all
  AllowOverride All
</Directory>

NameVirtualHost *:80
<VirtualHost *:80>
  # get the server name from the Host: header
  UseCanonicalName Off
  # include the server name in the filenames used to satisfy requests
  VirtualDocumentRoot /srv/www/%1
</VirtualHost>

Create your sites directory

sudo mkdir -p /srv/www
sudo chown -R _www:_www /srv/www
sudo chmod -R g+w /srv/www

Add your user account to the _www group so you can write to /srv/www

sudo dseditgroup -o edit -a `whoami` -t user _www

Start Apache (and configure it to start automatically at startup)

sudo apachectl start

Install Drush

brew install drush

Set up a test Drupal site

Create a database in MySQL

cd /srv/www
drush dl drupal
mv drupal-* dtest

Create a Drupal settings.php file and fill it out with your database credentials.

In the site .htaccess file uncomment the directive:

# RewriteBase /

Navigate to http://dtest.dev/install.php Once installed, you should also be able to enable Clean URLs.

And you're done!