mod_cfml Tomcat Valve

Configuration Options

The default Tomcat Valve config line would look something like this in the Tomcat server.xml file:

<Valve
    className="mod_cfml.core"
    loggingEnabled="false"
    maxContexts="200"
    timeBetweenContexts="2000"
    scanClassPaths="false"
    responseCode="307"
    sharedKey="secret key also set in the Apache/IIS config" />
classname="mod_cfml.core"

Required. Unchangable.

Tells Tomcat to run the mod_cfml.core class when this valve is invoked.

loggingenabled="[true|false]"

Optional
Default: false

This option enables logging within the mod_cfml valve. This is useful for determining if request header data is being passed to the Tomcat valve correctly, or if there are problems, it is useful for determining what those problems could be.

Logs are usually set to the "catalina.out" log on Linux systems, and for Windows Lucee/Railo installs to the "lucee-stdout" / "railo-stdout" log file.

maxContexts="200"

Optional
Values: Integer
Default: 200

The maxContexts value states how many web contexts may be created in Tomcat. Host aliases do not add up to this number, so an Apache VirtualHost with "Alias *.mydomain.com" will count as only 1 context in Tomcat.

The value should be a little bit higher then the total amount of configured websites in your frontend webserver.

If the maxContexts limit is reached, an error will be written to the Tomcat log files stating: "[mod_cfml] MaxContexts limit reached. No more contexts can be created!", and a 503 (Service Unavailable) error will be returned for any new contexts, along with the error message on-screen.

timeBetweenContexts="2000"

Optional
Values: Integer
Default: 2000 (2 seconds)

This value (stated in milliseconds) governs the context throttler, and sets the minimum time between the start of each context creation. Like the maxContexts value, this setting is specifically to help discourage certain kinds of Denial of Service attacks. The default setting of 2000 means "a maximum of 1 new website per 2 seconds may be added to Tomcat". In case of a server restart, the default setting may be uncomfortable for you if you have multiple high-traffic sites. In that case, you could change the setting to 0 (zero), which will prevent any errors going to end-users.

If you hit the limit enforced by the "timeBetweenContexts" value, an error will be written to the tomcat logs and a 503 (Service Unavailable) will be returned to the user. The error is specifically: "[mod_cfml] Time Between Contexts has not been fulfilled. Please wait a few moments and try again."

scanClassPaths="true|false"

Optional
Values: true or false
Default: false

This setting enables/disables the Tomcat Jar Scanner on each web context creation. This scan is the reason why web context creation in Tomcat seemed so slow, it takes multiple seconds to complete. For CFML engines, it is usually unnecessary to use it, and makes the web context loading 5 to 10 times faster.

If you are using Java/JSP pages in mod_cfml web contexts, or notice errors with jars which can not be found, then try setting this to True. If you are using Lucee or Railo, you might also be able to fix those errors by moving the missing jars to {web-context}/WEB-INF/lucee/lib/

responseCode="[301-308]"

Optional
Values: Integer
Default: 302

This setting tells mod_cfml what redirect response code to send to the browser after the context has been created so that the browser will issue the request again. Added in version 1.1.11.

Supports redirect response code values between 301 and 308. Valve will default to 302 response code if no value is provided. 307 response code should be used if your application requires HTTP POST data (such as API requests or other form data) to be preserved.

Here is a list of officially supported apache response codes.

sharedKey="secret key also set in the Apache/IIS config"

Required
Values: Alphanumeric
Default: null

To be sure any context-creating requests come from our frontend webserver, you can set up a shared secret key. We strongly advise you to implement this security measure, as context creation means exposing internal resources to the outside world.

It works really simple: when the valve is invoked, and the necessary X-Tomcat-DocRoot header is given, then we check if a sharedKey is set for the valve. If it is, then we check to see if it matches the value of the incoming request header X-ModCFML-SharedKey. If it does not match, or the incoming header does not exist, an error message "mod_cfml request authentication failed!" is logged, and a 503 error is returned, with the error-message on-screen.

