Deployment Optimizations #

This page contains a number of tips and tricks that enhance security and performance of JSPWiki, and assumes you have already read the first part of the Deployment guide.

Connecting Apache 2 to Tomcat #

Tomcat has a built-in HTTP connector, which by default serves content on port 8080. Many people change this so that it serves on port 80, thereby turning their Tomcat server into a bona fide web server. Personally, I prefer to serve static content from Apache because it:
  • provides an additional layer of security
  • increases performance (Apache is highly optimized for web serving, while Tomcat is not)
    Actually this is no longer true unless you are still running ancient (Tomcat 4 or earlier) versions. Modern Tomcat runs rather speedily as a webserver, in many cases outperforming Apache for static content while avoiding the rather haevy footprint of running both + mod_jk.
To do this, you need to install the Tomcat Connector Project's mod_jk adapter.

Note: there was once a connector called mod_jk2; this was deprecated long ago, and mod_jk is the correct connector to use.

Many good configuration guides exist for mod_jk, notably Mike Millson's guide. I'll be posting my own guide soon.

Once you have build and configured mod_jk, you will want to set up JkMount server directive that sends all Tomcat-related traffic for your Wiki to Tomcat. For example, here is a typical Virtual Server declaration (in /etc/httpd/conf/httpd.conf) that directs JSPWiki traffic to Tomcat:

