Shared Tomcat Hosting

Many smaller companies run there entire system on a standalone server, running many Web Sites from one server is called virtual hosting. These hosting services allow for the sharing of resources such as a Web server, Database server, firewall, etc.

Virtual Hosting Concepts

Different Web site will have distinct Fully Qualified Domain Names (FQDN) which is served by a Web server. A FQDN is in two parts a host and a domain name (web1.datadisk.co.uk - host=web1 domainname = datadisk.co.uk), I have a brief introduction to domain names in my Exim section.

There are two ways that virtual hosting can be implemented

One note before I go on is that if you plan to use SSL then you must use IP-based virtual hosting as SSL requires unique IP addresses.

Virtual Hosting in Apache

All i am going to do here is showing you an example setup of both types of virtual hosting, I will leave you to the internet for more information, basically use the below examples in the httpd.conf file and restart Apache

IP-Based Example
  # Listen on port 80 on all interfaces
Listen 80

# Setup specific interfaces
# Listen 192.168.0.1:80
# Listen 192.168.0.2:80
  ...
<VirtualHost 192.168.0.1>
  ServerName abbott.com
  DocumentRoot /home/websites/abbott/web
  ServerAdmin support@abbott.com
  ErrorLog /home/websites/abbott/error
  TransferLog /home/websites/abbott/log/access
</VirtualHost>

<VirtualHost 192.168.0.20>
  ServerName costello.com
  DocumentRoot /home/websites/costello/web
  ServerAdmin support@costello.com
  ErrorLog /home/websites/costello/error
  TransferLog /home/websites/costello/log/access
</VirtualHost>
Named-Based Example
 

# Listen on port 80 on all interfaces
Listen 80
  ...
NameVirtualHost 192.168.0.1

<VirtualHost 192.168.0.1>
  ServerName abbott.com
  DocumentRoot /home/websites/abbott/web
  ServerAdmin support@abbott.com
  ErrorLog /home/websites/abbott/error
  TransferLog /home/websites/abbott/log/access
</VirtualHost>

<VirtualHost 192.168.0.1>
  ServerName costello.com
  DocumentRoot /home/websites/costello/web
  ServerAdmin support@costello.com
  ErrorLog /home/websites/costelo/error
  TransferLog /home/websites/costello/log/access
</VirtualHost>

Note: the NameVirtualHost ensures that the Apache server will receive HTTP requests for the named-based virtual hosts by using the host and serverName parameters.

Named-Based Example (different ports)
  # Listen on port 80 on all interfaces
Listen 80
Listen 8000
  ...
NameVirtualHost 192.168.0.1:80
NameVirtualHost 192.168.0.1:8000

<VirtualHost 192.168.0.1:80>
  ServerName abbott.com
  DocumentRoot /home/websites/abbott/web
  ServerAdmin support@abbott.com
  ErrorLog /home/websites/abbott/error
  TransferLog /home/websites/abbott/log/access
</VirtualHost>

<VirtualHost 192.168.0.1:8000>
  ServerName costello.com
  DocumentRoot /home/websites/costello/web
  ServerAdmin support@costello.com
  ErrorLog /home/websites/costelo/error
  TransferLog /home/websites/costello/log/access
</VirtualHost>
Named-Based Example (server path)
  NameVirtualHost 192.168.0.1

<VirtualHost 192.168.0.1>
  ServerName abbott.com
  ServerPath /abbott
  DocumentRoot /home/websites/abbott/web
  ServerAdmin support@abbott.com
  ErrorLog /home/websites/abbott/error
  TransferLog /home/websites/abbott/log/access
</VirtualHost>

Virtual Hosting in Tomcat

I have already discussed how Tomcat can work with Apache in Tomcat and Apache setup, but Tomcat can be setup as a standalone server basically responding to requests for both static and dynamic content. Like Apache, Tomcat can use virtual hosting meaning that two or more Web Servers can be on the same Tomcat instance. To setup Tomcat to use virtual hosting is a two step process

First I will discuss setting up Tomcat as a standalone server

Named-Based Example
 