While implementing this, you should first configure and restart your frontend webserver (Apache or IIS). After that, configure the Tomcat valve.


Frequently Asked Questions

What is the mod_cfml Tomcat valve?

The mod_cfml Tomcat Valve is the part of the mod_cfml suite of software that dynamically creates hosts in Tomcat based on the request headers of the incoming request.

Does the mod_cfml Tomcat Valve check EVERY incoming request?

No. The suggested installation of the Valve is to install it in the default host of the Tomcat instance it's running in. Therefore, it only checks requests that get sent to the default host: hosts that don't exist yet and Tomcat doesn't know where else to send them.

How does the mod_cfml Tomcat Valve know when to add new hosts / aliases?

Incoming requests that are sent to Tomcat should contain at least one additional HTTP request header, the "X-Tomcat-DocRoot" header. This will be placed there by one of the mod_cfml web server components, either mod_cfml.so or the BonCode Connector).

Incoming requests that Tomcat doesn't know how to resolve get sent to the default host. In a default Tomcat installation, the default host is "localhost", so if Tomcat gets a request for www.yoursite.com, and doesn't know how to resolve that request, it will send it to "localhost". The mod_cfml Tomcat Valve takes advantage of this feature and uses it to catch any host that Tomcat doesn't know how to resolve.

The "magic" of the mod_cfml Tomcat Valve happens when Tomcat gets a request for www.yoursite.com, but that request gets sent to the default host because Tomcat doesn't know how to resolve it. Mod_cfml will see this "unknown host", and create a new host for it in Tomcat's memory while it's running.

If the request header "X-Webserver-Context" is also available, then the Tomcat valve will instead create a host with the header's value as a name (if it doesn't exist yet), and then add the current host as a host alias. This way, you can have one webserver context ("website"), with multiple hostnames, all running in the same Tomcat host context.

The Tomcat valve does this work by calling on the same libraries that the Tomcat "Host Manager" uses. So, realistically, mod_cfml uses pre-existing methods to make dynamically creating hosts in Tomcat very very easy.

Will there be a performance hit if I use the mod_cfml Tomcat Valve?

Yes, but ONLY on the first request for a new domain. The process of creating a new host entry in a running instance of Tomcat is somewhat complex, and requires many files to be written to the HDD to be read by Tomcat when the host is initialized. This process can take some time, depending on the speed of your drives and how busy they are. The average wait period for a new host context to be created is heavily dependent on the new setting "enableScanClassPaths". With enableScanClassPaths=false, the wait period is below 1 second; with enableScanClassPaths=true, it becomes around 3 to 5 seconds.

The wait time for a new host alias to be created is about 100 to 300 milliseconds.

If the request times out before the new host is created the request is passed to the default host and the default host site is displayed. HOWEVER, know that the host creation process threads are not killed even when the request times out. Instead, they continue and the host is eventually created. This means you can hit the "Refresh" button on your browser again and you will probably get your actual site rather then the default host. If this happens, you may increase the timeout limit for the initial request and mod_cfml will wait longer before timing out the request.

IMPORTANT: After the host/alias is created, mod_cfml is no longer involved, so there is no performance loss after the first hit.

How can I remove or "re-install" a host that has been created wrong?

Accidents happen. Usually this just means that the host wasn't configured in the web server correctly before the config was copied to Tomcat. To clear out a host created in Tomcat with mod_cfml, go to the Tomcat Host Manager and remove the host. Mod_cfml will then create a new host entry whenever another request for that domain comes in.

Alternatively, you can restart Tomcat to clear out all dynamically created hosts.

How can I upgrade mod_cfml whenever there is an update?

To update the mod_cfml Tomcat Valve, just stop Tomcat for a moment, remove the mod_cfml valve JAR file from the {tomcat}/lib/ directory, and drop the latest version of the mod_cfml Tomcat Valve jar file into the Tomcat lib folder again. Restart Tomcat, and you're all set.