6

I have a single Tomcat instance containing a number of webapps, each accessible via it's /Context. Tomcat is behind httpd (actually Debian Apache2), configured with virtual hosts to serve each app/Context. Tomcat connectivity is with mod_jk.

This works fine when I don't care about removing the context from urls: when the root of a virtual domain is requested, the requested is redirected to domain.com/Context.

However for one app I do want to remove the context. I believe this can be done by using mod_rewrite, and passing the re-written url to mod_jk for passing on to the correct Tomcat context. So my Debian Apache2 sites-available file looks like this:

NameVirtualHost *

<VirtualHost *>
    ServerName domain.be

    DocumentRoot /home/webapp/app/static/domain/

    RewriteEngine on
    RewriteRule ^/(.*)$ /Context/$1 [L,PT]
    RewriteLog "/var/log/apache2/domain-rewrite.log"
    RewriteLogLevel 4

    JkLogFile     /var/log/apache2/domain-mod_jk.log
    JkLogLevel    debug
    JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
    JkMount /Context w1
    JKMount /Context* w1
    JkOptions +ForwardURICompat

    ErrorLog /var/log/apache2/domain_error.log
    CustomLog /var/log/apache2/domain_access.log combined
    LogLevel warn

</VirtualHost>

According to the docs, the [PT] flag and +ForwardURICompat options should result in the rewritten URL being passed to jk_mod. However that doesn't seem to be happening.

The URL is being re-written, but it seems as if mod_jk is ignoring it: A request for domain.be/Context for example gets rewritten as /Context/Context - but is still handed to mod_jk as /Context.

Any ideas? Incidentally, I cannot use mod_proxy at the moment.

Thanks

Richard H
  • 38,037
  • 37
  • 111
  • 138

5 Answers5

4

@Josh, I think this solution won't work if tomcat performs any redirects. This is the typical case for example in an application demanding a login. When the user is not authenticated the app will redirect to something like /login however tomcat will append the current context like in /context/login so at the end the context does show in the URL.

As you mentioned in your other question/response using just mod-jk plus tomcat virtual hosts is an option but there you will need to deploy your applications as ROOT.war which might not be that straightforward. There is a workaround so your application can be just dropped into tomcat webapps folder but as I described here the server will deploy the app at least twice.

It would be great if RewriteRule[P] plus JkOptions +ForwardURICompat could work but it doesn't. BTW I have tested this and I know mod_proxy does work as I proxied my site to cnn.com and I got their page under my site URL. Below are the logs BTW for the requests where you can see a proxy is being used:

