---
title:   Running Java .WARs at port 80 with Ivy, Jetty, upstart, authbind and OpenJDK
date:   
lang:    en
origin:  blogger → here
---

Running Java .WARs at port 80 with Ivy, Jetty, upstart, authbind and OpenJDK

First, let's install the various dependencies:

sudo apt-get install openjdk-6-jdk ivy authbind curl nano

We need to create a Hello, World! application to test with:

sudo mkdir /var/tmp/helloworld
sudo chown 1000 /var/tmp/helloworld
echo '<%= "Hello, World! " + new java.util.Date() %>' > /var/tmp/helloworld/index.jsp

Let's test that ivy can fetch us the requirements for running Jetty.

/usr/lib/jvm/java-6-openjdk/bin/java -jar /usr/share/java/ivy.jar -dependency org.mortbay.jetty jetty-runner 7.3.1.v20110307

Use the same mechanism to start up Jetty on port 8080 for /var/tmp/helloworld. Since the previous run cached the dependencies to ~/.ivy2/cache/, this time Jetty will start up much faster.

Notice, that whichever user you end up running the service as must have an existing home directory which they also own.

/usr/lib/jvm/java-6-openjdk/bin/java -jar /usr/share/java/ivy.jar -dependency org.mortbay.jetty jetty-runner 7.3.1.v20110307 -main org.mortbay.jetty.runner.Runner -- --port 8080 /var/tmp/helloworld
curl http://localhost:8080/

Next we need to configure authbind to let you bind to port 80 as a regular user. Unfortunately, Authbind has a bug in that it doesn't let you just configure permissions for 0.0.0.0/0, and you have to define one row for all addresses which start with bit 0 and one row for bit 1. A bit funny, but it works.

echo '0.0.0.0/1:1,32000' > authbind.conf
echo '127.0.0.0/1:1,32000' >> authbind.conf
sudo mv authbind.conf /etc/authbind/byuid/1000 # assuming that your uid is 1000
sudo chown 1000 /etc/authbind/byuid/1000

Let's test your helloworld with Jetty and Authbind together, notice that we must explicitly tell Java to use the IPv4 stack with -Djava.net.preferIPv4Stack=true for authbind to do its jobs properly:

/usr/bin/authbind --deep /usr/lib/jvm/java-6-openjdk/bin/java -Djava.net.preferIPv4Stack=true -jar /usr/share/java/ivy.jar -dependency org.mortbay.jetty jetty-runner 7.3.1.v20110307 -main org.mortbay.jetty.runner.Runner -- --port 80 /var/tmp/helloworld
curl http://localhost/

Since everything went swimmingly so far, we'll go ahead and create an Upstart script to automatically start the service when the server comes up:

sudo nano -w /etc/init/helloworld.conf
# Create a file with the following contents:
start on runlevel [2345]
stop on runlevel [!2345]
	
exec /usr/bin/sudo -u '#1000' \
  /usr/bin/authbind --deep \
  /usr/bin/java -Djava.net.preferIPv4Stack=true -jar /usr/share/java/ivy.jar \
      -dependency org.mortbay.jetty jetty-runner 7.3.1.v20110307 \
      -main org.mortbay.jetty.runner.Runner -- \
          --port 80 /var/tmp/helloworld \
     > /dev/null 2> /dev/null

Now we're ready to test and see that our Upstart script pulls everything together correctly:

sudo start helloworld
curl http://localhost/

If upstart complains that it can't find the service, or something or other, make sure that the exec statement in helloworld.conf is perfect in that it doesn't contain any suprise spaces after the backslashes.

To further customize your environment, take a look at the additional parameters Jetty and Ivy accept:

/usr/lib/jvm/java-6-openjdk/bin/java -jar /usr/share/java/ivy.jar -help
/usr/lib/jvm/java-6-openjdk/bin/java -jar /usr/share/java/ivy.jar -dependency org.mortbay.jetty jetty-runner 7.3.1.v20110307 -main org.mortbay.jetty.runner.Runner -- --help

Have fun!