Tuesday, January 22, 2008

Leopard for the Web Developer - Running Tomcat as a Service

In my experimentation with configuring multiple virtualhosts with SSL, I stumbled upon the magic of launchd within mac os x. I use it to make a call to ifconfig when I start up to create a new loopback interface, and it works splendidly. Knowing that it would work on startup, I thought I'd apply the principles to Tomcat.

The process of setting up Tomcat as a service in Leopard is extremely simple. It goes something like this:

  1. Download Tomcat
  2. Unpack Tomcat where you want it (/usr/local/tomcat is a good spot)
  3. Create a lauchd plist configuration to point to the tomcat executable
  4. Place that configuration file someplace where launchd will find it.
  5. invoke launchdctl to install the new service
Once you do steps 1 and 2, it's time to create the launchd plist file. Here's what mine looks like -- I'll explain what's going on following

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>

<key>Disabled</key>
<false/>

<key>EnvironmentVariables</key>
<dict>
<key>JAVA_HOME</key>
<string>/System/Library/Frameworks/JavaVM.framework/Home</string>
</dict>

<key>Label</key>
<string>org.apache.tomcat.tomcat6</string>

<key>ProgramArguments</key>
<array>
<string>/usr/local/tomcat6/bin/catalina.sh</string>
<string>run</string>
</array>

<key>RunAtLoad</key>
<true/>

<key>ServiceDescription</key>
<string>Tomcat 6 Server</string>

</dict>
</plist>

OK, here's what's happening. The plist defines a dictionary data structure instructing launchd how it should work. You'll see a <key> followed by a value of some sort. I'll go key by key.

  1. Disabled - a boolean value.
    If you want to have this active, set the value to false, as it is here. If you want to disable the service without uninstalling it, just change the disabled value to true.
  2. EnvironmentVariables - a (sub)dictionary value.
    This is just a set of name value pairs defining environment variables that you might need. In our case, Tomcat needs to know what JAVA_HOME is. You can set more if you want by adding more <key> and <string> pairs
  3. Label - a String value.
    This one is really important. It needs to be a unique identifier for the launchd process. launchd keeps track of all the things it starts and stops with this Label value. Just make sure that it's unique. It's common practice to use the reverse-domain syntax that you see here (org.apache.tomcat.tomcat6). Incidentally, it's also common practice to name this plist file with the same label (org.apache.tomcat.tomcat6.plist)
  4. ProgramArguments - an array of strings.
    Think of this as what you would type at the command line. Basically, anything you can do at the command line can be placed in a ProgramArguments value. The first string in the array is the executable program that you wish to run. Anything following is an argument that you would pass to that command. In our case, this merely does the following command:
    /usr/local/tomcat6/bin/catalina.sh run
  5. RunAtLoad - boolean value.
    This is what makes this a service, telling OS X that this should run when starting up.
  6. ServiceDescription - String value.
    This helps in the console to figure out what's running. It should just be some sort of description identifying the process. In this case, Tomcat 6 Server.
And that's it for the configuration file. Go ahead and save it as org.apache.tomcat.tomcat6.plist on your desktop, or somewhere else obvious. We'll move it to where it needs to reside next.

Launchd looks in a couple of places for these kinds of configuration files. From the man pages of launchd:

~/Library/LaunchAgents         Per-user agents provided by the user.
/Library/LaunchAgents Per-user agents provided by the administrator.
/Library/LaunchDaemons System wide daemons provided by the administrator.
/System/Library/LaunchAgents Mac OS X Per-user agents.
/System/Library/LaunchDaemons Mac OS X System wide daemons.


Since I want tomcat to start up as a machine process, not a user one, I place it in /Library/LaunchDaemons. If I wanted to make it a user process, I put it in ~/Library/LaunchAgents. A couple notes about this. First, if you put your file in /Library/LaunchDaemons, the plist file needs to be owned by root. The easiest way to do this is to open Terminal and do a "sudo cp org.apache.tomcat.tomcat6.plist /Library/LaunchDaemons/". This will make root own the file so it can start up as a system process. Second, if you decide to place the file in ~/Library/LaunchAgents, you don't need root ownership, but you do need to make sure the directory exists. By default, Leopard does not have a "LaunchAgents" folder in the user Library. So, you might have to make that directory before you copy your file there.

Final step, you'll need the Terminal. It's install time.

If you placed the plist in /Library/LaunchDaemons, do this

sudo launchctl load /Library/LaunchDaemons/org.apache.tomcat.tomcat6.plist


If you placed the plist in ~/Library/LaunchAgents, do this

launchctl load ~/Library/LaunchAgents/org.apache.tomcat.tomcat6.plist


That should do it. You now have Tomcat installed as a service on Leopard.

8 comments:

BugBoy said...

thanks for the article. i think i followed all your steps. i rebooted and tried to access tomcat to no avail, but if i navigate to the /usr/local/tomact/bin directory and call ./catalina.sh run
tomcat starts right up

Anonymous said...

worked for me beautifully!
thanks a bunch

Oliver said...

you can start without rebooting your mac with

launchctl start org.apache.tomcat.tomcat6


then, use

tail /var/log/system.log

for error checking during start

Eric said...

Excellent tip, Oliver. Thanks!

Anonymous said...

Worked for me too!. As a follow up, how about a howto for fronting tomcat with apache?

Eric said...

Although there's some extra steps involved in getting Apache to connect to Tomcat, one of the first steps involved is getting mod_jk installed. I have an article about doing that here:

Install mod_jk on Leopard

I'll try to find some time to write up the missing steps to connect the two, but this should get you started

Eric said...

@bugboy

It sounds like you might have a permissions problem. If you install the plist file in /Library/LaunchDaemons you need to make sure that the file is owned by the root user. Try using the terminal and sudo to make that happen. The following command may help you:

sudo chown root /Library/LaunchDaemons/org.apache.tomcat.tomcat6
.plist

ignacio cases said...

It works really nice. Thank you very much.