ColdFusion Developer Week 2012

Adobe's second ColdFusion Developer Week kicks off today, June 4, and continues through Friday, June 8, 2012. Whether you're a new or experienced CFML developer, there's probably more than one session you'll find very interesting and useful. From basics to advanced language features, as well as frameworks and a focus on the new ColdFusion 10 release, there's just loads of good stuff, all provided via free online Webinars.

Check out the sessions and schedule, and sign up.

Like last year, I'll be presenting Improve Your Apps Through Unit Testing, tomorrow.

I also hope to revive this sleepy blog with some more interesting tid-bits soon, so stay tuned! It's been a busy year, but I've queued a number of topics for blog posts, so hopefully I can catch up a little in the near future.

CFML on Tomcat via Apache AJP Proxy, Redux

I often use Tomcat as my servlet container to power my CFML apps (works great for ColdFusion, Open BlueDragon and Railo!). I've been perfectly happy with the power and flexibility of using Apache HTTPD's mod_rewrite with an AJP proxy, as Sean Corfield has detailed. Then, after repeating a lot of rewrite rules in all of my virtual host definitions, I decided to merely place the following in my main Apache configuration file:

<Proxy *>
Allow from 127.0.0.1
</Proxy>
ProxyPreserveHost On
ProxyPassMatch ^/(.+\.cf[cm])(/.*)?$ ajp://localhost:8009/$1$2

That's it! Now, any Apache virtual hosts for CFML application can be defined as simple as this:

<VirtualHost *:80>
ServerName myrockinapp
DocumentRoot /var/www/myrockinapp
DirectoryIndex index.cfm
</VirtualHost>

I can still easily add URL rewriting to my Apache virtual hosts. For example, when using Mura CMS I often set the properties siteIdInURLs=0 and indexFileInURLs=0 to make super clean looking URLs (with no siteID or index.cfm in the URLs). This then of course requires a rewrite rule to ensure the proper requests are passed to Tomcat, which is as simple as adding these lines to your virtual host (or an .htaccess file in your Web root):

RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d
RewriteRule ^([a-zA-Z0-9/-]+)$ /index.cfm%{REQUEST_URI} [PT]

Makes all the configuration I used in this post look a bit silly now :P

Also, if you're interested in a clean, production-worthy server setup running on Ubuntu 10.04 with Railo, Tomcat, Apache and MySQL, I have this fairly well documented in this Google Doc.

Apache Authentication with Proxy

I've enjoyed leveraging Apache mod_rewrite and mod_proxy to leverage both the power of URL rewriting and the APJ proxy to proxy CFML requests to Railo running on Tomcat. I allow Apache to still handle requests for static assets (images, javascript, etc.). Today, I ran into a problem when I wanted to slap some basic authentication on a site. Requests handled entirely by Apache (static assets) were challenged for authentication, but CFML requests were proxied to Tomcat without requiring authentication. It makes perfect sense, as did the solution once I found it, but it just didn't occur to me at first.

First, here's a quick example of a basic virtual host that I'd use:

<VirtualHost *:80>
    ServerName mysite
    DocumentRoot /var/www/mysite/webroot/
    DirectoryIndex index.cfm

    <Proxy *>
        Allow from 127.0.0.1
    </Proxy>

    ProxyPreserveHost On
    ProxyPassReverse / ajp://mysite:8009/

    RewriteEngine On

    RewriteRule ^(.+\.cf[cm])(/.*)?$ ajp://%{HTTP_HOST}:8009$1$2 [P]
</VirtualHost>

After creating a password file using the htpasswd command, I thought I'd simply add the following inside my VirtualHost to provide basic authentication.

<Directory /var/www/mysite/webroot/>
    AuthType Basic
    AuthName "Restricted Files"
    AuthUserFile /usr/local/etc/apache/mysite.passwd
    Require user someusername
</Directory>

Unfortunately, as I mentioned, this only protected non-proxied requests. Fortunately, I found the tip for my solution relatively quickly at stackoverflow, here. I simply needed to apply the same authentication directives within the Proxy context.

Here's the revised virtual host with basic authentication for both static assets and those proxied to Tomcat:

