Praxent

Native LAMP Stack in Mac OS X!

A Guide to Native LAMP Stack in Mac OS X

Are you using MAMP Pro for web development? Has it ever caused you to drink heavily while simultaneously banging your head against the keyboard? Follow this guide, and you will never have to experience the horror that is the MAMP stack again!

Don’t get us wrong – MAMP was great for a while. Convenient even. It had this nice little button labeled “Start”, and then it would turn green when it was ready. It handled all those pesky VHosts and hosts file entries for me. Then one day, out of nowhere, it reared its ugly head when I had the audacity to try to use the ImageMagick extension for PHP.

This is the fly in the ointment when it comes to MAMP. It lives off in its own little world on your computer, oblivious to the endless stream of change in the real world of web development. It is an added layer to the already complex set of layers standing between your keyboard and a web application. It eats memory like a pig, has a hard time following directions, and does not play nice with others.

So, what to do? First, a disclaimer: the following guide is what you would call an ‘overhaul’ of your development environment. It can be fraught with peril – and subsequent triumph – for the determined soul. In other words, it may take you longer than you like to get back up and running. Plan accordingly.

Backup and cleanup

Dump and backup databases from MAMP’s environment:

Get all databases (grab a beer and a sandwich, this could take a while):

 

~$ mysqldump -u root -p --all-databases > database_backups.sql

 

Note that this will dump “ALL” databases into a single file. If you want to be up and running quickly with specific sites, try the next command instead. Also, this does not preserve users and permissions. So if you use a separate user/password for each of your databases, make sure you know what those are / how to set them up later.

Or, if you prefer, just grab the ones you need one at a time:

 

~$ mysqldump -u root -p --databases database_name > database_name_backup.sql

 

  • Backup /Applications/MAMP/htdocs (your websites!)
  • Remove MAMP Pro (drag to trash)
  • Delete MAMP from your system path

 

~$ echo $PATH

 

If you see any MAMP related thing in your path, find it and remove it. Usually, this will be a line in your bash profile.

  • Edit /etc/paths (with your favorite editor!):

 

~$ sudo emacs /etc/paths

 

Add /usr/local/bin to the first line. This will make sure that packages installed with Homebrew are the first thing in your path.

Now close this terminal window and open a new one. This will update your environment with the new path.

  • Install Homebrew (if you haven’t already):
    ~$ ruby -e "$(curl -fsSkL raw.github.com/mxcl/homebrew/go)"

     

  • Normalize Homebrew (if already installed):
    ~$ brew doctor

     

  • Fix any errors. (DO NOT SKIP THIS PART!) Usually these errors have to do with your path, or extraneous files and libraries in /usr/local, or brew not finding Mac OS System libraries where it expects them to be. There is a wide range of errors that occur, and this step can take some time, and some serious googling. Also, make sure you run:
    ~$ brew update

     

  • Install lunchy (for starting and stopping daemons):
    ~$ sudo gem install lunchy

     

A Side Note about daemons

Mac OS X relies on launchctl to start and stop services. It is similar to init.d in linux, or service in Ubuntu. lunchy is a wrapper for launchctl. It makes it easier to start and stop services. Services that are owned by root have init scripts in /Library/LaunchDaemons. To start and stop these services using lunchy, you must use sudo. Services owned by the user have init scripts in ~/Library/LaunchAgents/. Lunchy does not require sudo to start and stop these services.

Install Packages using Homebrew

PHP

~$ brew tap homebrew/dupes  ~$ brew tap josegonzalez/homebrew-php  ~$ brew install php53  
  • Install useful PHP extensions (using brew)~$ brew install php53-xdebug – There are a smorgasbord of extensions to choose from:
    • php-code-sniffer
    • php53-apc
    • php53-imagick
    • php53-memcached
    • php53-mongo
    • php53-redis
    • php53-uploadprogress
    • php53-xdebug (recommended)
    • php53-xhprof

These extensions are completely optional and can be installed at any time. You can always run a brew info package_name, and check out the web link for more info on each extension.

  • Edit php.ini (xdebug settings & memory limit)If you like to use memory hungry PHP frameworks like Drupal, you will need to up the memory limit for PHP scripts.~$ emacs /usr/local/etc/php/5.3/php.iniSearch for memory_limit and set it to 2048M

MariaDB (MySQL)

MariaDB is an optimized fork of MySQL. It works great as a drop-in replacement for the standard version of MySQL. If you would rather not use MariaDB you can do all of these same steps, just replace the word mariadb with the word mysql.

