An Architect's View

CFML, Clojure, Software Design, Frameworks and more...

An Architect's View

Railo for Dummies Part IV Appendix

March 28, 2009 ·

In the comments on Part IV, Barney suggested using AJP to proxy and I confirmed that it preserves the CGI variables REMOTE_ADDR and REMOTE_HOST which Paul Kukiel asked me about. Paul also noted that adding the ProxyPreserveHost directive causes the host headers to be passed through the proxy. I'd actually added that locally but didn't want to complicate the blog post by mentioning it. In this Appendix post, I want to tackle SES URLs. One downside of Tomcat is that it does not support the following common form of SES URLs: We're going to tackle this by changing our proxy strategy to use mod_rewrite.To recap, here's our previous virtual host definition in Apache (with ProxyPreserveHost added):
<VirtualHost *:80>

   DocumentRoot /Users/scorfield/Sites

   ProxyPreserveHost On
   ProxyRequests Off
   <Proxy *>
      Order deny,allow
      Allow from all

   ProxyPass / http://localhost:8080/
   ProxyPassReverse / http://localhost:8080/
Instead of using the basic ProxyPass, we're going to use the 'proxy' option of RewriteRule to rewrite just CFML requests as first step. We need to turn the rewrite engine on and then replace the forward proxying directives with a rewrite rule:
<VirtualHost *:80>

   DocumentRoot /Users/scorfield/Sites

   ProxyPreserveHost On
   ProxyPassReverse / ajp://localhost:8009/

   RewriteEngine On
   RewriteRule ^/(.*\.cf[cm])$ ajp://localhost:8009/$1 [P]
The rewrite rule says: "Match any complete URL that ends in .cfm or .cfc and send it to Tomcat via AJP". The [P] flag means "proxy this request and stop processing rules". Don't forget to restart Apache for the change to take effect:
sudo apachectl restart
Now our CFML requests are being processed by Tomcat but everything else is being processed by Apache. Normally, SES URLs are handled in CFML applications by looking at the CGI variable PATH_INFO and processing that. We can't quite get there but we could arrange for that part of the path to be passed as part of the query string instead. To do that, we add a second rewrite rule that handles URLs where .cfm (or .cfc) is present but not at the end of the URL:
RewriteRule ^/(.*\.cf[cm])(/.*)$ ajp://localhost:8009/$1?path_info=$2&%{QUERY_STRING} [P]
This isn't ideal (because CGI.PATH_INFO does not contain the information we need) but at least we can now get at it via URL.PATH_INFO. You can use any name for the URL variable to avoid possible collisions with your own URL variables (but of course whatever you use in the rewrite rule must match what you use in your code!). Unfortunately, you'll have to modify code that relies on CGI.PATH_INFO to use URL.PATH_INFO instead, e.g., the SES URL processing in Fusebox 5.5 (around line 66 of myFusebox.cfc). It's a pity we cannot set CGI variables in CFML because then we could force CGI.PATH_INFO back to a correct value! If anyone knows of a better solution, please let me know!

Tags: apache · coldfusion · osx · railo

12 responses

  • 1 dave // Mar 30, 2009 at 1:33 PM

    any advantage to using ajp over what I am doing here?
  • 2 dave // Mar 30, 2009 at 1:42 PM

    Sava cms does this with a jar file and then adding the mapping in web.xml

          &lt;description&gt;Translates friendly URLs to objects&lt;/description&gt;

  • 3 Matt Woodward // Mar 31, 2009 at 3:09 PM

    OpenBD has a friendly URL servlet as well.

    Also, once you're proxying you shouldn't need to specify a document root for your virtual hosts ... unless I'm missing something about your configuration. Apache doesn't need to know where the documents are since it's just proxying out to Tomcat anyway.
  • 4 Sean Corfield // Mar 31, 2009 at 3:33 PM

    @Matt, with the RewriteRule I'm only proxying .cfm / .cfc requests and letting Apache serve everything else (so, yes, I do need DocumentRoot).
  • 5 Matt Woodward // Mar 31, 2009 at 4:29 PM

    Yep, just noticed that after I made the comment.
  • 6 Damon Gentry // Apr 16, 2009 at 5:24 AM

    Hi all. It looks like Craig Kaminsky has posted a solution for this. Using the 'urlrewritefilter' jar file available from Google Code, you can get SES support for Railo under Tomcat.

    Craig's post is at:
  • 7 Tony Garcia // Apr 18, 2009 at 7:07 AM

    Hi Sean,
    I've been playing around with Tomcat and deployed Railo on it as the ROOT app (as you described in your posts) running a ColdBox app. as you know, ColdBox SES urls take on the form of &quot;index.cfm/handler/action.&quot; I found that I could get these form of URLs to work in Tomcat by just adding the following servlet mapping in the app's web.xml file:


    By doing this, I can still use the cgi.PATH_INFO variable, as well.
  • 8 Sean Corfield // Apr 18, 2009 at 11:26 AM

    @Tony, thanx for that. I'll have to try it out when I rebuild my Tomcat env for multiple webs in the next few days. I keep reading SES URLs just don't work on Tomcat so I hadn't actually tried it...
  • 9 Tom Chiverton // Apr 21, 2009 at 4:03 AM

    If I'm write, where you proxy ajp://localhost:8009 I could use ajp://projectA.localhost:8009 in one Apache virtual host, and ajp://projectB.localhost:8009 in another, right ?
  • 10 Sean Corfield // Apr 21, 2009 at 7:08 AM

    @Tom, yup, you can proxy to any servers and you can use different ones in each vhost.
  • 11 Tom Chiverton // Jun 4, 2009 at 11:05 AM

    You need to proxy a few other paths to make things like Flex Remoting working. The complete set is:

    ProxyPreserveHost On
    ProxyPassReverse / ajp://localhost:8009/

    RewriteEngine On
    RewriteRule ^/(.*\.cf[cm])$ ajp://localhost:8009/$1 [P,L]

    RewriteRule ^/flashservices/gateway(.*)$ ajp://localhost:8009/flashservices/gateway$1 [P,L]
    RewriteRule ^/messagebroker/(.*)$ ajp://localhost:8009/messagebroker/$1 [P,L]
    RewriteRule ^/flex2gateway/(.*)$ ajp://localhost:8009/flex2gateway/$1 [P,L]
    RewriteRule ^/openamf/gateway/(.*)$ ajp://localhost:8009/openamf/gateway/$1 [P,L]

  • 12 Alex // Aug 20, 2013 at 12:42 AM

    I was having trouble setting this up, so instead of using rewrites I'm proxying everything to Tomcat

    ProxyPreserveHost On
    ProxyPass / ajp://anotherserver:8009/
    ProxyPassReverse / ajp://anotherserver:8009/