MAMP is an easy way to get a basic MAMP (Mac, Apache, MySQL, PHP) environment running. Each package in the stack is configured such that it’s easy to drop the MAMP directory into /Applications and serve up a database-backed PHP site.

Much of this simplicity is baked in at compile time so you can deal with the entire stack as you would a regular Mac OS X app bundle (e.g. by dragging it around between networked machines to replicate it) rather than having to coordinate the components yourself. However, the default configuration can be a touch limiting, so a little surgery is in order. We can set it up to be a little more powerful, yet retain its friendliness.

Before you install: The normal .dmg on the MAMP download site is a binary-only setup. For tasks that are more involved than changing confuration files or creating symbolic links, you’ll find it handy to have the source available; source+binary packages are at the bottom of the download page. I’d recommend installing that even if you don’t plan on needing the source right away; it’s a lot easier to ignore the extra files than it is to try to add them in later.

1. Use Standard Ports

This isn’t absolutely required, of course, but it can make housekeeping simpler—and at the very least, your URLs prettier—if you configure Apache and MySQL to use the standard ports (80 and 3306, respectively) rather than the MAMP defaults of 8888 and 8889. Lots of packages that you might install in your PHP environment default to talking to MySQL on port 3306, so doing this once keeps you from having to specifically configure everything else.

The easiest way to accomplish this is to simply use the MAMP GUI program provided in /Applications/MAMP/MAMP.app, click the Preferences button, and visit the Ports tab. What it does is change the port numbers in the Listen directive in httpd.conf and the invocation of mysqld_safe in /Applications/MAMP/bin/startMysql.sh.

Moving Apache to port 80 will require that you run it as root or via sudo. Keep that in mind for later when we automate the startup.

2. Set Up Virtual Hosts

