How to reverse proxy with apache2 with mod_jk load balancing

Hello,
In my previous post I’ve talked about setting up 2 instances of tomcat on the same machine. This post is the second one of my series about load balancing instances of tomcats on a single machine as it’s a continuation of the first one. it talks essentially about how the real load balancing can be setup using mod_jk. Again in this post we are going to referrence our tomcat servers timo and pumba that we setup during the first post.

Apache mod_jk is a module for apache but maintained separately. In case you don’t have apache installed already, then install it with the following command:

$ sudo apt-get install apache2

We now need to install the module mod_jk .Unlike mod_proxy which is newer and comes bundled and maintained with apache2, mod_jk is installed differently. It’s module name can differ from distribution to distribution but, on Ubuntu we use the following to install it:

$ sudo apt-get install libapache2-mod-jk

Let’s pause here. Most of the time, modules come bundled with apache2 but not enabled. In Ubuntu they are found under the folder

/etc/apache2/mods-available

They are enabled with a command a2enmod. Its usage is simple:

$ sudo a2enmod name-of-the-module

Once the command is successful it creates s symbolic link of the

/etc/apache2/mods-available/module-name.conf
#
/etc/apache2/mods-available/module-name.load

to the folder

/etc/apache2/mods-enabled

That’s generally what happens but in our case , we won’t need to call the a2enmod command because as soon as libapache2-mod-jk is installed it’s enabled as well so it has both jk.conf and jk.load in the available as well as the enabled folder(but as a symbolic link)

Let’s edit jk.conf in the /etc/apache2/mods-available folder.

$ nano /etc/apache2/mods-available

Find and change this line

JkWorkersFile /etc/libapache2-mod/workers.properties

to look like the line below

JkWorkersFile /etc/apache2/workers.properties

Comment out the block and make the look like below:

  <Location /jk-manager>
        JkMount jk-status
        Order deny,allow
        Deny from all
        Allow from 127.0.0.1 # you can add other ips separated by a space
   </Location>

In the location tag, we are instructing apache2 to do use the worder jk-status when the url /jk-manager white list of IPs where connections should be allowed from.

Let’s create our own workers.properties file, a much simpler one. We will put it inside apache2 folder: /etc/apache2

$ sudo nano /etc/apache2/workers.properties
worker.list=loadbalancer,jk-status # configure list of workers to run

#setup 
worker.timo.port=8009 # ajp port on timo server
worker.timo.host=localhost
worker.timo.type=ajp13
worker.timo.lbfactor=2

#setup pumba
worker.pumba.port=8010 # ajp port on pumba server
worker.pumba.host=localhost
worker.pumba.type=ajp13
worker.pumba.lbfactor=1

#setup the load-balancer
worker.loadbalancer.type=lb
worker.loadbalancer.balance_workers=timo,pumba
worker.loadbalancer.sticky_session=True
#worker.loadbalancer.sticky_session_force=True

# Status worker for managing load balancer
worker.jk-status.type=status # setting type of jk-status' worker.

To be able to let the 2 servers timo and pumba look like a distributed system where users would not have to call them using 2 differents ports etc, we will setup a virtualhost on apache2 so that it will interface them, and then load balance them.

Let’s configure the virtualhost. We are going to create it Ubuntu’s way as in the /etc/apache2/sites-available folder.The file name is ourtimoandpumba.org it’s also the name of the virtualhost that we will have to enable later