<VirtualHost *:80> 
  ServerName mywiki.org 
  ServerAlias "www.mywiki.org" 
  DocumentRoot /home/jspwiki/mywiki.org/html 
  <Directory /home/jspwiki/mywiki.org/html> 
    Order deny,allow 
    Allow from All 
    AllowOverride None 
  </Directory> 
  SuexecUserGroup mywiki mywiki 
  CustomLog "/home/jspwiki/mywiki.org/access_log" "combined"  
  ErrorLog "/home/jspwiki/mywiki.org/error_log" 
  UseCanonicalName Off 
  JkMount /jspwiki tomcat 
  JkMount /jspwiki/ tomcat 
  JkMount /jspwiki/* tomcat 
</VirtualHost>

You will also need to create a configuration file to start up the mod_jk connector at Apache startup, and a workers.properties file to tell Apache what port and host to connect to. Here's a sample /etc/httpd/conf.d/tomcat.conf:

LoadModule jk_module extramodules/mod_jk.so 
JkWorkersFile "/etc/httpd/conf/workers.properties" 
JkLogFile "/var/log/httpd/mod_jk.log" 
JkLogLevel error 
JkLogStampFormat "[%a %b %H:%M:%S %Y]"

...and here is /etc/httpd/conf/workers.properties:

worker.list=tomcat 
worker.tomcat.port=8009 
worker.tomcat.host=localhost 
worker.tomcat.type=ajp13 
worker.tomcat.cachesize=10 
worker.tomcat.cache_timeout=600 
worker.tomcat.socket_timeout=300

There are many other features of mod_jk that I have not covered here, for example the software-based load-balancing features. But this example should get you started if all you need is a simple connector.

Serving static content from Apache #

If you are already using mod_jk to split web serving duties away from the servlet container, why not let Apache serve all of the static content too? Indeed, this is a good thing to do, since only servlet- and JSP-related calls pass through to Tomcat. To do this, you need to:
  1. Tweak the Apache JKMount directives
  2. Copy all static content (images, css, html, etc.) to the Apache document directory
For the first task, replace the JKMount directives in httpd.conf with:
JkMount /jspwiki tomcat 
JkMount /jspwiki/ tomcat 
JkMount /jspwiki/*.jsp tomcat 
JkMount /jspwiki/templates/[templatename]/*.jsp tomcat

This tells Apache to pass all JSP calls through to Tomcat, as well as any requests for the web context's root (/jspwiki). Note the addition of the last directive; make sure that templatename matches the name of the template declared in your jspwiki.properties file. Note: I have NOT added JKMount directives for the RPC servlets yet. If anyone has done this yet, feel free to mark this page up!

With respect to the second task, copying static content to Apache, it is best to let Ant do it. To make life easier, I have enclosed a sample Ant task that extracts the static content to a tar file, automagically, from a given WAR file. You can use this script (build-library.xml, attached) with any WAR file, not just JSPWiki. All you need to do is use an antfile task to call an external file, for example:

  <target name="tar-static" depends="war" description="Builds static content tar file for Apache/IIS.">
    <property name="build"          value="${basedir}/build" />
    <property name="tar.static"     value="${build}/${ant.project.name}-static.tar.gz"/>
    <ant antfile="${ant.library}" target="static" inheritAll="false">
      <property name="build"        value="${build}" />
      <property name="srcwar"       value="${basedir}/build/${ant.project.name}.war" />
      <property name="desttar"      value="${tar.static}" />
      <property name="static.user"  value="mywiki" />
      <property name="static.group" value="apache" />
      <property name="static.mode"  value="550" />
    </ant>
  </target>
Note the static.user, static.group and static.mode properties. These are ownership attributes specifying that the files should be owned by user mywiki and by group apache. The mode 550 indicates that the user and group can read or execute these files, but cannot write to them, and that other users cannot even read them. This is a good default setting for Apache.

To make the tar-static task work, you will need to set the ant.library property to reflect the location of build-library.xml. Once you have the tar file generated, all you need to do is move it to your web server, then unpack the contents into the Apache webroot for your wiki. In the example above, the web root is /home/jspwiki/mywiki.org/html; you could unpack it using the command:

sudo tar -p --same-owner -C /home/mywiki/mwiki.org/html/content -xzvf /tmp/JSPWiki-static.tar.gz

Pre-compiling JSPs #

Another tweak that I am rather fond of involves pre-compiling JSPs so that Tomcat doesn't need to do it at runtime. In addition to instant gratification (deploy the WAR and it is ready to go; no need wait for Tomcat to re-compile), it also means that our security worries decrease a bit too. Among other things, because we no longer compile post-deployment, Jasper won't leave JSPC droppings all over the server (specifically, in $CATALINA_HOME/work).

Pre-compiling JSPs requires that you work with a copy of JSPWiki's source tree, rather than with a binary distribution. Assuming you are comfortable working with Ant and so forth, here is what we need to do to precompile JSPWiki's JSPs:

  1. Download a CVS version of Tomcat, to enable client-side pre-compilation (see the note below)
  2. Add a placeholder to JSPWiki's out-of-the-box web.xml file
  3. Create a batch compilation script (see the example below)
  4. Change Tomcat's server.xml file to reflect the new WAR file location
  5. Tweak Tomcat's default servlet configuration $CATALINA_HOME/conf/web.xml to turn off performance-killing Jasper features

Note: as of this writing, Tomcat 5 (and likely Tomcat 4, too) contains a run-time bug that requires that JSPs be pre-compiled with the "tag-pooling" feature turned OFF. Unfortunately, the Ant JSPC task that compiles the JSPs only recently acquired the ability to turn off tag pooling. So you will need to download a CVS version of Tomcat 5 later than April 5, 2004. When Tomcat 5.20 becomes available, this problem should go away.

Download CVS Tomcat#

You should know where to get this. :). Any recent nightly build should work. Note: you do NOT need to deploy this to your server; you only need it for compilation purposes.

Add JSPWiki web.xml placeholder#

In the JSPWiki projecct directory, open etc/web.xml. Add the following text in between the <servlet> and <servlet-mapping> elements:
   <!-- PLACEHOLDER FOR PRE-COMPILED JSP SERVLETS -->
Specifically, the text needs to be in between these items:
   <servlet>
       <servlet-name>AttachmentServlet</servlet-name>
       <servlet-class>com.ecyrd.jspwiki.attachment.AttachmentServlet</servlet-class>
   </servlet>
and
   <!--
       And finally, let us tell the servlet container which
       URLs should correspond to which XML RPC servlet.
     -->
After the JSPC task parses the JSPs and generates Java based on their contents, our handy Ant task (see below) will inject the appropriate mappings back into web.xml.

Create Ant batch compilation script#

JSP compilation is best implemented as a series of Ant tasks. Using the JSPC task, Ant will generate Java source that implements the JSP markup as a series of servlets, then create an XML fragment containing <servlet-mapping> elements that point JSP calls to them. Afterwards, typically one would compile the servlets and bundle them into the WAR file.

To make life easier, I have enclosed a sample Ant task that does all of the above, automagically, from a given WAR file. You can use this script (build-library.xml, attached) with any WAR file, not just JSPWiki. All you need to do is use an antfile task to call an external file, for example:

  <target name="war-tomcat" depends="war" description="Builds the WAR file for Tomcat (with pre-compiled JSPs).">
    <property name="build"      value="${basedir}/build" />
    <property name="war.tomcat" value="${build}/${ant.project.name}-precompiled-jsp.war"/>
    <ant antfile="${ant.library}" target="war-tomcat" inheritAll="false">
      <property name="build"    value="${build}" />
      <property name="srcwar"   value="${basedir}/build/${ant.project.name}.war" />
      <property name="destwar"  value="${war.tomcat}" />
    </ant>
  </target>
You will need to set the ant.library property to reflect the location of build-library.xml. In addition, in the build.properties file that resides in the same directory as build-library.xml, you should specify the installation location of Tomcat 5 by storing its path in the property tomcat.home.

Tweaking Tomcat's server.xml to reflect the new WAR location#

In $CATALINA_HOME/conf/server.xml, the appropriate <Context> element should be modified to reflect the new WAR file, e.g.,:
<Context path="/mywiki" docBase="/home/tomcat/JSPWiki-precompiled-jsp.war"/>

Tweaking $CATALINA_HOME/conf/web.xml#

(Coming soon...)

Running Tomcat & JSPWiki with a Security Manager #

Deployment tools #

Production deployment of JSPWiki should generally be done on a server whose configuration can be tightly controlled. By "tightly controlled," we mean a process that enables you to quickly and reliably deploy software without error, and in a manner that doesn't depend on a lot of (or any) post-install futzing. This section describes some techniques you can use to make deployments painless and reliable.

SSH Agent #

If you frequently deploy versions of JSPWiki to secure staging and/or production servers, you probably recognize two things:
  • FTP is a bad idea, since the protocol is in clear text
  • But as bad as that is, the alternative (SSH) requires you to type your passwords in all the time, which is a pain
Fortunately, there is a good way to ensure high security and convenience. If you use SSH in combination with public-key authentication and a client-side SSH "agent," uploading files can be both bulletproof (highly secure!) and automatic (no passwords!).

SSH agents work by caching private keys in memory, supplying them to hosts you connect to. The nice part about using an SSH agent is that it works for all processes that use SSH in the current terminal session. (On Mac OS X, the "make global" option of SSH Agent means that it will apply to all sessions, not just the current one).

The directions below describe how to use SSH Agent for Mac OS X, using an example user samiam.

SSH Agent (Mac OS X)#

SSH Agent is a Mac OS X application that automates the processes of generating, storing, and caching public keys. It is designed to integrate with the Apple Keychain. To set up public key access to your server:
  • Run SSH Agent
  • Create a new Identity (RSA 2048 bit key is recommended). Save the key to a file (e.g., samiam_identity in a secure location on your hard drive
  • Verify that your server's sshd daemon permits public-key authentication. Verify these lines in /etc/ssh/sshd_config (or wherever your SSH daemon's configuration file lives):
    Protocol 2 RSAAuthentication yes PubkeyAuthentication yes AuthorizedKeys .ssh/authorized_keys
  • Copy the new public key up to the server:
    scp samiam_identity.pub samiam@www.myserver.org:/samiam/.ssh/authorized_keys
  • Verify correct configuration by using an SSH Agent to cache the local private key, then try to log in:
    ssh samiam@www.myserver.orgIf all goes well, you should see a command prompt.

Ant scripts#

Could you post your ant scripts? In particular, the script that does the jspc pre-compilation? --John N.

Apache 2.2 and Tomcat#

An update on Apache: v2.2 no longer really likes to talk with mod_jk very well (I've heard it's possible, but I've never actually gotten it to work), and mod_jk is being replaced by mod_proxy_ajp, which is bundled with Apache by default. -Blaine Willhoft


-- Regarding section "Serving static content from Apache", I think you can also use a symbolic link under the Apache directory that points to the web application. This would be an alternative to copying all of the static content. This would only work on platforms that actually support symbolic links (not Windows).

--AnonymousCoward, 02-May-2007

Add new attachment

Only authorized users are allowed to upload new attachments.
« This page (revision-9) was last changed on 31-Aug-2010 17:40 by 41.185.85.157