Getting more than one site working is pretty simple. Assuming you’ve installed MAMP at the default location of /Applications/MAMP:

  1. Create a directory /Applications/MAMP/conf/apache/vhosts. Put any virtual host definitions in this directory (see below for a simple virtual host).
    mkdir /Applications/MAMP/conf/apache/vhosts
    
  2. Open /Applications/MAMP/conf/apache/httpd.conf and add this to the end:
    NameVirtualHost *:80
    Include /Applications/MAMP/conf/apache/vhosts/*.conf
    
  3. Restart Apache. That’s it!
    sudo /Applications/MAMP/bin/apache2/bin/apachectl restart
    

    If you didn’t switch to port 80, you can drop the sudo, by the way.

Note that the Include statement makes it easy to turn virtual hosts on and off: just rename files in the vhosts directory. Use a .conf extension to enable a file; remove the extension to disable it. Feel free to use your own fancy expression here; restart MAMP every time to make the changes take effect.

Generally, other than whatever you set up as your filename inclusion expression above, the filenames of the vhost definitions don’t matter. One exception is that the first one processed becomes the default site served up when you hit 127.0.0.1 or localhost. Prefix the filename of the one you want to be the default site with something like 000- to make sure it comes first alphabetically.

Also note, of course, that if you don’t have a local DNS server, you’ll need to set up a line in /etc/hosts for each virtual host. On Leopard, that works out of the box. On Tiger, you have to make sure your lookupd is set up to read from /etc/hosts before hitting DNS.

Sample Virtual Host (/Applications/MAMP/conf/apache/vhosts/vhost.local.conf)

Here’s a trivial virtual host. Probably 90% of mine are just slight variations on this.

<VirtualHost *:80>
    ServerName vhost.local
    DocumentRoot /Applications/MAMP/htdocs/vhost.local/
    <Directory /Applications/MAMP/htdocs/vhost.local/>
        Options Indexes FollowSymLinks MultiViews
        AllowOverride All
        Order allow,deny
        allow from all
    </Directory>
</VirtualHost>

If your project doesn’t have a build process that dumps the published files to your virtual host’s DocumentRoot, sometimes it’s useful to create the DocumentRoot as a symbolic link that points to your working copy of the project’s version control repository. Then you can just work from there without having to publish your files out to some directory just so you can test things.

3. Run at Startup via launchd

I admit it: I’m lazy. I originally set up my MAMP GUI program to run as a login item for my account in System Preferences, but I got tired of having to switch to it so I could quit it and not have to look at it. My eyesight is precious; heaven forbid I waste it—not to mention the three whole seconds of my time—doing that! Far more productive would be to spend a few minutes learning how to set it up to run automatically, in a Leopardy way.

As Apple’s documentation on System Startup Programming Topics describes, the Leopardy way to start services automatically is via launchd (and the Tigerish way is via StartupItems, also covered in that link). Essentially, you create a .plist definition for each service you wish to handle, then register it with the system (or just reboot). In our case, our two services are Apache and MySQL, so we’ll create a separate file for each. All we’re doing is plistification of the regular shell scripts MAMP uses for startup.

Apache

Put the following in /Library/LaunchDaemons/com.living-e.mamp.apache:

<?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>com.living-e.mamp.apache</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Applications/MAMP/Library/bin/httpd</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>

MySQL

Create /Library/LaunchDaemons/com.living-e.mamp.mysql thusly:

<?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>com.living-e.mamp.mysql</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Applications/MAMP/Library/bin/mysqld_safe</string>
        <string>--port=3306</string>
        <string>--socket=/Applications/MAMP/tmp/mysql/mysql.sock</string>
        <string>--lower_case_table_names=0</string>
        <string>--pid-file=/Applications/MAMP/tmp/mysql/mysql.pid</string>
        <string>--log-error=/Applications/MAMP/logs/mysql_error_log</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>UserName</key>
    <string>YOUR_USERNAME_HERE</string>
</dict>
</plist>

Make sure you put your username in there! For MySQL we’re running as you rather than root; it works better if we do that. Actually, the MAMP package is set up to be run as a normal user already; the only reason we are doing it this way here is so Apache has access to port 80 from our port change above. If you’re using ports above 1024, you could probably tighten things up by creating these as “agents” rather than “daemons”, but I don’t want to get lost in Mac system startup minutiae. Their docs (including the man pages for launchd and launchd.plist) cover it all.

There, by doing this you’ve saved yourself a few seconds per boot. Depending on how long you go between boots, I figure I’ve saved you at least a minute or two per year! In a couple of years when you break even on the time you just spent setting this up, you’ll thank me for all of the free time.

4. Proxy Real Data

Often a web app’s architecture is designed around a REST or RPC service to shuttle data back and forth to the client side. In such cases, one useful technique Apache makes available is to use mod_proxy to let you transparently connect to some shared development server or staging data, without needing to configure your local build to know about the separate environment. You could even proxy production data if you wanted; just be careful not to clobber it!

Anyway, say your project has a REST endpoint at /rest. Working from our trivial virtual host from above, you do this in your httpd.conf:

<VirtualHost *:80>
    ServerName vhost.local
    DocumentRoot /Applications/MAMP/htdocs/vhost.local/
    <Directory /Applications/MAMP/htdocs/vhost.local/>
        Options Indexes FollowSymLinks MultiViews
        AllowOverride All
        Order allow,deny
        allow from all
    </Directory>

    # here the magic happens
    ProxyPass /rest http://testing-data-server.foo.com/rest
</VirtualHost>

Voila! Now any requests made to http://vhost.local/rest get forwarded to http://testing-data-server.foo.com/rest, and you can use real data without having to do a typical dump/restore cycle.

Oh, and if you’re going to do something like this, take all the necessary precautions so you don’t create an open proxy for the whole world to use.

5. Create a Friendlier DocumentRoot

It doesn’t take long to get tired of putting files in /Applications/MAMP/htdocs, MAMP’s default Apache DocumentRoot, to serve them up. Symbolic links to the rescue! Do this:

ln -s /Applications/MAMP/conf/apache/vhosts/ ~/Sites/conf
ln -s /Applications/MAMP/htdocs/ ~/Sites/vhosts

Now you can get to your virtual hosts (and their configuration files) through your home directory.

Of course, if you’re not using virtual hosts, you could just symlink the ~/Sites directory directly to MAMP’s DocumentRoot. Or just change the DocumentRoot altogether. However you like to work.

6. Get PEAR Working

MAMP ships with a PEAR environment, but you have to nudge it a bit to work completely. The /Applications/MAMP/bin/php5/lib/php directory is already in the include_path in php.ini, so using PEAR from PHP works out of the box, but the pear binary isn’t in your $PATH by default. Add a line to your ~/.profile:

export PATH=/Applications/MAMP/bin/php5/bin:$PATH

Now you can do things like pear upgrade-all to stay on top of new developments.

7. Relocate Your Databases For (Probably Slight) Performance

If you 1) have more than one disk in your system, and 2) don’t mind losing the application bundle-ness of your MAMP environment, you can get a bit of performance increase by moving your databases to a disk other than your regular boot volume. It most likely won’t be anything to write home about, but I know I’ve noticed an improvement when working on projects with multi-gigabyte databases.

MAMP comes with MySQL and SQLite, both of which store their data in /Applications/MAMP/db. Simply move the db directory to another disk and create a symbolic link in its place, pointing to the new location. For example, mine was:

mv /Applications/MAMP/db /Volumes/dev01/
ln -s /Volumes/dev01/db/ /Applications/MAMP/db



Don’t forget to restart MAMP.

8. Install mod_python

Out of the box, MAMP is designed around PHP & MySQL/SQLite; however, it’s not limited to that. If you want to develop with Python rather than PHP, adding mod_python can really make your environment sing. You need the MAMP source for this, so hopefully you took my advice earlier and installed the full distribution rather than the binary-only package.

  1. Install the module.
    • Binary download: If you’re feeling lucky and boisterous, you can try the precompiled mod_python I built for my system (MAMP 1.7.1, Apache 2.0.59, mod_python 3.3.1). Install it with:
      tar xzf MAMP-1.7.1_mod_python-3.3.1.tar.gz     \
          -C /Applications/MAMP/Library
      

      Then, skip to step 2.

    • Source download: If you’d rather build from source yourself (or my build doesn’t work for you), download the mod_python source. Build it like so:
      # this symlink makes the configure script work
      sudo ln -s /Applications/MAMP/Library/ /usr/local/apache2
      
      # MAMPified build
      ./configure --prefix=/Applications/MAMP/Library               \
                  --with-apxs=/Applications/MAMP/Library/bin/apxs   \
                  --with-python=/usr/bin/python
      
      make
      make install
      
  2. At this point, mod_python will be ready to go, but we could do with a bit more system integration. It’s nice to be able to easy_install something from the command line and have it not only automatically available to mod_python, but also living inside the MAMP application bundle. Let’s configure that:
    • One way is to use a symbolic link to point your user site-packages directory at MAMP’s new one:
      mkdir -p ~/Library/Python/2.5
      ln -s /Applications/MAMP/Library/site-packages/   \
            ~/Library/Python/2.5/site-packages
      
    • Alternatively, based on the Easy Install documentation, you can put this in ~/.pydistutils.cfg:
      [install]
      install_lib = /Applications/MAMP/Library/site-packages
      install_scripts = /Applications/MAMP/Library/bin
      

    I have both of these set up. Don’t ask me why; I can’t remember if I needed it or if it’s just left over from when I was trying different configurations out. If you do the latter but not the former, make sure to add /Applications/MAMP/Library/site-packages to your $PYTHONPATH.

  3. Finally, Add a line to /Applications/MAMP/conf/apache/httpd.conf:
    LoadModule python_module modules/mod_python.so
    
  4. Extra finally, restart MAMP.

Conclusion

The beauty of MAMP is that it’s a regular LAMP stack, just Mac-ish. It’s self-contained like a normal Mac application, but once you figure out where everything is, it’s easy to customize just like you would a regular LAMP stack. Just don’t go too crazy, or else you may as well just use fink!