<VirtualHost *:80>
    ServerName mysite
    DocumentRoot /var/www/mysite/webroot/
    DirectoryIndex index.cfm

    <Directory /var/www/mysite/webroot/>
        AuthType Basic
        AuthName "Restricted Files"
        AuthUserFile /usr/local/etc/apache/mysite.passwd
        Require user someusername
    </Directory>

    <Proxy *>
        Allow from 127.0.0.1
        AuthType Basic
        AuthName "Restricted Files"
        AuthUserFile /usr/local/etc/apache/mysite.passwd
        Require user someusername
    </Proxy>

    ProxyPreserveHost On
    ProxyPassReverse / ajp://mysite:8009/

    RewriteEngine On

    RewriteRule ^(.+\.cf[cm])(/.*)?$ ajp://%{HTTP_HOST}:8009$1$2 [P]
</VirtualHost>

URL Rewrite Goodies for Apache, Tomcat, Railo and Mura CMS

UPDATE, 8/31/2010: I'm going with a simplified approach these days, as posted here.

I've worked with Apache mod_rewrite quite a bit in the past, but never got into any terribly complex rewrite rules. On average, I've probably leveraged about 2% of the incredible potential power that mod_rewrite offers. More recently I finally had the opportunity to learn a bit more and leverage this handy tool. My rewrite rules evolved over the past couple months as I got into testing out the Railo CFML engine a bit more, and then while setting up my first Mura CMS powered site. I thought I'd share what I've learned, as others may be likely to use some or all of this type of Apache virtual host configuration.