$ nano /etc/apache2/sites-available/ourtimoandpumba.org
#/etc/apache2/sites-available/ourtimoandpumba.org
<VirtualHost *:80>
  ServerAdmin [email protected]
  ServerAlias live.ourtimoandpumba.org
  ServerName ourtimoandpumba.org
  JkMount /* loadbalancer
  JkMount /jk-manager/* jk-status
  Loglevel warn
  ErrorLog /var/log/apache2/ourtimoandpumba_error_log
  CustomLog /var/log/apache2/ourtimoandpumba_access_log combined
</VirtualHost>

After saving with crtl +X combination we need to enable the virtualhost unless it won’t be available. This supposed there is a domain name of the name ourtimoandpumba.org which is already pointed to the IP of the our physical server. As opposed to a2enmod to enable a module, we use a2ensite for virtualhost enabling.

$ sudo a2ensite ourtimoandpumba.org
$ sudo service apache2 restart # a reload as in service apache2 reload should be enough though

Voila! you have a load balancer managing your “cluster” of tomcat instances

14 Comments

  1. Malike

    Great post. Helped me alot.

    Reply
  2. Kenny_D

    Most superb work, kind coding genius!!

    I have been looking for a fairly good comprehensive how to, and after much labor, reading and failed attempts, I was finally able to complete my server setup. Now I have several instances of tomcat7 running on Ubuntu 12.04 LTS, along side several php websites.

    Only 1 minor correction that I would make is that on the 2nd to last line of code in this tutorial you have 01
    $ sudo nano a2ensite ourtimoandpumba.org

    but the “nano” needs to be removed. It only needs to be 01 $ sudo a2ensite ourtimoandpumba.org

    Reply
    1. kodjo-kuma djomeda (Post author)

      Thanks Kenny_D, I have never noticed that mistake, I have now removed the extra nano. Was the tutorial comprehensive enough for you ? I was under the impression this tutorial actually helped but was not too clear, is that so?

      Reply
      1. Kenny_D

        To answer your questions:
        1) “Was the tutorial comprehensive enough for you?” => ABSOLUTELY! You have a couple of other posts, that when combined with this one, makes a very well established Tomcat server with mod_jk.
        2) “this tutorial actually helped but was not too clear, is that so?” No. Your tutorial was incredibly clear. If anyone cannot understand this, then they do not need to be administering a server. For some of us (like myself), it was perfectly clear and helps us out greatly when we do not have a full time network engineer on staff because we are a single person shop and cannot afford that level of service and support at the moment. It is posts like this one that keep us moving forward and trouble free.

        Thanks again. Really good work with what you have posted.

        Reply
        1. kodjo-kuma djomeda (Post author)

          Very encouraging words! Thanks I am glad it helped.

          Reply
  3. Kenny_D

    How would we need to modify the virtual host file and/or our server.xml file if we needed our application to be accessible via the SSL port?

    Reply
    1. kodjo-kuma djomeda (Post author)

      Hello first of all, I let apache2 manage the ssl , as it has better tools to do so as opposed to attempt having it in tomcat, just saying.You actually have the choice of disabling plain http virtualhost all together or do a redirect using mod_rewrite stuff from the http virtualhost to the https virtualhost. That said, You will need to have 2 virtualhosts file one for https and one for http. the http virtual is configured with

      <Virtualhost *:80>
      ServerName timopumbaexample.org
      ServerAlias www.timopumbaexample.org
      RewriteEngine On # assuming a2enmod rewrite was called priorly
      RewriteCond %{HTTPS} off
      RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
      </Virtualhost>
      

      the https virtualhost would be like

      <Virtualhost *:443>
      ServerName timopumbaexample.org
      ServerAlias www.timopumbaexample.org
      
      SSLEngine on
      SSLCertificateFile /etc/apache2/ssl/timopumbaexample.org.crt
      SSLCertificateKeyFile /etc/apache2/ssl/timopumbaexample.org.key
      #if you have the imtermediary file from your ssl provider then you add the line below
      #SSLCertificateChainFile /etc/apache2/ssl/imtermediate.crt
      
      # all the mod_jk configurations from http virtual host should be here
      
      </Virtualhost>
      

      I don’t think you will need to do anything on the server.xml regarding SSL support.
      hope this helps

      Reply
  4. Kenny_D

    Ok. So I have a problem. I followed this and your multi-instance tomcat blog post. I set up four instances for tomcat7 (call them instance1, instance2, instance3 and instance4). Each instance of tomcat7 corresponds to a different web application (call them webapp1, webapp2, webapp3 and webapp4).

    When I first followed this post, I only had setup instance1 and instance2 and webapp1 (for instance1). Everything was working fine with it. However, when I added instance3 and instance4 and webapp2, webapp3 and webapp4, everything stopped working.

    When I start the tomcat instances, those start up without any error. But when I go to http://www.webapp1.com, all I get is an empty page. Same thing with webapp2.com, webapp3.com and webapp4.com.

    I have enabled webapp2, webapp3 and webapp4 with a2enmod (after copying and editing the entry for webapp1 in the /etc/apache2/sites-available directory. So that directory now has five entries
    webapp1.com
    webapp2.com
    webapp3.com
    webapp4.com
    default

    Can you tell me what might be the problem? Thanks.

    Reply
    1. kodjo-kuma djomeda (Post author)

      Hello, I am sorry for that. However I am a little bit confused about the way you are using mod_jk. The post here is about how to make multiple instances of tomcat serve the same application where we use apache mod_jk as a loadbalancer. if that is not the case then this post is not appropriate because as is now, the worker.properties file is configured for load balancing. If you are not doing load balancing I strongly suggest you switch to mod_proxy with mod_ajp which is my preferred way when load balancing is not involved.

      Kindly give me the output of :

      sudo apache2ctl -S

      to check the syntax and to see where every domain map to.

      Reply
  5. Kenny_D

    [email protected]:~# apache2ctl -S
    Warning: DocumentRoot [/var/www/d2solutionsgroup.com] does not exist
    VirtualHost configuration:
    wildcard NameVirtualHosts and _default_ servers:
    *:80 is a NameVirtualHost
    default server localhost (/etc/apache2/sites-enabled/000-default:3)
    port 80 namevhost localhost (/etc/apache2/sites-enabled/000-default:3)
    port 80 namevhost d2.com (/etc/apache2/sites-enabled/000-default:122)
    port 80 namevhost little.com (/etc/apache2/sites-enabled/000-default:241)
    port 80 namevhost never-.com (/etc/apache2/sites-enabled/000-default:295)
    port 80 namevhost extrac.com (/etc/apache2/sites-enabled/extrac.com:2)
    port 80 namevhost ina.com (/etc/apache2/sites-enabled/inm.com:2)
    port 80 namevhost rege.com (/etc/apache2/sites-enabled/rege.com:2)
    port 80 namevhost xro.com (/etc/apache2/sites-enabled/xro.com:2)

    Reply
    1. kodjo-kuma djomeda (Post author)

      I obsfucated some of the urls 😉 we never know.
      I can see clearly d2.com, little.com and never-.com pointing to the default app. are they supposed to do that? if not you probably have the same entry in
      /etc/hosts and /etc/hostname. Are thoses 3 you were concerned about? disable the default virtualhost and use the same apache2ctl command to check whether they are point like xro.com and rege.com etc.

      Reply
    2. kodjo-kuma djomeda (Post author)

      you still haven’t answered how you are using mod_jk. It looks like you are doing a normal reverse proxy with it.

      Reply
  6. Kenny_D

    Ok, maybe I am a bit confused here.

    I thought the purpose of this post and your other post regarding multiple instances of tomcat was so that you could have 1 instance of tomcat serving 1 web application for 1 domain and a 2nd instance of tomcat serving a 2nd web application for a 2nd domain. I did not understand that you have two instances of tomcat serving a web application for 1 single domain.

    So, how I have things setup (or at least wanted to have them setup) was as I described.
    instance of tomcat7_1a serving webapp_1a for domain_1a. Apache2 passing requests for domain_1a using mod_jk worker1.
    instance of tomcat7_2b serving webapp_2b for domain_2b. Apache2 passing requests for domain_2b using mod_jk worker2.
    instance of tomcat7_3c serving webapp_3c for domain_3c. Apache2 passing requests for domain_3c using mod_jk worker3.
    instance of tomcat7_4d serving webapp_4d for domain_4d. Apache2 passing requests for domain_4d using mod_jk worker4.

    Reply
    1. kodjo-kuma djomeda (Post author)

      Hello Sorry to create these doubt on your mind. The main purpose of this post is actually having:

      instance tomcat7_1a and instance tomcat7_2a serving only webapp_1a for domain_1a.

      I just wanted to see how you are using mod_jk and I know see that you are doing normal reverse proxy with it which is FINE.

      The only thing here I can think of is whether all the different tomcat7 instances have different ajp ports number. If They share same ports mod_jk will route the request to them no matter how your VirtualHost setup is. Please make sure you have different ajp port for each instance in each instance’s server.xml and check their mapping in the worker.properties file. Don’t forget to disable default Virtualhost for now. Hope this helps

      Reply

Leave a Comment

Your email address will not be published. Required fields are marked *

captcha * Time limit is exhausted. Please reload the CAPTCHA.

This site uses Akismet to reduce spam. Learn how your comment data is processed.