Tele-Lab auf der Cebit 2011

Das Hasso-Plattner-Institut ist auf der Cebit 2011 mit einem eigenen Stand in der Future Parc-Halle vertreten. Dort wird neben anderen Forschungsprojekten des HPI auch das Tele-Lab präsentiert.

Die Cebit findet vom 01. bis zum 05. März 2011 in Hannover statt. Besuchen Sie uns in Halle 9 am Stand C15.

Configuring Apache2 and Tomcat6 with Virtual Hosts

When it comes to setting up Tomcat and Apache with complex URL mappings and for delivering static content through the Apache only, it comes to quite a lot of possible solutions, that turn out to be a little edgy. The scenario:

  • LAMP (Linux, Apache, Mysql, PHP) hosting environment with additional Tomcat
  • serveral Java web applications: app1, app2
  • running on different (sub-)domains: www.foo.de, admin.foo.de, blog.foo.de
  • several other PHP web applications, e.g. phpMyAdmin, WordPress
  • static content (images, html, css, js) shall be served by the Apache
  • mixed content in different context paths within the subdomains

More concrete:

  • app1 will be hosted as www.foo.de, app2 as admin.foo.de
  • there is a WordPress at blog.foo.de
  • the phpMyAdmin will be available at admin.foo.de/pma

We suppose, you know how to deal your favourite Linux distrubution and it’s package managing system. The following relates to Ubuntu Karmic Koala. We installed everything we needed from the Ubuntu repositories except the JDK (we use latest Sun JDK from the manufacturers website and packed it using java-package and dpkg).

All system paths in this document relate to Ubuntu distributions and should also be applicable for Debian.

Setting up the basics

We decided to use mod_jk as connector between Apache2 and Tomcat. You can set up the LAMP, Tomcat and connector with apt-get like this. Confirm installation of all dependencies and check whether you may want one of the suggested packages (such as tomcat6-manager).

sudo apt-get install apache2-mpm-prefork tomcat6 mysql-server libapache-php5 php5-mysql libapache-mod-jk

