Here are the steps I had to go through to make Drupal 6.x work with (Sun|Open) Web Server (these are in addition to the normal Drupal installation steps documented by the Drupal project.
- Remove/rename the .htaccess file provided in the Drupal package. The .htaccess file provided contains several directives that are Apache specific and cause behavior that you don't want from Web Server. In this case the directive recognized causes Web Server to refuse access to Drupal.
- Make sure that . is part of the include path for PHP (this isn't so much a requirement for Web Server as it is for Drupal to work at all). I accomplished this by adding include_path = .;/usr/local/lib/php to my php.ini file, then restarting Web Server in order to force PHP (running as FastCGI child processes of Web Server) to re-examine the config.
- Modify obj.conf so that "Clean URLs" work. Drupal does a self-check with a .htaccess file that means nothing to Web Server. We have to manually create the rules so that this test can pass (you can do this prior to installing Drupal, or can do it after installation). This rule needs to be added to the obj.conf Default Object:
# # # # Drupal clean URLs # # # # If the request has not already been restarted, and the URI does not # map to an accessible file or directory <If not $internal and not -U $uri> # Find the URI and the Query string in the URL, then restart the # request with the URI and Query passed to index.php <If $url =~ '//[^/]+/([^?]*)(\?(.*)|())$'> AuthTrans fn="restart" uri="/index.php?q=$1&$3" </If> </If>This rule tells Web Server to perforum URL rewriting if the request has not already been restarted, the URI does not map to a file that exists (if you're running other web apps on the same server for the same domain you will probably want to create another "does not match" rule against the base URI for that app to prevent Drupal from trying to service the other app's requests), and finally some Regular Expression magic that understands the format of URIs that Drupal likes to construct. If all of these conditions are true then "restart" the request internally with a URI reconstructed from the submitted URL. Note that this rule is also built entirely around the idea of Drupal being at my URI "root." If you have Drupal buried farther down in URI space (i.e. /drupal/) then you'll want to adjust the AuthTrans path accordingly. This works great for an obj.conf that serves a single domain. In my case this obj.conf is used to service several domains so I have further checked if this request is for a domain that I know has Drupal running on it:
# # # # Drupal clean URLs # # # # If the request has not already been restarted, the request is # for a virtual server that I know has Drupal on it, and the URI does not # map to an accessible file or directory <If not $internal and $urlhost =~ '(?i)(foobar\.org|bazfoo\.com)$' and not -U $uri> # Find the URI and the Query string in the URL, then restart the # request with the URI and Query passed to index.php <If $url =~ '//[^/]+/([^?]*)(\?(.*)|())$'> AuthTrans fn="restart" uri="/index.php?q=$1&$3" </If> </If>This first checks the domain name against a know list of domains that are running Drupal. If that evaluation fails then the entire evaluation for rewriting is skipped.
Until these changes are made in the obj.conf and Web Server is reconfigured OR restarted the "Clean URLs" self test in Drupal will fail. This isn't a fatal problem, but it does mean your URLs will look less pretty to your readers.
These three steps were the only things I had to do to get Drupal 6.x running on Web Server. Now I get to spend far too much time working with Blocks, and Templates, and CSS, and more!
Note that the expression above is an attempt to make things compact. This could also be accomplished a little less arcainly with something like:
# # #
# Drupal clean URLs
# # #
# If the request has not already been restarted, and the VS is
# one I'm serving that I know has Drupal on it, and the URI does not
# map to an accessible file or directory
<If not $internal
and $urlhost =~ '(?i)(foobar\.org|bazfoo\.com)$'
and not -U $uri >
# If the URI is simply "/" and there is no query string
<If $uri = "/"
and not defined $query >
AuthTrans fn="restart" uri="/index.php"
</If>
# Otherwise the URI needs to be passed to Drupal, but making
# reference to variables not defined makes Web Server grumpy, so
# intentionally DON'T reference $query
<ElseIf not defined $query >
AuthTrans fn="restart" uri="/index.php?q=$uri"
</ElseIf>
# Otherwise we have a URI and a Query to pass to Drupal (note that
# a fourth rule might exist that would pass just the Query string
# and no URI, but I've yet to find a situation where the front page
# of Drupal expects Query data)
<ElseIf defined $query>
AuthTrans fn="restart" uri="/index.php?q=$uri&$query"
</ElseIf>
</If>
Update: Someone named Nikola seems to have adapted this for use with Magento (evidently some ecommerce platform). Neat!
What they came up with is:
<Object name="default"> ... # # # # Magento clean URLs # Adapted from a Drupal implementation http: //jmccabe.org/drupal_and_web_server # # # # If the request has not already been restarted and the URI does not # map to an accessible file or directory. # We will rewrite all other traffic to index.php. It turns out that there # is no need to send the requested path to Magento (e.g. /index.php/requested/path) # and since it causes the "No input file specified" error we can't do it anyway # Magento will parse the URL and get the path <If not $internal and not -U $uri> <If $uri =~ '/magento/.*'> # Making reference to variables not defined makes Web Server grumpy, so # intentionally DON'T reference $query if it's not defined <If not defined $query > AuthTrans fn="restart" uri="/magento/index.php" </If> # There is a query so send it along as well <ElseIf defined $query> AuthTrans fn="restart" uri="/magento/index.php?$query" </ElseIf> </If> </If>