Technology from the trenches

Apache2, PHP and MySQL on Mac OSX

I recently setup the so-called “MAMP” (MacOSX, Apache2, MySQL and PHP) on my laptop, so I can have a portable web development environment. I decided to use MacPorts (formerly DarwinPorts) for Apache2 and PHP5, which makes things a lot easier. There were a few “gotchas” though, so I thought I’d share what I learned. If you want an installation completely based on MacPorts builds, this site has some good instructions.

MySQL Preference Panel I went with the binary installation package from MySQL.com, instead of using the MacPorts version, for aesthetic reasons: it comes with a cool preference panel component for starting and stopping the server (click the thumbnail to the right for a larger image). Using this version instead does require a slight tweak to get the MacPorts packages to link to it, but its easy to do.

MySQL Administrator While you’re at MySQL.com, I highly recommend that you also download MySQL Administrator. I’ve never been a big fan of GUI database interfaces, but this is a sweet application, and well worth having.

Once you have MySQL up and running, install Apache2. I don’t know why Apple still ships OSX with Apache 1.x; Apache 2.x has been out for a long time now, and has many improvements over version 1. To install Apache2, run (in Terminal, duh):

sudo port -v install apache2

It installs into /opt/local/apache2. The one thing I dislike about DarwinPorts is the oddball location of /opt/local. Why not just /opt? Adding a /local sub-directory to /opt seems completely redundant.

If you want the System Preferences controls for the webserver to work with the newly installed Apache2, you’ll have to make some minor system changes. I think its worthwhile. Note, however, that future updates from Apple could overwrite these changes, and so you’ll have to redo them if that happens. First, shut down the native Apache1. Open the Sharing panel in System Preferences, click on “Personal Web Sharing”, then click the Stop button if it is running. Next, from the command line (Terminal) move the apachectl binary out of the way and create a link to the new one:

sudo bash
cd /usr/sbin
mv apachectl apachectl.mac
ln /opt/local/apache2/bin/apachectl .
cd /opt/local/apache2/bin
cp apachectl apachectl.bak

I made a backup copy of the apachectl in /opt/local/apache2/bin just in case a system update from Apple over-writes it.

Next, copy /opt/local/apache2/conf/httpd.conf.sample to /opt/local/apache2/conf/httpd.conf, and open the new file in a text editor (using a text editor that saves in plaintext format — do not use TextEdit, since it saves in Rich Text). I changed mine so that the new Apache will work as the system expects the old one to work. Here are the lines that I changed and/or added:

ServerAdmin <my email address>
ServerName <my server's name>
PidFile "/private/var/run/httpd.pid"
DocumentRoot "/Library/WebServer/Documents"

# This should be changed to whatever you set DocumentRoot to.
#
#<Directory "/opt/local/apache2/htdocs">
<Directory "/Library/WebServer/Documents">
...
</Directory>

DirectoryIndex index.html index.php
ErrorLog "/private/var/log/httpd/error_log"
CustomLog "/private/var/log/httpd/access_log" common

Include conf/extra/httpd-userdir.conf

Now you should be able to re-enable “Personal Web Sharing” in System Preferences, and have the new Apache working just like the old one.

The final step is to compile and install PHP5 using DarwinPorts. Before you do, however, it is necessary to modify the port’s Portfile file so that it links to the MySQL 5 install that resides in /usr/local. Make a backup of it first:

cd /opt/local/var/db/dports/sources
cd rsync.rsync.darwinports.org_dpupdate_dports/www/php5/
cp Portfile Portfile.bak

Open the Portfile with your favorite text editor and remove the line “–without-mysql”. Add two new lines:

      --with-mysql=/usr/local/mysql \
      --with-mysql-sock=/private/tmp/mysql.sock \

Now run the port command to download, compile and install PHP5 as a module for our new Apache2:

sudo port -v install php5 +apache2

Now all you need to do is run the command that DarwinPorts suggests, and include the new configuration information in your httpd.conf file. So run:

cd /opt/local/apache2/modules
sudo /opt/local/apache2/bin/apxs -a -e -n "php5" libphp5.so

And add this line to the bottom of the /opt/local/apache2/conf/httpd.conf file:

Include conf/extras-conf/mod_php.conf

Thats it! The installation is done. You might want to tweak the php defaults by copying /opt/local/etc/php.ini-dist to /opt/local/etc/php.ini and adjust to taste. If you use the PEAR extensions, you can customize its defaults by copying /opt/local/etc/pear.conf.sample to /opt/local/etc/pear.conf and editing as needed. Happy developing!

Tags: , , , , , ,