~$ brew install mariadb  ~$ cp $(brew --prefix mariadb)/support-files/my-large.cnf /usr/local/etc/my.cnf  ~$ sed -i "" 's/max_allowed_packet = 1.*M/max_allowed_packet = 32M/g' /usr/local/etc/my.cnf  ~$ cp /usr/local/opt/mariadb/homebrew.mxcl.mariadb.plist ~/Library/LaunchAgents/  ~$ mysql_install_db --verbose --user=`whoami` --basedir="$(brew --prefix mariadb)" --datadir=/usr/local/var/mysql --tmpdir=/tmp  ~$ launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.mariadb.plist  ~$ mysqladmin -uroot password 'password'  

Setting up Apache

Mac OS X has the Apache webserver built-in. Let’s make it play nice with our newly installed PHP module.

~$ sudo emacs /etc/apache2/httpd.conf  

Add the following line at the end of the LoadModule section:

~$ LoadModule php5_module /usr/local/opt/php53/libexec/apache2/libphp5.so  

Now we can restart apache:

~$ sudo apachectl restart  

Setting up VirtualDocumentRoot

Apache allows for a wildcard to be used when specifying the document root. The implications of this are that you can create a directory, and apache will treat that directory as if it were a VirtualHost. No more creating separate VHosts for every project!

It can help to create a config file for the OS X user:

~$ sudo touch /etc/apache2/users/username.conf  ~$ sudo emacs /etc/apache2/users/username.conf  
<VirtualHost *:80>    ServerName dev    DocumentRoot /Users/username/Sites    VirtualDocumentRoot /Users/username/Sites/%-2/htdocs    UseCanonicalName Off      <Directory "/Users/username/Sites/*/htdocs">      AllowOverride All      Order allow,deny      Allow from all    </Directory>  </VirtualHost>  

This sets up Apache to serve your projects from the Sites folder inside your home directory. Apache will serve files from the htdocs folder, so websites will be stored on your local filesystem here:

~/Sites/projectname/htdocs

There is one other configuration setting that is nice to have:

~$ sudo emacs /etc/apache2/httpd.conf  

Find the ServerName directive and change it to:

ServerName localhost:80  

This will suppress the warning about apache not being able to resolve a fully qualified domain name. Now restart apache.

~$ sudo apachectl restart  

From there, simply check that all is well.

Note: if you haven’t actually created a ~/Sites/project directory yet, you may get a warning here:

~$ apachectl -S  
VirtualHost configuration:  wildcard NameVirtualHosts and _default_ servers:  *:80                   dev (/etc/apache2/users/samheuck.conf:1)  Syntax OK  

Note that when using VirtualDocumentRoot, any site that is using RewriteRules to route all requests through a front controller (index.php), you will have to set RewriteBase / in .htaccess.

On Mac OS X, apache runs under the user _www. There is also a group called _www. Your project’s htdocs folders should have permissions set accordingly.

 

~$ chown -R username:_www project/htdocs

 

Setting up DNS

Now that Apache is all set up, we need an easier way to point our project names to localhost so that we can type something like projectname.dev in a browser. You could easily do this by adding lines to /etc/hosts, but that is tedious manual labor, and I will not stand for it.

~$ brew install dnsmasq  ~$ sudo cp /usr/local/opt/dnsmasq/homebrew.mxcl.dnsmasq.plist /Library/LaunchDaemons  

Setup the config file for dnsmasq:

~$ touch /usr/local/etc/dnsmasq.conf  ~$ emacs /usr/local/etc/dnsmasq.conf    # /usr/local/dnsmaq.conf  address=/.dev/127.0.0.1  rebind-domain-ok=/xip.io/nip.io/  

Start dnsmasq:

 

~$ sudo lunchy start dnsmasq

 

Dnsmasq is a caching DNS server that runs locally and handles DNS requests. We just set it up to send all requests ending in .dev to localhost. Now we just need to tell Mac OS to use dnsmasq instead of the DNS server that is assigned to you by your gateway. The most straightforward way of doing this is to simply add 127.0.0.1 to your list of DNS servers. The problem is that you will also need to make sure that you have another DNS server for other requests. I like to use OpenDNS.

Navigate to System Preferences -> Network -> WiFi (or your most used network interface) Click Advanced, and go the DNS tab. Under DNS servers, add 127.0.0.1 at the top of the list, followed by 208.67.222.222 (or any other nameserver).

There is a way to do this automatically with some scripting. This works well if you are always using different wireless networks and such.

Once DNS is set up, you should be able to:

 

~$ ping project.dev

 

and get a response from 127.0.0.1

That’s it! Now you can put your sites back into the sites directory you defined in your apache configuration, restore your databases, and you are off to the races. Happy coding!