Moving From IIS To Apache: It's Easier Than You Think
- a "web site" in IIS is a VirtualHost in Apache
- a "virtual directory" in IIS is an Alias in Apache
- a "home directory" in IIS is a DocumentRoot (or docroot) in Apache
- a "host header" in IIS is a ServerName or ServerAlias in Apache
- a "default document" in IIS is a DirectoryIndex in Apache
LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_http_module modules/mod_proxy_http.so LoadModule rewrite_module modules/mod_rewrite.soNext, if you're doing CFML stuff you'll want to add index.cfm as a DirectoryIndex, so find this section and update accordingly:
<IfModule dir_module> DirectoryIndex index.cfm index.html </IfModule>You can have as many directory indexes as you want, just separate with a space and realize they will get hit in the order in which they're declared. Finally, you'll want to enable name-based virtual hosting so you can have multiple virtual hosts sharing the same IP address. Towards the bottom of httpd.conf, find this section and uncomment the Include directive that will load the virtual hosts configuration file. When you're done it should look like this:
# Virtual hosts Include conf/extra/httpd-vhosts.confSave httpd.conf, and now let's take a look at how to configure your virtual hosts.Virtual Host ConfigurationOpen up conf/extra/httpd-vhosts.conf so we can configure some virtual hosts. You'll be spending a lot of time in this file as you use Apache. First, make sure this line right after the big comment block at the top is uncommented:
NameVirtualHost *:80This enables name-based virtual hosts for all IP addresses on port 80. Next you'll see a couple of examples of virtual hosts. You can either delete those or comment them out by putting a # on each line. I tend to leave them in there but comment them out for reference. For your first virtual host, let's set one up for localhost because (at least in my experience) once you enable name-based virtual hosting, you have to have a virtual host even for localhost. Add the following section, adjusting the DocumentRoot as needed based on where you installed Apache:
<VirtualHost *:80> ServerName localhost DocumentRoot "C:/Program Files (x86)/Apache Software Foundation/Apache2.2/htdocs" </VirtualHost>Save the file, and then restart Apache just to make sure all the changes we've made are working. If Apache doesn't restart don't panic, that just means you have a syntax error somewhere. Double-check everything and try again. If you can hit localhost in your browser and see "It works!", well, that message says it all I guess. Note that if you have multiple IP addresses on your machine and want to tell a virtual host to use a specific IP, or if you want to run a site on a port other than 80, you can replace the * with an IP, and the 80 with whatever port you need. Next let's configure a more real-world virtual host. I'll be using foo.com as my example, and we'll want people to be able to hit the site using foo.com or www.foo.com. I'm also going to tell Apache to use a log file specific to this site to make diagnosing problems and doing reporting easier. There are a few other things in here that I'll explain in a moment.
<VirtualHost *:80> ServerName foo.com ServerAlias www.foo.com DocumentRoot "C:/path/to/foo" Alias /CFIDE C:/path/to/CFIDE <Directory "D:/path/to/foo"> Order allow,deny Allow from all </Directory> CustomLog "logs/foo-access.log" common </VirtualHost>The ServerName and ServerAlias information is pretty self-explanatory--foo.com is the primary name for this virtual host, but with the alias of www.foo.com, either foo.com or www.foo.com will hit this virtual host. DocumentRoot tells Apache where to find the files that it will be serving when someone hits this virtual host.I threw an Alias in the mix simply to show how "virtual directories" (in IIS speak) work. Let's say in this case I want foo.com to have access to my CF administrator or maybe the javascript files that are stored in the CFIDE directory, but that CFIDE directory is not inside this host's docroot. The Alias directive tells Apache that when someone is requesting /CFIDE on this virtual host, those files will actually be served from somewhere outside the virtual host's docroot. The <Directory> directive requires a bit of explanation. For security reasons, by default all directory access (other than the default localhost site) is denied by Apache. This is done in the main httpd.conf file, so you can either make the change there, or I prefer to do this on a case-by-case basis inside each virtual host. In the case of a public site you won't know where people are coming from so you have to tell Apache to allow access to that directory from anywhere, which is done with the "Allow from all" line. I left this out, but note that you will likely have to add a <Directory> entry for the C:/path/to/CFIDE directory as well. Finally, I tell Apache to create an access log specific to this site instead of using the global Apache logs.For a lot of virtual hosts that's literally all there is to it. But since what started this whole process was rewriting issues, let's take a look at some of the cool things you can accomplish (and shoot yourself with) by using mod_rewrite. URL Rewriting and ProxyingFor the app in question we do a lot of URL rewriting and proxying so we can give the users a single site that actually is comprised of multiple sites, potentially on different physical servers. This is also a great way to handle long-term migrations where you have a legacy server that you don't really want to touch but still need content from, and you want to add a newer server in the mix. As with everything else related to Apache this is powerful stuff, but the basics are relatively simple. I do love this quote from the mod_rewrite docs, however: "The great thing about mod_rewrite is it gives you all the configurability and flexibility of Sendmail. The downside to mod_rewrite is that it gives you all the configurability and flexibility of Sendmail.''Let's start with a basic rewrite rule, and then we'll look at what I have to do a lot of which is proxying. Let's say for whatever reason in the foo.com virtual host you want requests to foo.html to actually hit bar.html. First we need to enable the rewrite engine in our virtual host, so inside your <VirtualHost> block, add this line:
RewriteEngine onNext we add a simple RewriteRule to tell requests for foo.html to be rewritten to bar.html:
RewriteRule /foo.html /bar.html [NC]The [NC] bit at the end stands for "no case," so that way both foo.html and FOO.HTML will be rewritten to bar.html. There are a ton of flags to do various things outlined in the docs, and if you want some nice rewrite example examples they have those too. So far so good? Next let's tackle proxying. Instead of a simple rewrite from foo.html to bar.html, let's say you want everything under a particular directory to be proxied to another server. To make the example more concrete, let's say your company has an intranet on one server and an employee directory that runs on another server, but you want people to be able to access the employee directory directly from your intranet. If you wanted to do a simple redirect from http://intranet/empdirectory to http://empdirectory, that's simple enough:
RewriteRule ^/empdirectory(.*) http://empdirectory$1 [NC,R]The (.*) after /empdirectory will include anything that comes after /empdirectory, and this is tacked onto the end of the remote URL via the $1. The "R" flag tells Apache to do a redirect for this RewriteRule, and you can even set the status code for the redirect. This does change the URL in the user's browser, however, so what if you didn't want that to happen? This is where proxying comes in. First, we change the "R" flag to a "P":
RewriteRule ^/empdirectory(.*) http://empdirectory$1 [NC,P]Now we're proxying instead of doing a redirect (and note that mod_proxy needs to be enabled to use the P flag, which is why we did that earlier), but if this is all you do you'll notice that the URL in the browser still changes. This is because there's nothing in place to handle proxying the response back to the requestor. So we need to add a ProxyPassReverse directive, which will allow us to hit http://intranet/empdirectory and keep that URL while the content is actually served from http://empdirectory.
RewriteRule ^/empdirectory(.*) http://empdirectory$1 [NC,P] ProxyPassReverse /empdirectory http://empdirectoryWith all this in place you can serve content from another server without your users knowing they're hitting another server. There are about a million and one other things you can do with mod_rewrite, but my only intent with this post was to share what I had to do in my specific move from IIS to Apache in the hopes it might help others who want to make this move. ConclusionEven though it was under duress, I'm honestly glad ISAPI Rewrite totally failed since that led me to setting up Apache on this box. After seeing ISAPI Rewrite have its various meltdowns I simply would not have felt comfortable using it. I'm sure I could have contacted support and gotten things figured out eventually, but it took me far longer to write this blog post than it did to switch to Apache, particularly since the rewrite syntax of ISAPI Rewrite is largely compatible with Apache's. I'm going to sleep much better at night knowing Apache is powering this app instead of being constantly worried that ISAPI Rewrite will have another meltdown. I should have made this disclaimer at the beginning but I am in no way an Apache expert, so if there are different or better ways to do any of this, if anything is explained poorly or incorrectly, or if I omitted any important details, please comment.
8 comments
We were going to settle for doing a rewrite rule that would have the URL change in the browser, but Apache passes this stuff through just fine. Funny how IIS -> IIS didn't work right but Apache -> IIS does.
So the next step for me was to remove the IIS association from ColdFusion in the Web Server Configuration tool, but when I attempt to remove IIS association, I get an error message "Error deleting IIS application extensions from Web site All" I even restarted the server and I'm still getting the same message. So what I'm wondering is if I should just go ahead and add Apache anyway, or do you think I should keep trying to fully remove IIS first before I proceed further?
Thanks for the great write up!
IIS admin service isn't the web server itself--you'll want to disable "World Wide Web Publishing Service" to stop IIS. Then to remove IIS you go into Add/Remove Programs, click on Add/Remove Windows Components on the left-hand side, and uncheck the "Web Server" box. Click next through the rest of that wizards and IIS will be removed.
On one VM I uninstalled IIS before I removed the CF connection in the web server configuration tool and I didn't run into any issues, so I don't think IIS needs to be running or even installed for you to be able to remove the associaton with IIS. I suppose it might interact with the IIS Admin Service, but I assume if I removed IIS altogether that would also have been removed, though I'm not positive of that.
If all else fails I'm sure this can be done manually so let me know if you still run into issues.



Also really don't like having to create yet another account on some site to leave a comment. I like the old wordpress comments system much better.