I spent yesterday afternoon trying to get Tomcat web apps served via Apache, since that decouples the public interfaces of our web services from their implementation — people don’t need to know when they hit a service that it’s running on a Tomcat server on port 8080. There’s a connector to allow this, mod_jk, but it’s a bit of a pain to get working — it required changes to five different config files. So I’ve pasted the required changes here, hopefully this will be helpful.
The scenario is that there’s a site (funcnet.eu) which will be running as an Apache 2.2.3 virtual host on an existing server. Two paths on that site should be redirected to CXF webapps running on Tomcat 6.0.16 on the same physical box. Any requests outside those two directories should be handled by Apache itself. This lets us host a WordPress installation and Java apps/services on funcnet.eu in a seamless way.
So first, the server-wide Apache configuration, just to load the mod_jk library, in /etc/httpd/conf/httpd.conf :
LoadModule jk_module modules/mod_jk.so
Then we need to add some JK mounts to the funcnet.eu virtual server configuration in /etc/httpd/conf.d/virtual_hosts.conf , as well as some rewrite rules using mod_rewrite:
<VirtualHost *:80>
ServerName www.funcnet.eu
ServerAlias funcnet.eu *.funcnet.eu funcnet.cathdb.info
DocumentRoot /var/www/virtual-hosts/funcnet.eu
ErrorLog logs/funcnet.eu/error_log
CustomLog logs/funcnet.eu/access_log common
JkMount /BioMiner-war local8009
JkMount /BioMiner-war/* local8009
JkMount /frontend-war local8009
JkMount /frontend-war/* local8009
RewriteRule ^/frontend/soap(.*)$ /frontend-war/services$1 [PT,QSA]
RewriteRule ^/frontend(.*)$ /frontend-war$1 [PT,QSA]
RewriteRule ^/biominer/soap(.*)$ /BioMiner-war/services$1 [PT,QSA]
RewriteRule ^/biominer(.*)$ /BioMiner-war$1 [PT,QSA]
</VirtualHost>
The idea of JkMount is that any request matching one of the URL patterns given will be handled by the ‘worker’ specified, local8009 (see below). Anything not matching these patterns will be handled by Apache. I’m not sure if you really need the exact-match version as well as the wildcard version for each directory, but one or two examples I saw used this, one day I’ll test it but for now it can remain in cargo-cult territory. The rewrite rules are completely optional, they’re just there to shorten and neaten-up the URLs we publish.
Then we created a file called /etc/httpd/conf.d/jk.conf (alk .conf files in conf.d are automatically loaded by our Apache server):
JkWorkersFile /etc/httpd/conf/workers.properties JkLogFile /etc/httpd/logs/mod_jk.log JkShmFile /etc/httpd/logs/mod_jk.shm JkLogLevel info JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
These should be pretty self-explanatory. Then finally (for Apache) we had to create /etc/httpd/conf/workers.properties as described in the previous file:
worker.list=local8009 worker.local8009.type=ajp13 worker.local8009.host=localhost worker.local8009.port=8009
This sets up a single ‘worker’ called local8009 which is an instance of Tomcat running on localhost. It communicates with Apache via the AJP/1.3 protocol on port 8009 — Apache uses this optimized binary protocol to talk to Tomcat as this is much more efficient than just proxying HTTP requests.
Finally, we had to add an AJP13 connector to our Tomcat server.xml (within the <Service name=”Catalina”> node) which listens on the port specified above:
<Connector
port="8009" protocol="AJP/1.3" maxPostSize="-1" maxSavePostSize="-1"
proxyName="funcnet.eu" proxyPort="80"/>
This disables a couple of maximum-size parameters (details here) and sets the hostname and port number that will be reported to applications invoked via AJP, should they request it. (I haven’t tried this yet though…)
I’m pretty happy with this setup as it lets us run a WordPress site in PHP on funcnet.eu and serve the Java web services off the same domain, along with any other static downloads we need. Hope the instructions are fairly clear, drop a comment if you get stuck. One thing worth noting is that you can raise the log level from ‘info’ to ‘debug’ in jk.conf to get more information in mod_jk.log if you need it. But this actually makes a log entry for every NON-proxied request to Apache (i.e. “couldn’t find a mapping for…”) so it’ll get very big very quickly.
EDIT: I’ve changed the rewrite rules from those given above as it appears CXF gets confused when you try to invoke a service endpoint (or its built-in WSDL rewriter) via a rewritten-and-then-proxied URL. So now the virtual host config for Apache looks like this:
<VirtualHost *:80>
ServerName www.funcnet.eu
ServerAlias funcnet.eu *.funcnet.eu funcnet.cathdb.info
DocumentRoot /var/www/virtual-hosts/funcnet.eu
ErrorLog logs/funcnet.eu/error_log
CustomLog logs/funcnet.eu/access_log common
JkMount /BioMiner-war local8009
JkMount /BioMiner-war/* local8009
JkMount /frontend-war local8009
JkMount /frontend-war/* local8009
RewriteEngine on
RewriteLog /etc/httpd/logs/funcnet.eu/rewrite_log
RewriteLogLevel 2
RewriteRule ^/soap/FrontEnd.wsdl$ /frontend-war/services/FrontEndService?wsdl [PT]
RewriteRule ^/soap/Geco.wsdl$ /BioMiner-war/services/GecoService?wsdl [PT]
RewriteRule ^/soap/Hippi.wsdl$ /BioMiner-war/services/HippiService?wsdl [PT]
RewriteRule ^/soap/CodaCath.wsdl$ /BioMiner-war/services/CodaCathService?wsdl [PT]
RewriteRule ^/soap/CodaPfam.wsdl$ /BioMiner-war/services/CodaPfamService?wsdl [PT]
</VirtualHost>
So now we just have permanent funcnet.eu/soap/<servicename>.wsdl URLs that serve the real WSDLs containing the SOAP endpoint addresses — which handily start with http://funcnet.eu/ because CXF’s WSDL rewriter detects what server the WSDL was requested via by looking in the query string.
Andrew.
{ 2 } Comments
One gotcha, if you are serving static content located in Tomcat under any of the mounted contexts, /* forces that content to be funneled up through ajp, which is a performance killer. Also make sure you are on the very very latest modjk, even if you have to BYO, as it offers loadbalancing yumminess.
Nah, all of the static stuff is hosted by Apache outside of those paths — despite any appearance to the contrary I might have given by phrasing it badly
Thanks for the tip though.
Post a Comment