You should already be able to see the default websites for Apache (http://www.foo.de) and Tomcat (http://www.foo.de:8080).

We will not deal with setting up the Tomcat Manager, but you will usually at least have to setup user credentials. Please refer to the Tomcat documentation.

Connecting Apache and Tomcat

The next thing is to configure mod_jk to connect Apache2 and Tomcat. JK uses the ajp13 (Apache JServ Protocol), to forward client requests from an HTTP server (Apache) to a servlet container (Tomcat) running the actual web application. First of all, enable the Apache module:

sudo a2enmod jk

Define the Tomcat as a so called worker for Apache by creating the file /etc/apache2/worker.properties like this:

workers.tomcat_home=/usr/share/tomcat6
workers.java_home=/usr/lib/j2sdk1.6-sun
ps=/
worker.list=tomcat6
worker.tomcat6.port=8009
worker.tomcat6.host=localhost
worker.tomcat6.type=ajp13
worker.tomcat6.lbfactor=1

Configure mod_jk either in /etc/apache2/mods-available/jk.conf or /etc/apache2/httpd.conf (we did the latter), but don’t forget to check the JK reference, if the below JkOptions suit your needs:

<IfModule mod_jk.c>
   JkWorkersFile /etc/apache2/workers.properties
   JkShmFile     /var/log/apache2/mod_jk.shm
   JkLogFile     /var/log/apache2/mod_jk.log
   JkLogLevel    warn
   JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
   JkOptions     +ForwardKeySize +ForwardURIProxy -ForwardDirectories
</IfModule>

Now, we only have to tell the Tomcat to provide a listening connector for incoming ajp13 requests (from the mod_jk connector). This can be done within /etc/tomcat6/server.xml (resp. $CATALINA_HOME/conf/server.xml). Usually, you just have to uncomment the appropriate line:

<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

The only issue that is left to make the servlets available via HTTP requests to the Apache, is defining a mount point for the JK connector. The rudimentary directive i.e. in /etc/apache2/sites-available/default looks like:

<VirtualHost *:80>
   ServerName www.foo.de
   DocumentRoot /var/www
   [...]
   <IfModule mod_jk.c>
      JkMount / tomcat6
      JkMount /* tomcat6
   </IfModule>
   [...]
</VirtualHost>

After restarting Apache and Tomcat, you should realize that http://www.foo.de is now serving the Tomcat ROOT application on port 80.

sudo /etc/init.d/tomcat6 restart
sudo /etc/init.d/apache2 restart

Subdomains and Virtual Hosts

In the next step, we will set up the virtual hosts for our subdomains http://admin.foo.de and http://blog.foo.de. We decided to have directories in $CATALINA_BASE for each (sub)domain, i.e. /var/lib/tomcat6/wwwapps for www.foo.de and /var/lib/tomcat6/adminapps for admin.foo.de.

We have to configure both – the Tomcat ant the Apache – to deal with the name-based virtual hosts. In the first, we take care for the Tomcat configuration, where we want to have our main applications for the virtual hosts being deployed to the root context / of each domain. Again edit /etc/tomcat6/server.xml and add some Host entries:

[...]
<Engine name="Catalina" defaultHost="www.foo.de">
   [...]
   <Host name="www.foo.de"  appBase="wwwapps"
         unpackWARs="true" autoDeploy="true"
         xmlValidation="false" xmlNamespaceAware="false">
      <Alias>foo.de</Alias>
      <Alias>localhost</Alias>
      <Valve className="org.apache.catalina.valves.AccessLogValve"
             directory="/var/log/apache2" prefix="www_access_"
             suffix=".log" pattern="common" resolveHosts="false"/>
   </Host>
   <Host name="admin.foo.de" appBase="adminapps"
         unpackWARs="true" autoDeploy="true"
         xmlValidation="false" xmlNamespaceAware="false">
      [...]
   </Host>
</Engine>
[...]

The Alias- and Valve-directives in the first Host entry are optional. The latter is for logging purposes. The Tomcat will not load the configuration change automatically but will have to be restarted: sudo /etc/init.d/tomcat6 restart.

Now for the Apache2 configuration. At first, we have to ensure the Apache to understand name-based virtual hosts. There should be a directive (NameVirtualHost *) for this in either apache2.conf, httpd.conf or (as in Ubuntu) ports.conf.

root@foo:/$ cat /etc/apache2/ports.conf
NameVirtualHost *:80
Listen 80
<IfModule mod_ssl.c>
    # SSL name based virtual hosts are not yet supported
    Listen 443
</IfModule>

Since we want our main domain www.foo.de only serving a Java web application, we just modify the default virtual host in /etc/apache2/sites-available/default as follows (remember that we want to deploy to the ROOT context later on):

<VirtualHost *:80>
   ServerName www.foo.de
   ServerAlias foo.de

   DocumentRoot /var/lib/tomcat6/userapps/
   <Directory /var/lib/tomcat6/userapps/>
      Options FollowSymLinks Indexes
      AllowOverride None
   </Directory>

   Alias / /var/lib/tomcat6/userapps/ROOT/

   <IfModule mod_jk.c>
      JkMount / tomcat6
      JkMount /* tomcat6
      JkUnMount /*.css tomcat6
      JkUnMount /*.js tomcat6
      JkUnMount /*.jpg tomcat6
      [...]
   </IfModule>
   [...]
</VirtualHost>

The Alias directive and the JkUnmount entries will do the trick of serving the static files (css/js/jpg/gif/png/html/…) not through the JK connector from Tomcat but will make the Apache directly deliver those files. Add the appropriate JkUnMount directives to match all your types of static content.

We set up a second virtual host for admin.foo.de in /etc/apache2/sites-available/admin analogous to the default one. Don’t forget to activate it.

sudo a2ensite admin

As already stated, we want to have additional administrative tools (next to the Java web app, that we will deploy to admin.foo.de), such as the phpMyAdmin. And we want to access this one at http://admin.foo.org/phpMyAdmin. With the configuration so far, we would get a 404 error site from the Tomcat, since JkMount /* tomcat6 in our Virtual Host configuration hands all requests to the servlet container.

In preparation, we must create a symbolic link in the DocumentRoot of admin.foo.de pointing to the directory for phpMyAdmin. In this example, let it be

sudo ln -s /var/www/phpMyAdmin /var/lib/tomcat6/adminapps/phpMyAdmin

We have to enhance that configuration file as follows (compare to config file for default host above):

<VirtualHost *:80>
   ServerName admin.tele-lab.org

   DocumentRoot /var/lib/tomcat6/adminapps/

   Alias /phpMyAdmin /var/lib/tomcat6/adminapps/phpMyAdmin
   Alias / /var/lib/tomcat6/adminapps/ROOT/ 

   <Directory "/var/lib/tomcat6/adminapps/">
      Options Indexes FollowSymLinks +Includes
      AllowOverride All
   </Directory>
   <Directory "/var/www/phpMyAdmin">
      Options Indexes FollowSymLinks
      AllowOverride AuthConfig
   </Directory>

   <IfModule mod_jk.c>
      JkMount /* tomcat6
      JkUnMount /*.css tomcat6
      JkUnMount /*.js tomcat6
      JkUnMount /*.jpg tomcat6
      [...]
      JkUnMount /phpMyAdmin/* tomcat6
   </IfModule>
   [...]
</VirtualHost>

The idea is, to exclude everything under http://admin.foo.de/phpmyadmin from being served by the Tomcat (see the last JkUnMount entry). Additionaly, we have to make the content from /var/www/phpMyAdmin available under the DocumentRoot. That is, why we need another Alias (mind the sequence of Aliases, it is important!) and the second Directory directive.

Deploying to root context

As already mentioned, we want to have our Java web apps available at the root context of the respective (sub)domain. Deploying to there is fairly ease: just delete the applications deployed to there by default (aka undeploying).

sudo rm -r /var/lib/tomcat6/webapps/ROOT*

Since Tomcat does not always release allocated memory for undeployed applications, it’s advisable to restart it at this time. Finally copy your war-File to the directory for your virtual host like this (i.e. for admin.foo.de):

sudo cp ~/my-app-0.1.war /var/lib/tomca6/adminapps/ROOT.war

[tbc.]