3 Responses to “Apache2, PHP and MySQL on Mac OSX”

  1. Brent Says:

    You may want to enable SSL (https) on your local apache install. To do that, you need to generate a few SSL certificates. Darwin/Macports installed the openssl config files into /opt/local/etc/openssl. Change into that directory, and edit the openssl.cnf file. I changed or added these lines:

    dir = ./CA # Where everything is kept
    default_days = 1365 # how long to certify for
    countryName_default = CA
    stateOrProvinceName_default = Alberta
    localityName_default = Banff
    0.organizationName_default = NetMojo
    commonName_default = localhost
    emailAddress_default = me@localhost

    Next, edit misc/CA.pl. I changed these lines:

    $DAYS="-days 1365"; # 3.74 years
    $CATOP="./CA";
    $DIRMODE = 0755;

    Generate a new Certificate Authority (CA), Certificate Request (a.k.a. private key, for our purposes), and Certificate. Keep this in mind:
    * use a password you’ll remember
    * press Enter to accept the defaults from openssl.cnf
    * skip the challenge password by pressing Enter

    sudo misc/CA.pl -newca
    sudo misc/CA.pl -newreq
    sudo misc/CA.pl -signreq

    Rename the files to something more appropriate:

    sudo mv newkey.pem localhost-key.pem
    sudo mv newcert.pem localhost-cert.pem

    Unencrypt the private key, so you don’t have to enter a password everytime that apache starts up:

    sudo openssl rsa -in localhost-key.pem -out localhost-unenc-key.pem
    sudo chown www localhost-unenc-key.pem
    sudo chmod 0400 localhost-unenc-key.pem

    Now edit the file /opt/local/apache2/conf/extra/httpd-ssl.conf. Here are the lines that I changed:


    SSLCertificateFile /opt/local/etc/openssl/localhost-cert.pem
    SSLCertificateKeyFile /opt/local/etc/openssl/localhost-unenc-key.pem
    SSLCACertificateFile /opt/local/etc/openssl/CA/cacert.pem
    SSLRandomSeed startup file:/dev/urandom 512
    SSLRandomSeed connect file:/dev/urandom 512
    SSLSessionCache shmcb:/private/var/log/httpd/ssl_scache(512000)
    SSLMutex file:/private/var/log/httpd/ssl_mutex
    DocumentRoot "/Library/WebServer/Documents"
    ServerName localhost:443
    ServerAdmin me@localhost
    ErrorLog /private/var/log/httpd/ssl_error_log
    TransferLog /private/var/log/httpd/ssl_access_log
    CustomLog /private/var/log/httpd/ssl_request_log \

    And finally, edit the /opt/local/apache2/conf/httpd.conf file and uncomment the include line:
    # Secure (SSL/TLS) connections
    Include conf/extra/httpd-ssl.conf

    That should be all. Start up apache and check the log files in /private/var/log/httpd. My error_log says:

    [Sun Apr 01 11:49:18 2007] [notice] Digest: generating secret for digest authentication ...
    [Sun Apr 01 11:49:18 2007] [notice] Digest: done
    [Sun Apr 01 11:49:18 2007] [notice] Apache/2.2.4 (Unix) mod_ssl/2.2.4 OpenSSL/0.9.8e
    DAV/2 PHP/5.2.1 configured -- resuming normal operations

    And my new ssl_error_log has a warning:

    [Sun Apr 01 11:49:17 2007] [warn] RSA server certificate is a CA certificate
    (BasicConstraints: CA == TRUE !?)

    And https://localhost works. Enjoy!

  2. Brent Says:

    I discovered a problem with my binary MySQL installation: it breaks some functionality in ‘curl’ that in turn breaks PEAR. Running ‘pear’ produces:

    PHP Fatal error: Unable to start curl module in Unknown on line 0

    This blog points out the reason:

    Basically, MySQL saw it fit to link their binary distribution not against OpenSSL (which is probably available on near 100% of unixoid hosts out there), but YaSSL - of which I personally never even heard. Since function names seem to clash between Ya and OpenSSL, we have a nice mixup here that libcurl (which also links against OpenSSL) can’t really digest. It tries to call the YaSSL init function on startup and fails miserably.

    I’m pretty sure that work around will be to recompile PHP and possibly curl to link against a Macports version of mysql — although I still intend to keep using the binary install from mysql. I’ll have to build mysql so that it uses the same socket destination as the binary install; either that or modify the start up scripts of the binary install to use the default socket location of the Macports install. I’m not sure when I’ll deal with this…

  3. Brent Says:

    Picking up on that thread, I updated my install of Macports, and edited the MySQL5 Portfile so that it uses the same location for the socket file as the binary install.

    The Portfile is in /opt/local/var/db/dports/sources/rsync.rsync.darwinports.org_dpupdate_dports/databases/mysql5, and the line to change is:

    --with-unix-socket-path=/private/tmp/mysql.sock \

    This should allow software linked to this client to access the running MySQL daemon from the binary version. Build & install:

    sudo port -v install mysql5

    Then rebuild and reinstall any libraries or programs that were linked to mysql. For me, thats curl, php and ruby…


    sudo port -v uninstall curl
    sudo port -v install curl +openssl +mysql5

    sudo port -v uninstall php5
    sudo port -v install php5 +apache2 +mysql5

    sudo port -v uninstall rb-rubygems
    sudo port -v uninstall ruby
    sudo port -v install ruby +apache2 +mysql5
    sudo port -v install rb-rubygems

Leave a Reply