Matthew Woodward // * CFML, Grails, and Java Developer
* Principal IT Specialist, US Senate
* Open BlueDragon Steering Committee Member
* All-Around Geek
A few quick tips if you find yourself having to access a network drive from Apache and Tomcat on a Windows Server. This is all pretty much old hat but since I still get questions about this fairly regularly and was just setting up some things on some servers this weekend, I figured I'd write this up.
In my situation we're running an application on three VMs behind a load balancer, and users can upload files from the application. Since I didn't want to set up a process behind the scenes that copied uploaded files between all three servers (though it would have given me a chance to take another run at using Unison), we have an uploads directory living on a SAN. This way no matter which VM the user is on, the uploads all go to and are served from a single file system.
On Windows Server, by default services run under the Local System Account, which doesn't have access to network resources. So if you install Apache and Tomcat as services and expect to be able to point them to a UNC path for some of your content, that won't work out of the box. You need to be running Apache and Tomcat under an account that has network access. In most environments in which I've worked this type of account is typically called a "service account," because you'll end up getting a domain account just like your typical Active Directory user account, but of course it won't be associated with a human being.
Once you have that account in place, you go into your services panel, right click on the service, click on "Properties," and then click the "Log On" tab. You'll see by default the Local System Account radio button will be checked. Click the radio button next to "This Account," enter your service account information, click "OK," and then restart the service. At this point your service will be running under the service account and will have access to network resources. Note that you'll have to do this for each service that needs access to the network drive, which in my case meant doing this for both Apache and Tomcat.
That takes care of the web server and things at the Tomcat level in terms of basic access, but you'll likely be configuring an alias of some sort to point to the network drive. In my case I wanted /uploads to point to \\server\sharename\uploads, which meant setting up an alias in Apache, a Context in Tomcat, and a mapping in OpenBD. This is where a lot of people get confused, so I'll go through each of these settings one by one.
The necessity for a web server alias is probably pretty obvious. If you're serving an image directly from your web server, e.g. http://server/uploads/image.gif, if /uploads doesn't exist under your virtual host's docroot, then Apache will throw a 404.
Allowing Apache to access the network drive involves (depending on how you have Apache configured) using a Directory directive to give Apache permission to access the directory, and then an Alias directive so Apache knows where to go when someone requests something under /uploads. So the following goes in your virtual host configuration file:
<Directory "\\server\sharename\uploads"> Order allow,deny Allow from all </Directory> Alias /uploads "\\server\sharename\uploads"
You may have other stuff in your Directory directive as well but that's the basics of what will allow Apache to see /uploads as the appropriate location on your SAN.
The next layer down will be your CFML engine. Remember that if in your CFML code you want to read or write files to /uploads, even though Apache knows what that is now, your CFML engine will not. I'm emphasizing that point because it's such a common source of confusion for people. If things are happening in your CFML code, it won't be interacting with Apache at all, so it won't know about the Alias you set up in Apache. Simple enough to solve with a mapping; just go into your CFML engine's admin console and create a mapping that points /uploads to \\server\sharename\uploads and that handles things at the CFML level.
Lastly comes Tomcat. Depending on how you're serving files, you may be proxying from Apache to Tomcat, so if Tomcat needs to know where /uploads lives, since it's not in the webapp's base directory Tomcat will throw a 404 unless you tell it where /uploads is located.
Tomcat doesn't have Aliases in the same way Apache does, but what you can do in Tomcat is configure multiple Contexts under a single host. So in Tomcat's server.xml (or in a separate host config file if you prefer), you simply add a Context that points /uploads to the network location:
<Host name="myapp"> <Context path="" docBase="C:/location/of/my/app" /> <Context path="/uploads" docBase="\\server\sharename\uploads" /> </Host>
So now you have things set up in such a way that Apache, your CFML engine, and Tomcat all know where /uploads really lives.
Another point of confusion for people on Windows is the concept of "mapped drive" letters. A lot of people think that if you map \\server\sharename to a drive letter of let's say D:, than in your code you can then access the uploads directory we've been using as our example via D:\uploads.
The simplest way to explain why this doesn't work is to point out that mapped drive letters are associated with a Windows user account. They don't exist at the operating system level. While you may remote into the server using your credentials, map to a network location, and assign that to drive letter D:, another user logging in won't see that mapping, and services running on the server under various user accounts definitely won't know anything about mapped drives.
This is why in all the examples above you see the full UNC path to the network resource being used. You have to use the UNC path in order to get this all to work correctly because that's the only way services running under a service account will be able to address the network resource.
Hope this helps eliminate some of the persistent confusion I see around this issue.
BFusion/BFlex is coming up on September 11 and 12, 2010 in lovely Bloomington, IN. You need to be there, and here's why.
I've been invovled with BFlex/BFusion since the first year and it's one of my favorite conferences. I'm particularly excited this year to be able to help people delve into the open source CFML engines, so I hope to see lots of you there.
Great training, great price, great location, and great people. What are you waiting for? GO REGISTER NOW!
RewriteRule ^/([a-zA-Z0-9-]{1,})/(.*)$ ajp://%{HTTP_HOST}:8009/$1/index.cfm/$2 [NE,P]
Translation:
ProxyRequests Off
<Proxy *>
Order deny,allow
Allow from 127.0.0.1
</Proxy>
ProxyPreserveHost On
ProxyPassReverse / ajp://your-host-here:8009/
RewriteEngine On
# if it's a cfml request, proxy to tomcat
RewriteRule ^(.+\.cf[cm])(/.*)?$ ajp://%{HTTP_HOST}:8009$1$2 [P]
# if it's a trailing slash and a real directory, append index.cfm and proxy
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^(.+/)$ ajp://%{HTTP_HOST}:8009%{REQUEST_URI}index.cfm [P]
# if it's a real file and haven't proxied, just serve it
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f
RewriteRule . - [L]
# 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
# MUST COME AFTER ANY OTHER FIXED/EXPECTED REWRITES!
RewriteRule ^/([a-zA-Z0-9-]{1,})/(.*)$ ajp://%{HTTP_HOST}:8009/$1/index.cfm/$2 [NE,P]
Note that you can put the rewrite rules in a .htaccess file or in the virtual host configuration file. I prefer having the rewrite rules be defined as part of the virtual host, so in my case I have all this in the <VirtualHost> block in my virtual hosts config file. (I have a bunch of other stuff in the virtual host configuration as well but I left everything other than the parts relevant to the URL rewriting out to avoid any confusion.) That's it! I hope that helps others looking into doing this with Mura, or that you at least learned a few things about mod_rewrite along the way.
Dallas TechFest was last Friday and although I was sad to be missing the final CFUnited, TechFest was a blast. It was incredibly refreshing to see 400+ CFML, PHP, .NET, Java, and Flex people all in the same place at the same time for some geek cross-pollination. This doesn't happen nearly enough so thanks to all the organizers of the event, all the great speakers, and to Dave Shuck for inviting me to speak.
The talk I gave was entitled "CFFree: Building and Deploying CFML Applications on a Free Software Stack." This was a 90-minute introduction to developing, deploying, testing, and monitoring CFML applications using Tomcat, Open BlueDragon, Railo, and a plethora of other free software applications and tools. If you didn't make Dallas TechFest this year and are interested in this topic you're in luck! I gave everyone who attended my session a VirtualBox VM that has all the free CFML goodness installed on Ubuntu 10.04, and you can download the VM from my Dropbox (2.5 GB). You can also check out the presentation slides above (view or download PDF). My apologies that the speaker notes get cut off in the PDF version, but I created the presentation in Google Docs and as far as I can tell there's no way to control the font size of the speaker notes in the PDF. You can also view the presentation directly in Google Docs; just make sure to click "Actions" at the bottom then "Show Speaker Notes" to view the speaker notes since the slides alone don't tell you all that much. As always if you grab the VM or read through the presentation and have any questions about any of this feel free to contact me. I'm considering doing a couple of screencasts on this topic because due to time constraints I had to breeze over some of the configuration details, not to mention some of the free software goodness I didn't get to show at all. If you want to learn more about free CFML in person, next up on the calendar is a full day hands-on session that Adam Haskell and I will be doing at BFusion in September, and then of course three full days at OpenCF Summit in February 2011. Hope to see you at one or both of these events!Dallas TechFest is a great multi-technology event that's coming up on 7/30. There are tracks on Java, Flex, PHP, .NET, and most importantly CFML, so it's not only a great place to get your CFML fix, but also to engage in some all-too-rare cross-pollination between technologies. (The tech community doesn't do nearly enough of this sort of thing in my opinion.)
The CFML track doesn't have details on the track page unfortunately, but when you check out the speakers page you'll see the following great CFML speakers:I don't know what the specific topics for some of the speakers are, but I can tell you that I'll be speaking on Building and Deploying CFML on a Free Software Stack, Jeff Lucido is speaking on Open BlueDragon for Google App Engine, and I'm pretty sure Steve Good is speaking on Mura. With this lineup I'm sure all of the CFML topics will be great!
UPDATE: Steve pointed out in the comments a big oversight on my part--you can check the Agenda page to see all the details of all the tracks.
There are also some big names from other technologies at TechFest as well, such asScott Davis (Grails guru extraordinaire), Ted Neward (.NET developer and consultant), Mark Piller (Midnight Coders), and Craig Walls (SpringSource) to name but a few.
Sounds excellent, right? Well, today's your lucky day. If you haven't registered yet there's still time, and there's a big discount to boot! Register now and use the discount code coldfusion to get in for only $25. That's right, a mere $25 for all this geeky goodness. See you there!I ran into this today while working on ColdTonica, and since it's something I'm still surprised people forget (including myself) I thought I'd share.
ColdTonica is a CFML clone of StatusNet (formerly Laconica), which is an open source PHP-based microblogging service similar (although vastly superior) to Twitter. As you might imagine, those simple 140-character notices you spend way too much of your day posting go through a lot of transformations before reaching the final form in which they are displayed, because the notices need to be parsed and manipulated to add things like links to tags, links to @ replies, shortening URLs, and so on. Honestly when I started studying the StatusNet code and saw what all goes on behind the scenes for such a seemingly simple service, I have to admit I was a bit surprised. All the text manipulation of course involves a lot of regular expressions, and since for ColdTonica we're porting the PHP code over to CFML, it saves us a ton of time since all the regular expressions have already been written. Unfortunately there are some syntax issues with the regular expressions that render them incompatible with CFML and even Java, so it did take a bit of research and help from a friend of mine to start to unravel and convert them. One of the issues I ran into while moving the PHP regular expressions over to CFML is that CFML doesn't have Unicode support in regular expressions (some nice info about Unicode in regex here, although the information about Java is dated), at least not without first converting Unicode to ASCII values and wrapping them all in Chr(). This is what I've discovered while messing with this at least; if this isn't correct I'm happy to be proven wrong. Since the PHP regular expressions use the Perl syntax of \x{hex_value_here}, which CFML doesn't support, converting the regular expressions was getting a bit messy. Java, however, does support the \x syntax (though it didn't used to), but with a slightly different syntax. You can read more about Java regex syntax in Java 6 here. During the course of this I was reminded of the fact that under the hood, CFML strings are Java strings, which means that rather than using functions like REReplaceNoCase() in CFML and converting the hex codes into something usable by Chr(), I can simply use Java's replaceAll() function on the String class. This lets me keep the PHP syntax more intact and do a lot less conversion research. So the original PHP looks like this:
$r = preg_replace('/[\x{0}-\x{8}\x{b}-\x{c}\x{e}-\x{19}]/', '', $r);
And the CFML version using replaceAll() on the String class looks like this:
r.replaceAll("/[\x00-\x08\x0B-\x0C\x0E-\x19]/", "");
At least I think that's right. ;-) I still need to test all of this out, but as I convert the rest of these it'll be much simpler to go this route and keep things in hex as opposed to converting everything to CFML-compatible Unicode regex syntax. The moral of the story is you can do a lot in CFML by leveraging the underlying Java functionality, and this doesn't apply only to the String class. So if you run into things that are a bit weird to try and accomplish in CFML check the Java docs and see what additional functionality you have available. You'll probably be surprised at what you learn!
This is long-delayed after cf.Objective() 2010, but here is a zip of the sample app and the presentation PDF from the presentation Peter and I gave on running CFML applications on Google App Engine.
We also gave this presentation at the CFMeetup a couple of weeks ago (you can watch the recording), and are doing it again for the Mid-Michigan CFUG on Tuesday, June 8, at 7 pm Eastern US time. To use the sample app create a new Google App Engine project in Eclipse, then copy the unzipped files into that project.If you need help getting up and running with GAE on Eclipse, check this blog post on the Detroit Area Adobe UG's blog, or check the GAE for Java page. The MMCFUG may also be streaming this meeting live so I'll post again with a URL if that happens.I didn't add this to the PDF or code before I uploaded them, but both are released under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License. 
(download)