Friday, September 14, 2007

MySQL, Apache2, PHP5 and Tomcat (with mod_jk) on Mac OsX

For MySQL, Apache and Php5 there are a couple of web pages describing how to do it, and some package does automagically everything (e.g. MAMP). However, in such way you are bound to certain versions - sometimes old.
A better option is to be able to do it yourself, so that you can upgrade when you want and choose the version you want. Avery good description of how to do that is given in Richard Valk's blog.
Here are the links:
What is really good in these pages is that Richard describes the way to install these softwares in a way that is somehow independent on the actual version.
For instance, by carefully following step by step the instructions, I was able to successfully install the current versions: httpd 2.2.6, mysql 5.0.45, php 5.2.4 even though his instructions refer to earlier versions.
At the end of the process described in these pages you'll have Apache and MySql starting automatically at boot time.

Delicate points in the process are:
- make sure that you choose the script for the right architecture (ppc or intel)
- make sure that you carefully read and follow the section about the MySQL libraries.

One point not mentioned in Richard's php page is the fact that probably you also want to add index.php as a file automatically used when you access a directory (as index.html is). To do it you have to edit Apache2/conf/httpd.config, and modify the DirectoryIndex statement as follows:

<ifmodule>
DirectoryIndex index.html index.php
</ifmodule>

To check that it works, create the file index.php in your deployment directory (default is the Apache's htdocs) with the following content

<html><body><h1>It works!</h1>

<h2><?php
echo("php also works!");
phpinfo();
?></h2>

</body></html>

and then point at http://localhost/index.php.

Another point is that when you invoke apachectl (to start and stop Apache) probably it still resolves to the preinstalled Apache (try to issue the which apachectl command in a shell, you will probably find out that this points to /usr/sbin/apachectl). This can generate problems. I solved this by renaming /usr/sbin/apachectl to /usr/sbin/apachectl_orig (just to be able to restore the original setting if needed!), and creating a link from /usr/sbin/apachectl to /Library/Apache2/bin/apachectl:
ln -s /Library/Apache2/bin/apachectl /usr/sbin/apachectl



Let's now move on to Tomcat: its installation is very simple, and is well described on the apache wiki: essentially you download, unpack, and set the JAVA_HOME environment variable. I easily installed 5.5.25 ( I unpacked it in /Library/Tomcat - note that later there will be references to this directory - so if yours is different adapt the commands to your configuration).

At this point Tomcat responds on port 8080 while Apache responds on port 80. It would be better to have both of them responding on port 80. This can be done by registering Tomcat as an Apache service, so that Apache recognizes certain URLs and forwards them to Tomcat. Doing so (through the mod_jk module) is a bit more complex - because I was not able to find reliable instructions, and the official documentation page does not describe clearly all steps.
So here is how I did it:

1) define the TOMCAT_HOME environment variable pointing at the place where Tomcat was unpacked;

2) get the mac binary mod_jk.so (the actual name will be something like mod_jk-1.2.25-httpd-2.2.4.so) from the Tomcat site, rename it mod_jk.so and drop it into APACHE2_HOME/modules, where APACHE2_HOME stays for the place where Apache2 was installed.

3) edit conf/server.xml in your TOMCAT_HOME, find the line
</Engine>
and add right before that:
<Listener className="org.apache.jk.config.ApacheConfig" modJk="/Library/Apache2/modules/mod_jk.so" />
(assuming that /Library/Apache2 is your Apache2 home).

4) Create a new file containing the following lines:

# Setup for Mac OS X
# Define the homes
workers.tomcat_home=/Library/Tomcat
workers.java_home=/Library/Java/Home

# Define the file separator
ps=/

# Define the worker's names
worker.list=ajp13

# Definition for worker
#
worker.ajp13.port=8009
worker.ajp13.host=127.0.0.1
worker.ajp13.type=ajp13

and save it with the name workers.properties in the directory TOMCAT_HOME/conf/jk (if the directory does not exist, create it).

