Apache vs. Lighttpd Rewrite Rules: How to migrate.

When migrating an existing complex PHP powered website from Apache to lighttpd one of the big problems is how to map the webserver configuration. Most of the configuration and modules can be easily mapped, the real problem is mapping non-trivial rewrite rules.

In short while mapping the match condition is mostly easy you might struggle with these points:

  • Environment variables passed from the mod_rewrite variants are different
  • Mapping Apache mod_rewrite flags is not fully supported
  • The lighttpd mod_rewrite does not allow checking of server variables.
  • The lighttpd mod_rewrite does not support rewrite maps.
  • The lighttpd mod_rewrite does not support file tests.
  • .htaccess doesn't work in lighttpd
  • No rewrite debug log in lighttpd.
Important: please take all these points as results of some experimentation, experience that might not be 100% correct, but still might help the one or the other.

A short note on the official documentation: there is a migration document in the lighttpd wiki with a mod_rewrite section which gives a single example. Sadly it doesn't really explain the main differences very well.

Different Environment Variables

Both mod_rewrite implementations do use different environment variables which your PHP or CGI scripts might depend on. If you have an application doing rewrite logic you will have to adapt it. At least the following Apache $_SERVER mod_rewrite variables are not available:

Apache mod_rewrite lighttpd mod_rewrite
SCRIPT_URL REQUEST_URI
SCRIPT_URI SERVER_NAME + SCRIPT_URL
SCRIPT_NAME REQUEST_URI
REQUEST_URL REQUEST_URI
REDIRECT_URI SERVER_NAME + REDIRECT_URL
QUERY_STRING REDIRECT_QUERY_STRING

Note: the second column contains alternative replacement variables, that principally work, but might not behave exactly the same in some rewrite scenarios.

So the following PHP script piece could be used to adapt your rewrite code

if (strpos($_SERVER['SERVER_SOFTWARE'], 'lighttpd') !== false) {
   $_SERVER['SCRIPT_URL'] = $_SERVER['REQUEST_URI'];
   $_SERVER['SCRIPT_URI'] = "http://" . $_SERVER['SERVER_NAME'] . $_SERVER['SCRIPT_URL'];
   $_SERVER['SCRIPT_NAME'] = $_SERVER['SCRIPT_URL'];
   $_SERVER['PHP_SELF'] = $_SERVER['SCRIPT_URL'];
   if(!empty($_SERVER['REDIRECT_URL'])) {
      $_SERVER['REDIRECT_URI'] = "http://" . $_SERVER['SERVER_NAME'] . $_SERVER['REDIRECT_URL'];
      $_SERVER['REDIRECT_QUERY_STRING'] = $_SERVER['QUERY_STRING'];
   }
}

Mapping Apache mod_rewrite Flags

Flag Replacement
F %
G %
L Use "rewrite-once"
N %
NC %
NE %
NS %
QSA You can map and replace the whole URL in lighttpd, including the query params.
PT %
R You can map and replace the whole URL in lighttpd. This makes the flag redundant.
S %
T Cannot be realized in lighttpd