Yosemite MAMP homebrew dev setup part 2
In my previous post OS X 10.10 Yosemite, Apache, MySQL, PHP 5.6, (MAMP) Homebrew Dev Setup I covered a lot. Like a lot a lot, but by the end of the post all we had really accomplished was installing the basic building blocks of a development server, namely: Apache, MySQL, and PHP. In this post we’ll take those components and turn them into a sweet development workflow.
Updating Brew
Everyone loves running brew update && brew upgrade
just to see what’s been
updated. It’s a seriously
busy repo,
but it’s easy to forget to do and then your versions languish. Fortunately for
us Mark Kalmes wrote a LaunchAgent plist for us called,
aptly,
brewupdate.
We’re going to grab the latest version and install it.
curl https://raw.githubusercontent.com/mkalmes/brewupdate/develop/net.mkalmes.brewupdate.plist > ~/Library/LaunchAgents/net.mkalmes.brewupdate.plist
launchctl load ~/Library/LaunchAgents/net.mkalmes.brewupdate.plist
The first line downloads the latest version straight from github to the user-space LaunchAgents folder. The second line loads it. You can edit the file and change when it updates, the default is 11 AM (local time zone). I changed mine to 8 AM because I like to start the day with a fresh brew (ha ha.)
Just don’t forget to run brew upgrade
yourself occasionally. You could make
another LaunchAgent by changing the parameter from update
to upgrade
, but I
really don’t like unattended upgrades as much as updates.
Apache 2: DocumentRoot
That’s a clever title, you see we’re running Apache HTTPD 2, and at the same
time this is part 2 of the Apache section… Anyways, at the end of Part 1 Apache
was running on port 80 like a champ. The DocumentRoot is set to something
ridiculous like /usr/local/var/www/htdocs
which is pretty freaking
inconvenient.
First we need to create our /Sites folder and we’ll still keep our web documents inside of that folder.
mkdir ~/Sites ~/Sites/htdocs
Then edit your /usr/local/etc/apache2/2.4/httpd.conf
file and change the
DocumentRoot directive, as well as accompanying Directory declaration to match
your new htdocs location:
DocumentRoot "/Users/USERNAME/Sites/htdocs"
<directory>
</directory>
Obviously replace USERNAME
with your username’s folder name. Then inside of
that directory declaration we’re going to change some of the default Apache
values to be more permissive:
Options All MultiViews
AllowOverride All
This is given with the usual caveat that OF COURSE you would never default everything like this on a production server- but on a development server there’s generally not much security implication (unless you’re playing with live data!). My full DocumentRoot section looks like this:
DocumentRoot "/Users/dannywahl/Sites/htdocs"
<directory>
#
# Possible values for the Options directive are "None", "All",
# or any combination of:
# Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
#
# Note that "MultiViews" must be named *explicitly* --- "Options All"
# doesn't give it to you. # # The Options directive is both complicated and important. Please see
# http://httpd.apache.org/docs/2.4/mod/core.html#options
# for more information.
Options All MultiViews
#
# AllowOverride controls what directives may be placed in .htaccess files.
# It can be "All", "None", or any combination of the keywords:
# AllowOverride FileInfo AuthConfig Limit
AllowOverride All
#
# Controls who can get stuff from this server.
# Require all granted
</directory>
Now, restart your httpd daemon:
sudo httpd -k restart
If you didn’t use --with-privileged-ports
when you installed Apache then you
don’t need root. Now when you visit http://localhost you
should just get a blank directory listing instead of the default “It Works!”
page. Let’s put a test page there. First let’s create a sub-directory in our
/Sites folder called phpinfo.localhost
(more on the .
later).
mkdir ~/Sites/phpinfo.localhost
Now let’s create a page that calls the phpinfo();
function and place it in
that folder. if you don’t know about
phpinfo() it’s a simple
function that outputs a page that shows you information about your PHP
configuration.
printf ‘<?php phpinfo(); ??>‘ >> ~/Sites/htdocs/phpinfo.localhost/index.php
Now you should be able to visit http://localhost/phpinfo.localhost/
and see
the overview of your PHP configuration. That’s it for now for Apache, let’s move
on to MySQL.
MySQL
In the first post we simply installed MySQL and set a root password. It’s good to have a password because some authentication APIs require one, but we’re not necessarily using it for security (otherwise we wouldn’t be using root), so we’re going to save our authentication in a my.cnf options file. Homebrew provides us with a sample file, but it’s not symlinked by default so we’re going to copy it to an available configuration folder and since MySQL is running in user-space, we will override the configuration at the user-space level:
cp -v $(brew –prefix mysql)/support-files/my-default.cnf ~/.my.cnf
Now we have our config override, let’s have it auto-save our credentials.
cat > ~/.my.cnf
[client]
user=root
password=PASS
[mysql]
user=root
password=PASS
[mysqldump]
user=root
password=PASS
[mysqldiff]
user=root
password=PASS
EOF
Replace “PASS” with your root MySQL password. If you have special characters in your password, which you shouldn’t, add double quotes around the password. Now you can connect to mysql without having to manually authenticate.
mysql -u root
phpmyadmin
Finally we’re going to install everyone’s favorite database manager, phpmyadmin. Again, we’ll be using homebrew to install it.
brew install phpmyadmin
After a successful installation you will get a caveat about adding a directory alias to your httpd configuration to enable phpmyadmin, but we’re not going to do that we’re going to symlink it to to our ~/Sites directory.
ln -s /usr/local/share/phpmyadmin ~/Sites/htdocs/phpmyadmin.localhost
This will create a symbolic link in your webroot called phpmyadmin.localhost that takes you to /usr/local/share/phpmyadmin (which itself is a symlink to the Cellar). The benefit here is you don’t need to restart Apache, and again we’ll go over it later but the .localhost is important.
Now that phpmyadmin is installed, we need to configure it. First we’ll import the phpmyadmin linked tabled configuration storage via commandline:
mysql -u root -e 'CREATE DATABASE IF NOT EXISTS `phpmyadmin`;'
mysql -u root phpmyadmin
Once the tables are imported open your phpmyadmin config file located at
/usr/local/etc/phpmyadmin.config.inc.php
and you're going to do a few things:
- generate a blowfish secret
- Set your
controluser
andcontrolpass
(I use root again) - Uncomment the storage database and tables section
In the end your blowfish and servers configuration sections should look something like this:
$cfg['blowfish_secret'] = 'y=PUY@-GleE+~%OiGQVz#)N4I)@Q%Ug_Jr[DxF';
/* YOU MUST FILL IN THIS FOR COOKIE AUTH! */
/* * Servers configuration */
$i = 0;
/* * First server */
$i++;
/* Authentication type */
$cfg['Servers'][$i]['auth_type'] = 'cookie';
/* Server parameters */
$cfg['Servers'][$i]['host'] = '127.0.0.1';
$cfg['Servers'][$i]['connect_type'] = 'tcp';
$cfg['Servers'][$i]['compress'] = false;
$cfg['Servers'][$i]['AllowNoPassword'] = false;
/* * phpMyAdmin configuration storage settings. */
/* User used to manipulate with storage */
// $cfg['Servers'][$i]['controlhost'] = '';
// $cfg['Servers'][$i]['controlport'] = '';
$cfg['Servers'][$i]['controluser'] = 'root';
$cfg['Servers'][$i]['controlpass'] = 'root';
/* Storage database and tables */
$cfg['Servers'][$i]['pmadb'] = 'phpmyadmin';
$cfg['Servers'][$i]['bookmarktable'] = 'pma__bookmark';
$cfg['Servers'][$i]['relation'] = 'pma__relation';
$cfg['Servers'][$i]['table_info'] = 'pma__table_info';
$cfg['Servers'][$i]['table_coords'] = 'pma__table_coords';
$cfg['Servers'][$i]['pdf_pages'] = 'pma__pdf_pages';
$cfg['Servers'][$i]['column_info'] = 'pma__column_info';
$cfg['Servers'][$i]['history'] = 'pma__history';
$cfg['Servers'][$i]['table_uiprefs'] = 'pma__table_uiprefs';
$cfg['Servers'][$i]['tracking'] = 'pma__tracking';
$cfg['Servers'][$i]['designer_coords'] = 'pma__designer_coords';
$cfg['Servers'][$i]['userconfig'] = 'pma__userconfig';
$cfg['Servers'][$i]['recent'] = 'pma__recent';
$cfg['Servers'][$i]['favorite'] = 'pma__favorite';
$cfg['Servers'][$i]['users'] = 'pma__users';
$cfg['Servers'][$i]['usergroups'] = 'pma__usergroups';
$cfg['Servers'][$i]['navigationhiding'] = 'pma__navigationhiding';
$cfg['Servers'][$i]['savedsearches'] = 'pma__savedsearches';
/* Contrib / Swekey authentication */
// $cfg['Servers'][$i]['auth_swekey_config'] = '/etc/swekey-pma.conf';
/* * End of servers configuration */
You might notice that I changed my host to "127.0.0.1" from "localhost". By
default /etc/hosts should resolve localhost to 127.0.0.1 so it shouldn't trigger
a DNS lookup, but by changing it to an IP address you'll never have that happen
because there are ways to inadvertently send lookups to your machine DNS for
localhost. Again, this is not necessary. After saving your phpmyadmin
configuration you should be able to visit the page at
http://localhost/phpmyadmin.localhost
dnsmasq
Dnsmasq is a lightweight DNS/DHCP server which can be installed and serve DNS for addresses that aren't in the global namespace. We'll be installing dnsmasq via homebrew and configuring it, along with Apache to serve sites on reserved TLDs.
brew install dnsmasq
Once dnsmasq is installed we need to copy a configuration profile, edit it, and then load the daemon. First we'll copy a provided configuration:
cp /usr/local/opt/dnsmasq/dnsmasq.conf.example /usr/local/etc/dnsmasq.conf
printf '\naddress=/localhost/127.0.0.1' >> /usr/local/etc/dnsmasq.conf
sudo cp -fv /usr/local/opt/dnsmasq/*.plist /Library/LaunchDaemons
sudo launchctl load /Library/LaunchDaemons/homebrew.mxcl.dnsmasq.plist
Effectively we are telling dnsmasq to resolve all .localhost domains to 127.0.0.1 and setting it to run the daemon at the machine level (with Apache). So you can now try to ping any .localhost domain and it will resolve to 127.0.0.1:
ping -c 1 thisdoesntexist.localhost
PING thisdoesntexist.localhost (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.029 ms
--- thisdoesntexist.localhost ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.029/0.029/0.029/0.000 ms
Obviously trying to visit http://thisdoesntexit.localhost won't work because Apache isn't configured to handle requests to that address, yet. There are two different ways to configure this, the first is to create a vhost entry for every domain you want to use, the second is to enable mod_vhost_alias- which is what we'll do now.
mod_vhost_alias
Mod_vhost_alias is an Apache module that let's you do pattern matching from a request URL to a directory structure, there are lots of cool examples at the documentation site- but the one we want is pretty straight forward. Open your httpd.conf file (in /usr/local/etc/apache2/2.4/) and uncomment the mod_vhost_alias module
LoadModule vhost_alias_module libexec/mod_vhost_alias.so
then in terminal we'll configure vhost_alias_module:
printf '\nUseCanonicalName Off\nVirtualDocumentRoot /Users/USERNAME/Sites/htdocs/%%0' >> /usr/local/etc/apache2/2.4/httpd.conf
And finally restart the httpd daemon:
sudo httpd -k restart
The end result is that now every folder that ends in .localhost in your ~/Sites/htdocs/ folder is accessible as a FQDN. Go back to your browser and now you can visit http://phpinfo.localhost and http://phpmyadmin.localhost If you create another folder inside of htdocs that ends in .localhost it will be available in your dev environment as a standalone domain. Here's a couple of examples of how that could be useful:
Say you want a standalone domain of wordpress:
git clone git@github.com:WordPress/WordPress.git ~/Sites/htdocs/wordpress.localhost
What about multiple branches of drupal on standalone domains? Let's make
http://drupal6.localhost
and http://drupal7.localhost
git clone git@github.com:drupal/drupal.git --branch 6.x --single-branch ~/Sites/htdocs/drupal6.localhost
git clone git@github.com:drupal/drupal.git --branch 7.x --single-branch ~/Sites/htdocs/drupal7.localhost
As another example, how about a single domain with multiple moodle instances in
sub-directories like http://moodle.localhost/26
and
http://moodle.localhost/27
mkdir ~/Sites/htdocs/moodle
git clone git@github.com:moodle/moodle.git --branch MOODLE_26_STABLE --single-branch ~/Sites/htdocs/moodle/26
git clone git@github.com:moodle/moodle.git --branch MOODLE_27_STABLE --single-branch ~/Sites/htdocs/moodle/27
Wrapping Up
So there you go! Mac OS X with brewed versions of important stuff like openssl and git, Apache 2.4, MySQL, and PHP 5.6 and a killer setup using mod_vhost_alias and dnsmasq to provision .localhost domains on the fly. Of course there are a million ways to dev from here, but this is a pretty solid foundation.
If you need help with educational technology in your institution, from strategic planning, to implementation, to technical support contact us and we can help get you on the path to success.