Tuesday, August 01, 2006

Virtual hosts with Apache and Tomcat

I wanted the ability to host multiple domains from one instance of Tomcat and also wanted to keep the domain name in tact in the browser address bar. I had already been hosting multiple web sites, but when the user would type something like "www.somedomain.com", I would have to redirect them to "www.whitesandsolutions.com/somedomain/do/home" or something like that. What I wanted was the www.somedomain.com to remain in tact.

After a bit of reading, I decided to install the Apache web server and use the virtual host functionality. Click here for the Apache virtual hosts documentation. Name-based virtual hosts were exactly what I needed. Making it all work correctly took a bit of trial and error. Here are some notes of mine. I may not have it configured in the best possible way, but it does work...

Install Apache Web Server 2.2
Install Tomcat 5.5.17

Here is my Apache httpd.conf file. All commented lines have been removed for brevity:

ThreadsPerChild 250
MaxRequestsPerChild 0
ServerRoot "C:/Program Files/Apache Software Foundation/Apache2.2"
Listen 80
LoadModule actions_module modules/mod_actions.so
LoadModule alias_module modules/mod_alias.so
LoadModule asis_module modules/mod_asis.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule authn_default_module modules/mod_authn_default.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authz_default_module modules/mod_authz_default.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule cgi_module modules/mod_cgi.so
LoadModule dir_module modules/mod_dir.so
LoadModule env_module modules/mod_env.so
LoadModule imagemap_module modules/mod_imagemap.so
LoadModule include_module modules/mod_include.so
LoadModule isapi_module modules/mod_isapi.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule mime_module modules/mod_mime.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule negotiation_module modules/mod_negotiation.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule userdir_module modules/mod_userdir.so
ServerAdmin your.name@yourcompany.com
ServerName 123.123.123.123
DocumentRoot "C:/Program Files/Apache Software Foundation/Apache2.2/htdocs"
<Directory />
Options FollowSymLinks
AllowOverride None
Order deny,allow
Deny from all
Satisfy all
</Directory>
<Directory "C:/Program Files/Apache Software Foundation/Apache2.2/htdocs">
Options Indexes FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
</Directory>
<IfModule dir_module>
DirectoryIndex index.html
</IfModule>
<FilesMatch "^\.ht">
Order allow,deny
Deny from all
</FilesMatch>
ErrorLog logs/error.log
LogLevel warn
<IfModule log_config_module>
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
<IfModule logio_module>
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
</IfModule>
CustomLog logs/access.log common
</IfModule>
<IfModule alias_module>
ScriptAlias /cgi-bin/ "C:/Program Files/Apache Software Foundation/Apache2.2/cgi-bin/"
</IfModule>
<Directory "C:/Program Files/Apache Software Foundation/Apache2.2/cgi-bin">
AllowOverride None
Options None
Order allow,deny
Allow from all
</Directory>
DefaultType text/plain
<IfModule mime_module>
TypesConfig conf/mime.types
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
</IfModule>
<IfModule ssl_module>
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
</IfModule>
NameVirtualHost *:80
<VirtualHost *:80>
ServerName 123.123.123.123
ServerAdmin your.name@yourcompany.com
DocumentRoot "C:/Program Files/Apache Software Foundation/Apache2.2/htdocs"
ErrorLog logs/error.log
</VirtualHost>
<VirtualHost *:80>
ServerName www.domain1.com
ServerAdmin your.name@yourcompany.com
DocumentRoot "C:/Tomcat 5.5/webapps/domain1/ROOT/"
ServerAlias domain.com
ErrorLog logs/error.log
ProxyPass / http://localhost:8081/
ProxyPassReverse / http://localhost:8081/
</VirtualHost>
<VirtualHost *:80>
ServerName www.domain2.com
ServerAdmin your.name@yourcompany.com
DocumentRoot "C:/Tomcat 5.5/webapps/domain2/ROOT/"
ServerAlias domain2.com
ErrorLog logs/error.log
ProxyPass / http://localhost:8082/
ProxyPassReverse / http://localhost:8082/
</VirtualHost>
<VirtualHost *:80>
ServerName www.domain3.com
ServerAdmin your.name@yourcompany.com
DocumentRoot "C:/Tomcat 5.5/webapps/domain3/ROOT/"
ServerAlias domain3.com
ErrorLog logs/error.log
ProxyPass / http://localhost:8083/
ProxyPassReverse / http://localhost:8083/
</VirtualHost>


If I remember correctly, the relevant changes I made from the version of this file as it was installed by default was to uncomment a couple of LoadModule lines and then add the virtual host lines at the bottom. I wanted to include the whole thing though for reference.

Once this was done, I then had to configure Tomcat. Here is my Tomcat server.xml file:

<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.core.AprLifecycleListener" />
<Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.storeconfig.StoreConfigLifecycleListener"/>
<GlobalNamingResources>
<Environment name="simpleValue" type="java.lang.Integer" value="30"/>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />

</GlobalNamingResources>
<Service name="Catalina">
<Connector port="8080" maxHttpHeaderSize="8192"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
connectionTimeout="20000" disableUploadTimeout="true" />
<Connector port="8009"
enableLookups="false" redirectPort="8443" protocol="AJP/1.3" />
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true"
xmlValidation="false" xmlNamespaceAware="false">
</Host>
</Engine>
</Service>
<Service name="domain1">
<Connector port="8081"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" acceptCount="100" connectionTimeout="20000"
proxyName="www.domain1.com"
proxyPort="80" disableUploadTimeout="true" />
<Engine name="domain1" defaultHost="domain1-host">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>

<Host name="domain1-host" appBase="webapps/domain1"
unpackWARs="true" autoDeploy="true"
xmlValidation="false" xmlNamespaceAware="false">
</Host>
</Engine>
</Service>
<Service name="domain2">
<Connector port="8082"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" acceptCount="100" connectionTimeout="20000"
proxyName="www.domain2.com"
proxyPort="80" disableUploadTimeout="true" />
<Engine name="domain2" defaultHost="domain2-host">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
<Host name="domain2-host" appBase="webapps/domain2"
unpackWARs="true" autoDeploy="true"
xmlValidation="false" xmlNamespaceAware="false">
</Host>
</Engine>
</Service>
<Service name="domain3">
<Connector port="8083"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" acceptCount="100" connectionTimeout="20000"
proxyName="www.domain3.com"
proxyPort="80" disableUploadTimeout="true" />
<Engine name="domain3" defaultHost="domain3-host">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
<Host name="domain3-host" appBase="webapps/domain3"
unpackWARs="true" autoDeploy="true"
xmlValidation="false" xmlNamespaceAware="false">
</Host>
</Engine>
</Service>
</Server>

The Tomcat directory structure looks like this:



The rest is all standard stuff. Create your ROOT.xml context files, and deploy your web sites. I created an index.jsp file for each of my apps so that when the user typed in www.domain1.com it would redirect to www.domain1.com/do/home. My index.jsp file looks like this:

<%@ taglib uri="/WEB-INF/lib/struts-logic.tld" prefix="logic" %>
<logic:redirect href="
http://www.domain1.com/do/home">;

And I added index.jsp to my welcome-file-list in my ROOT.xml context file:

<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>


Comments are welcome. If you have better, more efficient ways of setting this up, please let me know.

No comments: