INSTALLING MOD_JK ON APACHE HTTPD IN CENTOS 6.X/7.X: CentOS again. Today I’m going to show you how to install and configure mod_jk in apache httpd using a server with CentOS. Currently this tutorial was tested on Centos 6.x and 7.x so you should run out of troubles if you stick with one of those versions.
INTRODUCTION
So, what’s mod_jk? mod_jk is an apache httpd module used to make apache tomcat applications interact with a httpd server. In simple words, mod_jk allows us to connect an instance of tomcat with the apache httpd web server. This is useful for example if you have your httpd serving different kind of webapps (php, RoR, etc) and you want to publish a java app running on a tomcat instance. In this case, httpd run in port 80 and tomcat (usually) in port 8080, so we need to connect somehow the tomcat instance with httpd so our users can interact with our java app directly from port 80. In this case, the httpd server is giving us access to for example an internal network where your tomcat instances live. See the next diagram for a visual explanation:
WHY NOT USE MOD_PROXY?
This is indeed a good question. From a stackoverflow question/answer:
mod_proxy:
- Pros:
- No need for a separate module compilation and maintenance. mod_proxy, mod_proxy_http, mod_proxy_ajp and mod_proxy_balancer comes as part of standar Apache 2.2+ distribution.
- Ability to use http/https or AJP protocols, even with the same balancer.
- Cons:
- mod_proxy_ajp does not support larke 8k+ packet sizes.
- Basic load balancer.
- Does not support Domain model clustering.
mod_jk:
- Pros:
- Advanced load balancer.
- Advanced node failure detection.
- Support for large AJP packet sizes.
- Cons:
- Need to build and mantain a separate module.
So, the discussion is there, no final answer. A good article covering this topic is: “Deciding between mod_jk, mod_proxy_http and mod_proxy_ajp” from Tomcat Experts.
INSTALLATION
The installation process for mod_jk is really simple but we’re going to need to compile the module first. Before doing any compile work, ensure you have both httpd and tomcat installed. Now:
1 |
yum install httpd-devel apr apr-devel apr-util apr-util-devel gcc gcc-c++ make autoconf libtool |
Now, go to the official mod_jk website and download the latest version: http://tomcat.apache.org/download-connectors.cgi (1.2.41 at the published date of the post):
1 2 3 4 5 |
mkdir -p /opt/mod_jk/ cd /opt/mod_jk wget http://www.eu.apache.org/dist/tomcat/tomcat-connectors/jk/tomcat-connectors-1.2.41-src.tar.gz tar -xvzf tomcat-connectors-1.2.41-src.tar.gz cd tomcat-connectors-1.2.41-src/native |
In the native folder (check the last step in the code above) we’re going to configure-make-make install the connector:
1 2 3 4 |
./configure --with-apxs=/usr/sbin/apxs make libtool --finish /usr/lib64/httpd/modules make install |
UPDATE (May 16, 2016): The user Matthew Herzog in the comments pointed me that apxs has moved to /usr/bin/apxs as opposed to /usr/sbin/apxs. In my system I still have apxs on /usr/sbin but if you run into troubles doing the previous steps maybe this can help.
2nd UPDATE (May 16, 2016): The user Akash Hikadi reported on the comments that to make the previous command to work he had to add the flag enable-api-compatibility. If you get the next error when doing the previous steps “No targets specified and no makefile found” or “No rule to make target install” try running:
1 2 3 4 |
./configure --with-apxs=/usr/sbin/apxs --enable-api-compatibility make libtool --finish /usr/lib64/httpd/modules make install |
If all goes well you’re going to have the mod_jk.so installed on your /etc/httpd/modules folder.
CONFIGURATION
First, lets enable the AJP connection on your tomcat server, in your server.xml configuration file:
1 |
vim $TOMCAT_HOME/conf/server.xml |
Add under the <Service name=”Catalina”> tag:
1 2 |
<!-- Define an AJP 1.3 Connector on port 8009 --> <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> |
And modify the Engine tag so its looks like:
1 |
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1"> |
Observation 1: for each tomcat instance linked to your httpd server, you need to define a different jvmRoute parameter. For example, for a second instance you could use:
1 |
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm2"> |
Now, lets go with the httpd configuration. First, create a mod_jk.conf file in your conf.d folder:
1 |
vim /etc/httpd/conf.d/mod_jk.conf |
And populate the file with the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
LoadModule jk_module "/etc/httpd/modules/mod_jk.so" JkWorkersFile /etc/httpd/conf/workers.properties # Where to put jk shared memory JkShmFile /var/run/httpd/mod_jk.shm # Where to put jk logs JkLogFile /var/log/httpd/mod_jk.log # Set the jk log level [debug/error/info] JkLogLevel info # Select the timestamp log format JkLogStampFormat "[%a %b %d %H:%M:%S %Y] " #JkRequestLogFormat "%w %V %T" #JkEnvVar SSL_CLIENT_V_START worker1 |
Before continuing, create the folder to store the shared memory of the module:
1 2 |
mkdir -p /var/run/mod_jk chown apache:apache /var/run/mod_jk |
Now, create the workers.properties file: (look at the JkWorkersFile property on mod_jk.conf file):
1 |
vim /etc/httpd/conf/workers.properties |
With the next content:
1 2 3 4 5 6 7 |
workers.apache_log=/var/log/httpd worker.list=app1Worker worker.stat1.type=status worker.app1Worker.type=ajp13 worker.app1Worker.host=app1.myhost.com #put your app host here worker.app1Worker.port=8009 |
For every app server from tomcat to httpd you’re going to have a specific worker. Don’t forget to define the worker first in the worker.list property. For example, lets assume we’re going to add another app from tomcat:
1 2 3 4 5 6 7 8 9 10 11 |
workers.apache_log=/var/log/httpd worker.list=app1Worker,app2Worker worker.stat1.type=status worker.app1Worker.type=ajp13 worker.app1Worker.host=app1.myhost.com #put your app host here worker.app1Worker.port=8009 worker.app2Worker.type=ajp13 worker.app2Worker.host=app2.myhost.com #put your app host here worker.app2Worker.port=8009 |
Well, everything looks good now. The final step is to configure the VirtualHost for every app on httpd:
1 |
vim /etc/httpd/conf.d/app1.conf |
It’s a good practice to maintain your VirtualHosts in separated files. Now, in your recently created app1.conf file:
1 2 3 4 5 6 7 8 9 10 |
<VirtualHost *:80> ServerName app1.myhost.com ServerAdmin admin@myhost.com LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" combined CustomLog /var/log/httpd/app1_access.log combined ErrorLog /var/log/httpd/app1_error.log <IfModule mod_jk.c> JkMount /* app1Worker </IfModule> </VirtualHost> |
We are connecting httpd with tomcat using the JkMount directive in the VirtualHost configuration. If for example you’are adding a VirtualHost for your second app use the app2Worker configured previously and so on for other apps.
FINAL STEPS AND CONCLUSION
If you followed all the previous steps, you should be able to interact with your tomcat app directly from http://app1.myhost.com which is handled by httpd. Beautiful!
In this tutorial, we learned how to use mod_jk to connect different tomcat instances with the httpd web server. The procedure is straighforward but involves some compile tasks and a few configurations on each server. If you have any dobts don’t hesitate to initiate a converstion in the comments sections.