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.
What if Drupal runs under the root of a (sub) domain?
Like: http://example.com