5) edit conf/httpd.config in Apache2, adding at the end of the file:
# Tomcat bridge auto configuration
Include /Library/Tomcat/conf/auto/mod_jk.conf
(assuming that your TOMCAT_HOME is /Library/Tomcat)

6) restart Tomcat (sudo $TOMCAT_HOME/bin/shutdown.sh an then sudo $TOMCAT_HOME/bin/startup.sh). At this point the file called /Library/Tomcat/conf/auto/mod_jk.conf is automatically created.

7) restart Apache (sudo $APACHE_HOME/bin/apachectl restart)

8) open a browser, and point it to http://127.0.0.1/servlets-examples/
You should see page coming from your TOMCAT_HOME/webapps/servlets-examples. You can try to execute the hello world, everything should be now fine.

The next problem is what happens if you want all this to work with your machine name instead of localhost.
In fact opening
http://your_machine.your.domain/servlets-examples/ in your browser will give a "Not Found". To fix this, you'll have to change in conf/xml the following lines:

<Engine name="Standalone" defaultHost="localhost" jvmRoute="jvm1">
...
<Engine name="Catalina" defaultHost="localhost">
...
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true"
xmlValidation="false" xmlNamespaceAware="false"
>


In all three cases you need to change "localhost" with "your_machine.your.domain" where
your_machine.your.domain is of course the name of your machine.
Restart Tomcat first and then restart Apache: point at
http://your_machine.your.domain/servlets-examples/ in your browser and it should work. Note that now http://127.0.0.1/servlets-examples/ will give a Not Found!
If you want both localhost (127.0.01) and
your_machine.your.domain, you'll have to go though the Virtual Hosts setting - but I'll not cover that here.

IMPORTANT NOTICE: when you deploy a new webapp, always first restart Tomcat and then restart Apache (so that the automatic configuration is first regenerated by Tomcat and then read by Apache).

The next step would be to have Tomcat starting automatically at boot time.
An example and some explanation can be found here.
In short, here is what is needed (assuming that you already have Apache starting at boot):
a) create a directory Tomcat in /System/Library/StartupItems/
b) create a file called Tomcat in that directory. This is its content (of course reference to the directory where Tomcat is installed should be modified according to you system):
#!/bin/sh

. /etc/rc.common

StartService ()
{
if [ "${TOMCAT}" = "-YES-" ]; then
ConsoleMessage "Starting Tomcat Servlet/JSP Server"
/Library/Tomcat/bin/startup.sh
fi
}

StopService ()
{
ConsoleMessage "Stopping Tomcat Servlet/JSP Server"
echo "Stopping Apache web server"
/Library/Tomcat/bin/shutdown.sh
}

RestartService ()
{
ConsoleMessage "Restarting Tomcat Servlet/JSP Server"
echo "Restarting Apache web server"
/Library/Tomcat/bin/shutdown.sh
/Library/Tomcat/bin/startup.sh
}

JAVA_HOME=/Library/Java/Home; export JAVA_HOME
RunService "$1"

and make it executable
(sudo chmod a+x
/System/Library/StartupItems/Tomcat/Tomcat)

c) Next create a file called StartupParameters.plist into the same Tomcat directory. The content should be:
{
Description = "Tomcat Servlet/JSP Server";
Provides = ("Tomcat");
Requires = ("Resolver");
OrderPreference = "None";
Messages =
{
start = "Starting Tomcat Servlet/JSP Server";
stop = "Stopping Tomcat Servlet/JSP Server";
};
}

d) The last step is to make sure that Apache will wait for Tomcat to start. We can do that by changing the
StartupParameters.plist in the
/System/Library/StartupItems/Apache directory in the following way:

{
Description = "Apache web server";
Provides = ("Web Server");
Requires = ("Tomcat");
Uses = ("Disks", "NFS");
}

(essentially we added the line that declares that Apache "Requires Tomcat").

For further info on Tomcat and on how to deploy servlets and JSPs. see the article on Apple Developer's Connection.

No comments: