Wes Hooper

Apache, MySQL and PHP dev environment on OSX Lion

I'd been using a Ubuntu VM to run Apache, MySQL and PHP for development on my computer but it was proving to be more hassle than it was worth and I wanted to simplify.

After finding (via @jamieyork) a blog post by Rob Allen explaining how he did it, I decided to give it a go myself.

I also looked at MAMP but quickly hit a bug which convinced me I'd rather get a setup perfect for how I work instead.

As Jamie was trying to do the same thing and so we had it documented for other Dejumbled developers, I made these notes which I hope may be helpful for others too.

Besides the basics of getting everything running, I also prefer to have tiny configuration files which simply override defaults as required. A setup where all I need do is checkout the repo and reload Apache for it to work. Everything is UTF8 only.

Lastly, using a /var/www/vhosts path means consistency with our staging and live environments plus avoids developer specific paths such as /Users/wes/Sites/blah getting in the code.

MySQL

  1. Download MySQL and install its 3 items. I went for Community Server 5.5 for OSX 10.6, 32-bit DMG version as running OSX with 32-bit kernel, though 64-bit should work so planning to change sometime.
  2. Edit your profile (nano ~/.bash_profile) and add the following line to the start of the file: export PATH=~/bin:/usr/local/bin:/usr/local/mysql/bin:$PATH
  3. Restart, then confirm MySQL running in System Preferences.
  4. Set up MySQL root password, note there is no space after -p in the last two commands: mysqladmin -u root password new-password mysqladmin -u root -pnew-password -h localhost password new-password mysqladmin -u root -pnew-password reload
  5. Create /etc/my.cnf as the following to override defaults, forcing UTF8 and more generous caches: [mysql] default-character-set = utf8 [mysqld] collation_server = utf8_general_ci character_set_server = utf8 skip-character-set-client-handshake myisam_sort_buffer_size = 64M query_cache_size = 128M tmp_table_size = 512M max_heap_table_size = 512M table_cache = 4096 log_output = TABLE general_log = ON slow_query_log = ON long_query_time = 2 max_allowed_packet = 16M

PHP

Create /etc/php.ini as the following to override defaults and set the extension directory:

short_open_tag = Off magic_quotes_gpc = Off allow_url_fopen = Off register_long_arrays = Off html_errors = Off expose_php = Off max_execution_time = 60 max_input_time = 60 error_reporting = E_ALL | E_STRICT display_errors = On log_errors = On memory_limit = 192M post_max_size = 48M upload_max_filesize = 48M max_file_uploads = 50 extension_dir = "/usr/lib/php/extensions/no-debug-non-zts-20090626" zend_extension = "/usr/lib/php/extensions/no-debug-non-zts-20090626/xdebug.so" date.timezone = Europe/London ;browscap = /var/www/vhosts/servers/cache/php_browscap.ini session.save_path = "/tmp" soap.wsdl_cache_dir = "/tmp" xdebug.default_enable = On xdebug.profiler_enable = Off xdebug.profiler_output_dir = /tmp mbstring.internal_encoding = utf8 mbstring.func_overload = 2 ; OSX doesn't use default /var/mysql/mysql.sock pdo_mysql.default_socket = /tmp/mysql.sock mysql.default_socket = /tmp/mysql.sock mysqli.default_socket = /tmp/mysql.sock

DNS (so *.dev points to localhost)

Figured this out thanks to Mike Ferrier (see full details for more than the quick steps below) and is a great way avoid messing with the hosts file:

  1. Generate an rndc key sudo rndc-confgen -a -c /etc/rndc.key
  2. Edit /etc/named.conf and add a zone for dev after one of the others: zone "dev" IN { type master; file "dev.zone"; allow-update { none; }; };
  3. Create a /var/named/dev.zone file $TTL 60 $ORIGIN dev. @ 1D IN SOA localhost. root.localhost. ( 45 ; serial (d. adams) 3H ; refresh 15M ; retry 1W ; expiry 1D ) ; minimum 1D IN NS localhost. 1D IN A 127.0.0.1 *.dev. 60 IN A 127.0.0.1
  4. Set DNS to start automatically: sudo launchctl load -w /System/Library/LaunchDaemons/org.isc.named.plist
  5. System Preferences, Network. Select your network adapter, click Advanced. Select DNS, add 127.0.0.1 then hit Apply. Make sure it's first in the list, so local DNS is queried before slower internet ones which don't know the answer.

Apache

  1. Enable Apache via System Preferences > Sharing > Web Sharing.
  2. Symlink your repos folder and make sure anyone (i.e. Apache) can read+execute repo contents: sudo mkdir /var/www sudo ln -s /Users/yourname/Work/svn /var/www/vhosts sudo chmod a+rx /var/www sudo chmod -R a+rx /var/www/vhosts/*
  3. You'll need to make directories storing user uploaded content writeable too: sudo chmod -R a+wx /var/www/vhosts/app/uploads/*
  4. Replace /etc/apache2/httpd.conf with slim, default-overriding-only version: Listen 80 ServerName localhost ServerAdmin errors@get-sent-here.com ServerRoot "/usr" DocumentRoot "/var/www/vhosts" ErrorLog "/private/var/log/apache2/error_log" LoadModule authz_host_module libexec/apache2/mod_authz_host.so LoadModule cache_module libexec/apache2/mod_cache.so LoadModule deflate_module libexec/apache2/mod_deflate.so LoadModule mime_module libexec/apache2/mod_mime.so LoadModule vhost_alias_module libexec/apache2/mod_vhost_alias.so LoadModule negotiation_module libexec/apache2/mod_negotiation.so LoadModule dir_module libexec/apache2/mod_dir.so LoadModule alias_module libexec/apache2/mod_alias.so LoadModule rewrite_module libexec/apache2/mod_rewrite.so LoadModule php5_module libexec/apache2/libphp5.so LoadModule auth_basic_module libexec/apache2/mod_auth_basic.so LoadModule authz_default_module libexec/apache2/mod_authz_default.so LoadModule mem_cache_module libexec/apache2/mod_mem_cache.so User _www Group _www <Directory /> Options FollowSymLinks AllowOverride None Order deny,allow Deny from all </Directory> <Directory "/var/www/vhosts"> Order allow,deny Allow from 127.0.0.1 </Directory> DefaultType text/plain DirectoryIndex index.html index.php AddType application/x-httpd-php .php EnableMMAP Off EnableSendfile Off TraceEnable Off UseCanonicalName Off AddDefaultCharset UTF-8 AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/x-javascript NameVirtualHost *:80 Include /var/www/vhosts/vhosts.conf
  5. Create PHP script to automatically generate a vhosts.conf and restart Apache: <?php $vhosts = '# This file is automatically generated, do not edit!'; foreach (glob('/var/www/vhosts/*/vhost/dev.conf') as $filename) { $vhosts .= "\nInclude $filename"; } file_put_contents('/var/www/vhosts/vhosts.conf', $vhosts); $result = shell_exec('sudo apachectl configtest'); system('sudo apachectl restart'); ?>
  6. Create 'updatewebserver' command which runs the PHP script: open -e ~/.bash_profile
  7. And add: alias updatewebserver='php /var/www/vhosts/servers/localhost/updatewebserver.php'
  8. Finally, reload your profile for Terminal to take effect: source ~/.bash_profile

Imagemagick

1) Install Homebrew: https://github.com/mxcl/homebrew/wiki/installation 2) $ brew install imagemagick 3) $ curl http://pear.php.net/go-pear.phar > go-pear.phar 4) $ sudo php -d detect_unicode=0 go-pear.phar 4a) Change installation base (option 1) to: /usr/local/pear 4b) Would you like to alter php.ini ? [Y/n] : Y 5) Add pear path to PATH in bash profile 5b) nano ~/.bash_profile 5b2) which is /usr/local/pear/bin 5c) close and re-open terminal 6) $ sudo pecl channel-update pecl.php.net 7) $ sudo pear channel-update pear.php.net 8) $ sudo pecl install imagick 8b) press Enter for the autodefault 9) Add to php.ini: extension="imagick.so"

ICU/intl

Follow steps 7-11 at: http://www.eperezdesigns.com/blog/web-development/php/install-php-extension-intl-on-osx-lion/ which are broadly as follows

Install ICU from http://site.icu-project.org/download/48#ICU4C-Download tar xzvf icu4c-4_8_1-src.tgz cd icu/source ./runConfigureICU MacOSX make sudo make install Download PHP 5.3.6 from http://www.php.net/get/php-5.3.6.tar.gz/from/a/mirror tar zxvf php-5.3.6.tar.gz cd php-5.3.6/ext/intl phpize ./configure --enable-intl make sudo cp modules/intl.so /usr/lib/php/extensions/no-debug-non-zts-20090626/ Add to your php.ini file extension=intl.so Restart Apache sudo apachectl restart Verify your installation php -i | grep intl You should see something similar to this: intl intl.default_locale => no value => no value intl.error_level => 0 => 0

Misc

I find it handy to be able to get to main config files and logs, so created a few links:

sudo ln -s /etc/apache2/httpd.conf /var/www/vhosts/httpd.conf sudo ln -s /etc/php.ini /var/www/vhosts/php.ini sudo ln -s /etc/my.cnf /var/www/vhosts/my.cnf sudo ln -s /var/log/apache2/error_log /var/www/vhosts/error.log

To access your hosts from VirtualBox VM's, edit their hosts files to point names to 10.0.2.2 which is the IP used for guest to reach your main OS. Don't know of a way to get them to work automatically - tried using same IP as DNS server without success...

If OSX ever starts ignoring entries in /etc/hosts check it isn't using DOS line endings.

Personally, I like to keep the PHP manual available locally for viewing in iChm. My development environment works offline, so an offline manual is handy.

Security

Having the vhosts directory readable by all users probably isn't the best idea. It may be possible to do something smarter with groups there. However, I'm assuming you're the only user and full disk FileVault encryption is enabled, which also disables the guest login.

If you get errors about 'Symbolic link not allowed or link target not accessible' the chmods may not have worked. Or your home directory is encrypted with legacy FileVault - upgrade to OSX Lion and new FileVault (which this article was written for) or run Apache as your user (highly not recommended).

Update: OSX Mountain Lion tweaks

First up, make sure you have the latest Xcode CL tools installed:

Then step through the following to get you back on track:

Also, the Web Sharing prefs panel no longer exists.

Next...

I plan to do a clean install of OSX ML plus PHP 5.4, hopefully clean up some of the permission issues, work out why I (mostly) need to have an internet connection for .dev domains to resolve, then rewrite and tidy up the above. Meanwhile, this looks handy...