127.0.0.1 - - [15/Dec/2011:12:56:34 --0500] [localhost/sid#1008ef278][rid#1009980a8/initial] (2) forcing proxy-throughput with http://localhost/nestorurquiza-app/
127.0.0.1 - - [15/Dec/2011:12:56:34 --0500] [localhost/sid#1008ef278][rid#1009980a8/initial] (1) go-ahead with proxy request proxy:http://localhost/nestorurquiza-app/ [OK]
127.0.0.1 - - [15/Dec/2011:12:56:49 --0500] [localhost/sid#1008ef278][rid#1009aaca8/initial] (2) forcing proxy-throughput with http://localhost/nestorurquiza-app/login
127.0.0.1 - - [15/Dec/2011:12:56:49 --0500] [localhost/sid#1008ef278][rid#1009aaca8/initial] (1) go-ahead with proxy request proxy:http://localhost/nestorurquiza-app/login [OK]
127.0.0.1 - - [15/Dec/2011:12:57:15 --0500] [localhost/sid#1008ef278][rid#1009980a8/initial] (2) forcing proxy-throughput with http://localhost/nestorurquiza-app/j_spring_security_check
127.0.0.1 - - [15/Dec/2011:12:57:15 --0500] [localhost/sid#1008ef278][rid#1009980a8/initial] (1) go-ahead with proxy request proxy:http://localhost/nestorurquiza-app/j_spring_security_check [OK]
127.0.0.1 - - [15/Dec/2011:13:08:41 --0500] [localhost/sid#1008ef278][rid#1009980a8/initial] (2) forcing proxy-throughput with http://localhost/nestorurquiza-app/
127.0.0.1 - - [15/Dec/2011:13:08:41 --0500] [localhost/sid#1008ef278][rid#1009980a8/initial] (1) go-ahead with proxy request proxy:http://localhost/nestorurquiza-app/ [OK]
Wahyu Kristianto
  • 8,719
  • 6
  • 43
  • 68
Nestor Urquiza
  • 2,821
  • 28
  • 21
  • 1
    You are correct that my original solution is not the best way and fraught with peril. But since posting that, I have used Tomcat VirtualHosts with much success. Despite not hearing about people using it much, it is definitely what one would want to use in this situation and not at all hard after creating one. – Josh Johnson Jun 16 '12 at 17:38
2

I'll leave my original answer up but it is wrong. The proper way to do this would be with a Tomcat VirtualHost:

http://tomcat.apache.org/tomcat-6.0-doc/virtual-hosting-howto.html

The official walk-through in the link above is exactly what I've used several times now. I won't attempt to boil it down here.

The concept is the same as an Apache Vhost. Create a virtual host (eg. for something.yourtdomain.com) and deploy your webapp to the ROOT application (/) for that vhost and you're all set. This way, if you already have a ROOT webapp, you can have another at a different domain and the prior will remain unaffected.

As Nestor mentioned, an Apache rewrite rule will not handle things like tag libs and frameworks that automatically create links/form actions/etc for you based on the context root. In this case they will create the correct context root (/).

Josh Johnson
  • 10,729
  • 12
  • 60
  • 83
  • 2
    In case you were not aware, you can actually leave your applications within the webapps directory and just set the appBase to the full path of the application. --- Example: – skel625 Aug 28 '12 at 07:04
2

I've been using this with great success:

RewriteEngine On
RewriteCond %{REQUEST_URI} !^/(Context/.*)$
RewriteRule ^/(.*)$ /Context/$1 [P,L]

Notes on your situation:

  • You will need to get mod_proxy working or the [P] will be ignored and the request will be forwarded instead of proxied. There is no way around this.
  • +ForwardURICompat is part of mod_jk and will take effect after the rewriting.
  • mod_jk is ignoring the request because it never gets there. You need a RewriteCond (above) to prevent requests to /Context from being rewritten.

I'm currently looking for a way to do this without mod_rewrite and using, instead, just mod_jk and Tomcat <Host>'s. But I'm having trouble with apache, mod_jk and Tomcat hosts playing nicely together. The above should work fine for you.

Community
  • 1
  • 1
Josh Johnson
  • 10,729
  • 12
  • 60
  • 83
0

Following hints given by Nestor Urquiza's answer, i managed to solve the issue by defining additional Host in tomcat's server.xml because as said, the j_security_check request is answered by tomcat with a forward instruction to the browser which inevitably contains the context name so that users trying to login gets 408 errors. Therefore, a real passthrough inside Apache VirtualHost JkMount /* worker1 directive is achievable by making the intended context, a ROOT one.

The Apache httpd.conf [ and/or an included *.conf ] file :

<!-- the subdomain -->

<VirtualHost *:80>
    ServerName appWelcome.example.org
    ServerAlias www.appWelcome.example.org
    JKMount /* worker1
</VirtualHost>

<!-- with mod_jk set up -->

LoadModule    jk_module modules/mod_jk.so
JWorkersFile  /etc/apache2/workers.properties
JkShmFile     /var/log/apache2/mod_jk.shm

So to map all request made to subdomain http://appWelcome.example.org/ directly to the in-charge /appWelcome tomcat context, the appWelcome context must be addressable with request to http://appWelcome.example.org:8080/

So the tomcat server.xml file would then wear a separate Host for the app you are wiling to expose: .

<Server ...>
  <Service>
    <Engine defaultHost="localhost" ...>

      <Host name="appWelcome.example.org" appBase="appWelcomeBase" ... >
        <Valve ... />
      </Host>

      <Host name="localhost" appBase="webapps" ...>
        <!-- this Host is typically shipped with manager, host-manager, docs, 
          sample, examples and a default ROOT context that shows tomcat default home. -->
        <Valve ... />
      </Host>

    </Engine>
  </Service>
</Server>

Note that the permissions ( and selinux context if enabled ) have to be adjust to mimic the default Host ones as follows :

$CATALINA_HOME/conf/Catalina/app.example.org as $CATALINA_HOME/conf/Catalina/localhost

$CATALINA_HOME/appWelcomeBase as $CATALINA_HOME/webapps

Whence this is done all that is left to do is issue rename and move the appWelcome.war web archive for it to auto-deploy in the created appBase ( replacing $CATALINA_HOME with its value, e.g. /var/www/tomcat7) :

# mv $CATALINA_HOME/webapps/appWelcome.war $CATALINA_HOME/appWelcomeBase/ROOT.war

Voila !

simonarame
  • 353
  • 2
  • 9
-1

Use mod_proxy_ajp instead mod_jk like below:

<VirtualHost *:80>
  ServerName domain.be

  DocumentRoot /home/webapp/app/static/domain/

  ...

  ProxyPass /Context ajp://localhost:8009/Context
  ProxyPass / ajp://localhost:8009/Context/

  ...
</VirtualHost>
Kamran
  • 829
  • 1
  • 10
  • 12
  • That still won't work if Tomcat performs any redirects. It doesn't actually change the fundamental problem at all. Not an answer. – user207421 Nov 04 '12 at 09:05