Many people have asked for an example for mod_magnet that doesnt involve Ruby on Rails.

I have choosen drupal. Drupal is a nice little content managment platform written in php. I used it before switching to rails. :) Though lets start.

As already mentioned in the “Dr. Magneto vs Mr 404 handler” article, drupal uses a small nice rewrite rule set:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]

Ok. Lighttpd doesnt support -d/-f. So let’s use mod_magnet. For the example we assume drupal is already installed and accessible under “http://www.example.org/drupal/”. The needed drupal.lua can be downloaded here. The script is nearly as simple as the rails example. So is the integration with lighttpd. The configsnippet is:

$HTTP["url"] =~ "^/drupal" {
    # we only need index.php here.
    index-file.names = ( "index.php" )
    # for clean urls
    magnet.attract-physical-path-to = ( "/etc/lighttpd/drupal.lua" )
}

Last but not least you need to configure drupal to use clean urls. You go to “Admin” => “Site configuration” => “Clean urls” (quick link http://www.example.org/drupal/index.php?q=admin/settings/clean-urls ) and click on the “Run the clean URL test” link. If it was successful you can enable clean urls and save the settings.

“But my drupal runs under ‘/someotherpath’, what do i need to change?”

Of course the url conditional in the config snippet above. You also need to change the prefix in the drupal.lua. Do not append a trailing slash there.

Alternatives?

404 handler?

Of course it would work as well, but the 404 handler breaks the 403 return code, which is used by drupal.

url.rewrite-once?

This is a possible solution aswell. But you need to rewrite all static files to itself.

url.rewrite-once = (
    "^(/drupal/files.*)"       => "$1",
    "^(/drupal/themes.*)"      => "$1",
    "^/drupal/([^.?]*)\?(.*)$" => "/drupal/index.php?q=$1&$2",
    "^/drupal/([^.?]*)$"       => "/drupal/index.php?q=$1",
)

Killes mentioned another rewrite solution on #drupal on freenode:

url.rewrite-once = (
    "^/drupal/system/test/(.*)$" => "/drupal/index.php?q=system/test/$1",
    "^/drupal/([^.?]*)\?(.*)$"   => "/drupal/index.php?q=$1&$2",
    "^/drupal/([^.?]*)$"         => "/drupal/index.php?q=$1",
    "^/drupal/search/node/(.*)$" => "/drupal/index.php?q=search/node/$1" 
)

Security

A small side note, in SA-2006-006 the drupal team warned about a security hole through carefully named arbitrary scripts in the files directory. The apache workaround of course doesnt work here either. The following block should secure your server with lighttpd. :)

# "Fix" for Drupal SA-2006-006, requires lighttpd 1.4.13
$HTTP["url"] =~ "^/drupal/files" {
    cgi.assign = ()
    fastcgi.server = ()
    scgi.server = ()
}

For versions before 1.4.13 you need to move your cgi/fastcgi/scgi defintions into a conditional that inverts the match as shown in the example above. But i have to admit it complicates the config quite a bit. ;)

Update: the script was broken for prefices containing lua patterns special chars. This has been fixed and a new version was uploaded.