Here's a run-down of the "end goal," if you will, which I will walk through step by step to recap the problems and solutions I discovered along the way:

  • Apache will proxy CFML requests to Tomcat servlet engine, for Railo to handle (while Apache handles all other static content, PHP, etc.)
  • Tomcat will properly have Railo handle this common SES style URL (leveraging cgi.path_info): http://host/index.cfm/path-info/
  • Protect Railo Admin URLs from public access (well, actually hide them to mitigate hacking attempts)
  • Run a Mura CMS site with super SEO friendly URLs (e.g., http://host/a-cms-page/ instead of the default http://host/siteid/index.cfm/a-cms-page/), while still allowing for standard CFML requests (for custom app integration under same host as CMS)

Please note that the following Apache modules must be activated in your Apache configuration: mod_rewrite, mod_proxy and mod_proxy_ajp.

Apache Proxy CFML Request to Tomcat/Railo

I'll simply direct you to existing resources for this first bit and then show my basic example virtual hosting configuration. First, I'm running Railo in a multi-web setup on a single instance of Tomcat, which Sean Corfield has nicely outlined here (including a kind nod to a prior blog post of mine :). I learned a very nice means of proxying CFML requests from Apache to Tomcat thanks to this Sean Corfield post, which was prompted by some helpful comments from Barney Boisvert on Sean's prior post.

So here is an example Apache virtual host:

<VirtualHost *:80>
    ServerName railocmstest
    DocumentRoot /var/www/railocmstest/webroot
    DirectoryIndex index.cfm

    <Proxy *>
        Allow from 127.0.0.1
    </Proxy>

    ProxyPreserveHost On
    ProxyPassReverse / ajp://railocmstest:8009/

    RewriteEngine On

    # If it's a CFML (*.cfc or *.cfm) request, just proxy it to Tomcat:
    RewriteRule ^(.+\.cf[cm])$ ajp://%{HTTP_HOST}:8009$1 [P]
</VirtualHost>

SES URLs with path_info

Okay, the above gets Apache proxying standard *.cfm/*.cfc requests to Tomcat for Railo to handle, but a request to http://railocmstest/index.cfm/some-path-info/ will simply throw a 404 error, because Apache finds neither file nor directory at /var/www/railocmstest/webroot/index.cfm/some-path-info/. Plus, the current rewrite rule is not even proxying this type of request to Tomcat, because the regular expression used only looks for any URI that ends with ".cfc" or ".cfm".

Simply change this line:

RewriteRule ^(.+\.cf[cm])$ ajp://%{HTTP_HOST}:8009$1 [P]

...to this:

RewriteRule ^(.+\.cf[cm])(/.*)?$ ajp://%{HTTP_HOST}:8009$1$2 [P]

Okay, now if we reload Apache the http://railocmstest/index.cfm/some-path-info/ will indeed be proxied to Tomcat, however, now we just get the 404 error from Tomcat instead of Apache! Not a problem -- I picked up another trick from a comment by Tony Garcia on, again, this Sean Corfield post. In either our Tomcat's conf/server.xml file or in our Web root's WEB-INF/web.xml (you can create one if it doesn't exist) file, add the following servlet mapping:

CFMLServlet /index.cfm/*

Just be sure the servlet name you use here matches the one used for Railo, which is CFMLServlet by default, but I change mine to GlobalCFMLServlet in my multi-web setup as explained here.

We can now restart our Tomcat service and http://railocmstest/index.cfm/some-path-info/ is now good to go -- no more 404 error and cgi.path_info will now properly return /some-path-info/.

You may be inclined to try a URL pattern of /*.cfm/* in your servlet mapping, as I was, but it will not work as expected. If you also need URLs ending with /other.cfm/path-info/ and /app/index.cfm/path-info/, for example, you'll have to add two more servlet mappings with URL patterns /other.cfm/* and /app/index.cfm/*.

Hide Railo Admin URLs

A simple way to hide your Railo Admin URLs is to use one rewrite rule to forbid access to any paths beginning with /railo-context/admin/ and use some unusual URL to proxy in its place:

RewriteRule ^/railo-context/admin/(.*) - [F]

RewriteRule ^/SOMETHING-DIFFICULT-TO-GUESS/admin/(.*\.cf[cm])$ ajp://%{HTTP_HOST}:8009/railo-context/admin/$1 [P]

After an Apache reload, the above rewrite rules will cause a 403 (Forbidden) error to be thrown at http://railocmstest/railo-context/admin/index.cfm, but you can find what you're looking for at http://railocmstest/SOMETHING-DIFFICULT-TO-GUESS/admin/index.cfm with no problem. In this Railo Google Groop thread Sean Corfield also suggests using a separate virtual host to access your admin, which can listen on an unusual port. You could also use SSL to encrypt transmissions at the admin URLs.

Super SES CMS URLs

"Out of the box," Mura CMS has relatively friendly, SES URLs of the form http://host/siteid/index.cfm/something-friendly/, but we can do better. In the helpful Mura forums I quickly found the information I needed to make very quick changes to the Mura code to get rid of the /siteid/index.cfm portion of the URLs generated. Since there were two steps, in two different threads, plus one other tweak I found necessary, I posted a summary thread to a Mura forum. The rewrite rule example I provide in the form thread is more generic, intended to work without consideration for Tomcat proxying, Railo Admin hiding, etc., so here's what I've actually done for my first Mura CMS powered site...

I found that I needed to cover a few extra use cases. These four situations must be covered:

  1. If there's a trailing slash and it resolves to an existing physical directory, then we'll assume there should be an index.cfm in there and proxy to Tomcat.
  2. If it's an existing file, just let Apache serve it -- this takes care of all static and non-CFML requests.
  3. If rewrite rules are still processing, then we must be looking for a Mura CMS powered URL, which must have a trailing slash, so we'll permanently redirect with an appended trailing slash if it's missing.
  4. Finally, if rewrite rules are still processing, then we'll just prepend "index.cfm" in front of the REQUEST_URI.

...and here it is:

# If trailing slash and real directory, then append index.cfm and proxy it to Tomcat/Railo:
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^(.+/)$ ajp://%{HTTP_HOST}:8009%{REQUEST_URI}index.cfm [P]

# If it's a real file (and we haven't proxied to Tomcat, so it must be static), just serve it:
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f
RewriteRule . - [L]

# Require trailing slash at this point:
RewriteRule ^(.+[^/])$ $1/ [R=301,L]

# Everything else must be a CMS URL path, which is rewritten and proxied to Tomcat/Railo:
# MUST COME AFTER ANY OTHER FIXED/EXPECTED REWRITES!
RewriteRule . ajp://%{HTTP_HOST}:8009/index.cfm%{REQUEST_URI} [NE,P]

If you're wondering why I have rewrite conditions with %{DOCUMENT_ROOT}%{REQUEST_URI} instead of %{REQUEST_FILENAME} when checking for file/directory existence, it's because the latter just didn't work for me! All examples I've seen suggest the latter, but it just didn't work -- possibly something Ubuntu-specific, or something that I changed elsewhere in my Apache configuration? I don't know, but what I've used should work on any setup.

UPDATE (2009-06-04)

I've discovered a little bug in Mura CMS regarding the handling of would-be 404 pages, so the last two rewrite rules from above must be changed to be less broad and an additional final rule can be added to still leverage the friendly/skinned Mura 404 page (rather than Apache's default 404):

# Require trailing slash at this point, if otherwise valid CMS URL:
RewriteRule ^([a-zA-Z0-9/-]+[^/])$ $1/ [R=301,L]

# Valid CMS URL path is proxied to Tomcat/Railo:
# MUST COME AFTER ANY OTHER FIXED/EXPECTED REWRITES!
RewriteRule ^([a-zA-Z0-9/-]+)$ ajp://%{HTTP_HOST}:8009/index.cfm%{REQUEST_URI} [NE,P]

# Anything else must be a 404 error:
RewriteRule . ajp://%{HTTP_HOST}:8009/index.cfm/this-will-force-a-404/ [NE,P]

I've also updated the following Complete Package section to reflect these updates...

The Complete Package

So, here is the complete virtual host example, incorporating all of the above:

<VirtualHost *:80>
    ServerName railocmstest
    DocumentRoot /var/www/railocmstest/webroot
    DirectoryIndex index.cfm

    <Proxy *>
        Allow from 127.0.0.1
    </Proxy>

    ProxyPreserveHost On
    ProxyPassReverse / ajp://railocmstest:8009/

    RewriteEngine On

    # Forbid access to Railo Admin URLs:
    RewriteRule ^/railo-context/admin/(.*) - [F]

    # Proxy "secret" Railo Admin URLs to "real" Railo Admin URLs on Tomcat:
    RewriteRule ^/SOMETHING-DIFFICULT-TO-GUESS/admin/(.*\.cf[cm])$ ajp://%{HTTP_HOST}:8009/railo-context/admin/$1 [P]

    # If it's a CFML (*.cfc or *.cfm) request, just proxy it to Tomcat:
    RewriteRule ^(.+\.cf[cm])(/.*)?$ ajp://%{HTTP_HOST}:8009$1$2 [P]

    # If trailing slash and real directory, then append index.cfm and proxy it to Tomcat/Railo:
    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
    RewriteRule ^(.+/)$ ajp://%{HTTP_HOST}:8009%{REQUEST_URI}index.cfm [P]

    # If it's a real file (and we haven't proxied to Tomcat, so it must be static), just serve it:
    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f
    RewriteRule . - [L]

    # NOTE: Everything else must be a CMS URL path (letters/numbers/hyphens/slashes only), or a 404...

    # Require trailing slash at this point, if otherwise valid CMS URL:
    RewriteRule ^([a-zA-Z0-9/-]+[^/])$ $1/ [R=301,L]

    # Valid CMS URL path is proxied to Tomcat/Railo:
    # MUST COME AFTER ANY OTHER FIXED/EXPECTED REWRITES!
    RewriteRule ^([a-zA-Z0-9/-]+)$ ajp://%{HTTP_HOST}:8009/index.cfm%{REQUEST_URI} [NE,P]

    # Anything else must be a 404 error:
    RewriteRule . ajp://%{HTTP_HOST}:8009/index.cfm/this-will-force-a-404/ [NE,P]
</VirtualHost>

Cheers!

Railo JARs on JBoss (or Tomcat) - Tips and Tricks

As a follow up to a previous related post, I wanted to share a couple potentially helpful tricks that I've since learned. Everything I document here has been tested with both Railo 3.0.2.004 (current stable) and Railo 3.1.0.012 (current beta), both of which can be downloaded from here, on JBoss Application Server (AS) 4.2.3.GA.

The purpose (as I see it) of a Railo JARs installation is to provide an alternative to using a full-blown Railo WAR for each of your Railo CFML applications. This allows you to define your Railo CFML servlet "globally" in JBoss/Tomcat and then use virtual hosts for multiple CFML apps. Each CFML app is then leveraging the same Railo instance, one copy of the jars and one Railo server admin (but still multiple Web contexts with unique Railo Web Admin for each Web site/context).

Also keep in mind that JBoss AS leverages Tomcat as its Web server, so just about everything here should directly translate. Here are the locations of key configuration files and directories in both JBoss 4.2 and Apache Tomcat 6:

{JBOSS_HOME}/lib/ {JBOSS_HOME}/server/default/lib/
or
{TOMCAT_HOME}/lib/

{JBOSS_HOME}/server/default/deploy/jboss-web.deployer/conf/web.xml
or
{TOMCAT_HOME}/conf/web.xml

{JBOSS_HOME}/server/default/deploy/jboss-web.deployer/server.xml
or
{TOMCAT_HOME}/conf/server.xml

Quick Review of Railo JARs Install on JBoss/Tomcat

I will first give a very brief outline of the steps required to install Railo (jars) on JBoss/Tomcat here. There are, however, some potential problems with this configuration, which I'll outline below, with a solution/workaround for each.

[More]

Railo 3.0 on JBoss AS 4.2 via Apache 2.2 with Root Context and No Proxy

So I wanted to take a good look at the Railo 3.0 CFML engine and see what all the buzz was about. I wanted to be sure I could replicate the same basic Apache virtual host configurations I've been using with my ColdFusion 8 multi-server configuration. I also decided to try to get this all working with the JBoss Application Server. This entry summarizes the battle that was eventually won...

Choosing An Application Server

After a great deal of reading comparisons and opinions regarding Resin, Tomcat and JBoss Application Server (also with/without Apache), I decided I wanted to shoot for running the Railo CFML engine on the JBoss Application Server. There was plenty of good press and lots of die hard proponents for each of these application server options, so I don't feel there's a wrong decision and recommend you decide for yourself. For me, I just liked the robustness of JBoss and the full-featured community edition (Resin, for example, only provides a lot of its full-featured options in the paid licenses).

Basic Railo Installation/Deployment (EAR/WAR)

I'll leave out a lot of the lower level details of my installations, because there are plenty of Railo installation guides out there already (and probably growing). I must, however, mention that a lot of Gary Gilbert's Railo posts were particularly useful in my learning experience.

Using the aforementioned guides I was able to get JBoss AS installed and then deployed Railo 3.0 as a WAR and then also tried the EAR deployment alternative. I was not able to deploy Railo 3.0.2.001 on JBoss AS 5.0.1.GA, but all deployments worked fine for me on JBoss AS 4.2.3.GA. I've noticed other folks comment on being able to deploy Railo on JBoss 5 on Ubuntu 8.04, which is my development OS, but I was not successful. The errors I received appeared to be known JBoss 5 bugs, but who knows!

Adding Apache HTTPD to the Stack

After getting Railo 3.0 running on JBoss 4.2, I then wanted to integrate Apache 2.2, which was relatively straightforward using the mod_jk module for Apache HTTPD (again, this stuff is already well documented). At this point, however, I could either have only one Railo Web root and/or needed to use specific context paths for each Web site/context (e.g., http://localost/app1-context, http://localhost/app2-context, etc.).

Railo on JBoss via Apache, as I really wanted it to be

I then wanted to be able to run multiple Apache virtual hosts as multiple Railo web contexts on the same instance of Railo, but without needing a unique context path for each and without needing to proxy from Apache. After hours of experimentation and searching for help, I just could not find a way to make this happen.

Just as I was about to give up, I was reassured that this could be done when I read a couple installation guides that used Tomcat virtual hosts and a Railo installation using the JARs download only (not an EAR or WAR deployment): this one by James Constable and this one by Gary Gilbert.

These guys were doing exactly what I wanted to do, simply with Tomcat instead of JBoss, and since I knew JBoss AS uses Tomcat as its Web server, I knew there must be a way! I simply needed to identify the JBoss deployment directory in which to locate the Railo jars, and which web.xml and server.xml files to modify within the JBoss deployment directory structure. Here they are:

{JBOSS_HOME}/lib -- Drop the Railo jar files in here.
{JBOSS_HOME}/server/default/lib -- Drop the Railo jar files in here.

{JBOSS_HOME}/server/default/deploy/jboss-web.deployer/conf/web.xml -- Define the Railo servlet, servlet mappings and welcome files in this file.

{JBOSS_HOME}/server/default/deploy/jboss-web.deployer/server.xml -- Define Host entries for each application/virtual host in this file (to match up with Apache virtual hosts).

Next Steps

I would like to learn a bit more about JBoss AS administration and be sure my environment is configured for high performance and sensible security. I'll also want to run JBoss as a daemon that starts automatically at boot. I'm running Ubuntu 8.04 as my main development environment and I found what promises to be a fantastic article on a proper JBoss AS installation on Ubuntu!

I'm also looking for some sort of confirmation that my basic method of configuring this Railo/JBoss/Apache stack makes sense, or whether there's a preferred alternative (using WAR, EAR, proxy, etc.). I hope to get a lot of answers in the near future since Railo just recently joined forces with JBoss (read the Railo announcement here or the JBoss.org announcement here).

BlogCFC was created by Raymond Camden.