<Server port="8005" shutdown="SHUTDOWN" debug=0>
  ...
  <Service name="Catalina">

  <Connector port="8080" protocol="HTTP/1.1"
             maxThreads="150" connectionTimeout="20000"
             redirectPort="8443"
  />

  <Engine name="Catalina" defaultHost="abbot.com" debug="0"
     
     <Host name="abbot.com" debug="0"
           appBase="/home/websites/abbot/webapps"
           autoDeploy="true" unpackWARs="true"

           <Valve className="org.apache.catalina.valves.AccessLogValve"
                  directory="/home/websites/abbot/logs"
                  prefix="abbot_access."
                  suffix=".log"
                  pattern="common"
                  resolveHost"false"
           />

           <Context path="" docBase="ROOT" debug="0"/>
           <Context path="/laughs" docBase="laughs" debug="0"/>
     /Host>

     <Host name="costello.com" debug="0"
           appBase="/home/websites/costello/webapps"
           autoDeploy="true" unpackWARs="true"

           <Valve className="org.apache.catalina.valves.AccessLogValve"
                  directory="/home/websites/costello/logs"
                  prefix="costello_access."
                  suffix=".log"
                  pattern="common"
                  resolveHost"false"
           />

           <Context path="" docBase="ROOT" debug="0"/>
           <Context path="/laughs" docBase="laughs" debug="0"/>
     /Host>
  /Engine>




  </Service>
</Server>

Note: the context elements are optional, sometimes you may want to override the default one.

IP-Based Example (only available from Tomcat version 5.5 or greater)
 

<Server port="8005" shutdown="SHUTDOWN" debug=0>
  ...
  <Service name="Catalina">

  <Connector port="8080" protocol="HTTP/1.1"
             maxThreads="150" connectionTimeout="20000"
             redirectPort="8443"
             useIPVHosts="true"
  />

  <Engine name="Catalina" defaultHost="abbot.com" debug="0"
     
     <Host name="abbot.com" debug="0"
           appBase="/home/websites/abbot/webapps"
           autoDeploy="true" unpackWARs="true"

           <Valve className="org.apache.catalina.valves.AccessLogValve"
                  directory="/home/websites/abbot/logs"
                  prefix="abbot_access."
                  suffix=".log"
                  pattern="common"
                  resolveHost"false"
           />

           <Context path="" docBase="ROOT" debug="0"/>
           <Context path="/laughs" docBase="laughs" debug="0"/>
     /Host>

     <Host name="costello.com" debug="0"
           appBase="/home/websites/costello/webapps"
           autoDeploy="true" unpackWARs="true"

           <Valve className="org.apache.catalina.valves.AccessLogValve"
                  directory="/home/websites/costello/logs"
                  prefix="costello_access."
                  suffix=".log"
                  pattern="common"
                  resolveHost"false"
           />

           <Context path="" docBase="ROOT" debug="0"/>
           <Context path="/laughs" docBase="laughs" debug="0"/>
     /Host>
  </Engine>
  </Service>
</Server>

Note: there is only once difference than the named-based version is the use of useIPVHosts, this causes Tomcat to use the server name to do the matching for the virtual host, not the passed Host attribute in the HTTP header. You need to make sure that you have hosts entries in /etc/host file or DNS.

When using Apache with Tomcat (Tomcat and Apache setup), they only additional parameter you need to use in Apache is the JkMount inside the <VirtualHost> element and in Tomcat again you use the attribute useIPVHost.

Virtual Hosting Apache/Tomcat # In Apache
<VirtualHost 192.168.0.1>
   ...
   JkMount /*.jsp abbot-worker
</VirtualHost>

# In Tomcat
<Connector port="8009" protocol="AJP/1.3" rediectPort="8443" useIPVHost="true"/>

Tuning and Security

Because both of the Tomcat example above all reside in one instance, there is a single point of failure, in that if the instance were to go down then both virtual hosts will go down. The only way to over come this is to setup two separate Tomcat instances running on the same server, this has advantages and disadvantages.

Separate JVM's for each Virtual Host
Advantages Each instance is separate from each other, thus you can bring one instance down without affecting the other
Each can be monitored separately, so it is easier to spot which one is causing problems
Disadvantages More resources (CPU, Memory, Disk space) are consumed
More work in setting up and maintaining

There are three resource parameters you can adjust within the JVM, I will focus on performance tuning in a later topic but for now i will give you the three parameters. You will need to update the JAVA_OPTS variable in the run.sh script to tune this parameters, depending on how many virtual hosts you are going to use and your memory limits it might be a good idea to up the default values.

Example JVM

# This will be in the bin/run.sh file

JVM_OPTS="-Xms125m  -Xmx256m $JVM_OPTS"

The last item I will discuss the using the security manager with virtual hosts, you can create a separate security policy for each host, thus restricting each host to only accessing the files that it is suppose to access, I have already discussed Tomcat security but you might what to take this example further.

Security Policy grant codeBase "file: /home/websites/abbot/webapps/ROOT/WEB-INF/-" {
  permission java.io.FilePermission "some/abbot/private_resource/*", "read";
  ...
};