WordPress on lighttpd with pretty permalinks

Even though wordpress runs very well on lighttpd (lightty), information on how to set this up is quite scattered around the net. On top, most of the explanations refer to one another, and only a few have proper explanations on what is going on — even though many are very helpful and may even work in some/many cases.

One otherwise good write-up is the one done by Joe Crobak, but I think it is not fully correct as it suggests the two alternative methods below to be used in parallel (which is not really be needed).

My take on this (which could also be incorrect… so I advice the reader to dig into the details of this before deploying it) is as follows:

No pretty permalinks

If you use the normal “ugly” links like I currently do here on this blog (www.b4net.dk/?p=214 or ?page_id=214), you don’t need any special setup for wordpress to work with lighttpd. It just seems to work out-of-the box, once you have the normal setup going, like in this setup or similar, that accepts all *.host.tld and host.tld requests:

   $HTTP["host"] =~ "(^|\.)host.tld" {
     server.document-root = "/var/www/host/"
   }

Pretty permalinks

However, if you want permalinks to work, you may need to implement the equivalent of these apache mod_rewrite directives:

   <IfModule mod_rewrite.c>
   RewriteEngine On
   RewriteBase /
   RewriteRule ^index\.php$ - [L]
   RewriteCond %{REQUEST_FILENAME} !-f
   RewriteCond %{REQUEST_FILENAME} !-d
   RewriteRule . /index.php [L]
   </IfModule>

What this does is to 1) make no changes to requests for anything that starts with “index.php”, 2) allow requests for files or directories that exists to pass through, and 3) add the string “/index.php” to all other requests.

To illustrate the 3 rules above, this is what may happen:

   host.tld/index.php?p=123 -> host.tld/index.php?p=123
   host.tld/wp-admin        -> host.tld/wp-admin (eventually host.tld/wp-admin/index.php)
   host.tld/nice/permalink  -> host.tld/index.php/nice/permalink

There are two alternative ways I will describe that can be used to implement this in lighttpd: 1) using a 404 error handler or 2) a rewrite section:

404 Error Handler Method

This method is described many places on the net, and is the simplest to set up, e.g. by Chris Johnston (note: this particular link deals with vhosts; it also works in simpler setups).

It works by simply adding an error handler in the lighttpd section that deals with your host, like this:

   server.error-handler-404 = “/index.php”

When the user requests a file, lighttpd first checks, as normally, if either the file or a directory with suitable index.* files it exists, and loads/executes that. This is equivalent to 2) above and also catches case 1).

If the file does not exists, lighttpd instead calls up the root directory index.php file, seemingsly passing the “original” parameters on to the file. This is is somewhat similar to 3) above, i.e. it appears as if your permalinks gets invoked like this:

   host.tld/nice/permalink  -> host.tld/index.php/nice/permalink

It has, however, certain problems — at least I have NOT been able to get this to work properly with plugins that needs to interact with the users through a combination of permalinks and parameters. So in essence, it looks as if it was supposed to translate like this:

   host.tld/nice/permalink?p=1  -> host.tld/index.php/nice/permalink?p=1

… it actually does this:

   host.tld/nice/permalink?p=1  -> host.tld/index.php/nice/permalink

i.e. the query gets messed up. This is the case with e.g. Satollo’s newsletter plugin and also the ALO EasyMail Newsletter plugin; some of the subscribe confirmation/unsubscribe links simply don’t work but just shows the “template” page instead.

You can “fix” this either by using the method below or by adding these lines to the relevant lighttpd config section:

   url.rewrite-once = (
      # workaround
      "^/my/newsletter/(.*)$" => "/index.php/my/newsletter/$1"
   )

where “/my/newsletter” is the page you’re using for newsletter interaction/whatever plugin you need.

If someone else figures out a better error-handler workaround, I’d be most happy to hear about that!

Rewrite directive

The alternative way to achieve the mod_rewrite is using specific rewrite rules. If you do it this way, I don’t think there are any reasons also to have a 404 error handler as pr. above.

You can e.g. add the following lines to your lighttdp file for the host you’re setting up, as pr. e.g. Emil Haukeland’s setup:

   $HTTP["host"] =~ "(^|\.)host.tld" {
      url.rewrite-final = (

         # Exclude some directories from rewriting
         "^/(wp-admin|wp-includes|wp-content)/(.*)" => "$0",

         # Exclude .php files at root from rewriting
         "^/(.*.php)" => "$0",

         # Handle permalinks and feeds
         "^/(.*)$" => "/index.php/$1"
      )
}

This works somewhat similar to the rules above: Files that are (supposed) to exist directly in any of the wp-admin, wp-includes or wp-content subdirectories, and all .php files in the root directories, are treated “as is” and other requests gets translated as follows:

   host.tld/nice/permalink?p=1  -> host.tld/index.php/nice/permalink?p=1

There are alternative methods that does a similar rewrite, some cleaner that others and some newer than others. But make sure your rewrite rules only catches the “don’t touch” and “rewrite to use index.php” correctly, depending on how you have set up your permalinks.

You may also have to remember loading the mod_redirect module in lighttpd, if it is not default in your installation.

However, they all have a caveat: If you have other subdirectories that you need to give access to and not have rewritten to let wordpress deal with, you need to list them explicitly (like if you install gallery2)!

So instead of relying on the “if exists” as in rule 2) above, you need to explicitly list them. That makes it somewhat harder to maintain, but possibly also a bit safer, as wordpress gets to deal with all “unknown” files otherwise and you need to be rather explicit about what you allow access to.

Alternatives

A different alternative would be to use mod_agent with some LUA scripting. To me, however, it appears as a slightly more complex solution, and may also slow down your site (based on hearsay — I have NOT tested this)! YMMV.

Another option would be to make specific rewrite rules that addresses only your posts and pages to include /index.php initially; depending on your chosen permalink structure, this might work also. It would have the “advantage” that the default would be to try loading any other files directly, so if you host other systems underneath the same directory (bad idea…) it would possibly be easier to maintain.

2 Responses to “WordPress on lighttpd with pretty permalinks”

  1. Hi Per, my WordPress is installed in a sub-directory on my website, like domain.com/wp/ , how could I config to make pretty permalinks works on my lighttpd? I try change
    $HTTP["host"] =~ “(^|\.)host.tld” {
    to
    $HTTP["host"] =~ “(^|\.)domain.com/wp” {
    but it doesn’t work. :(

  2. [...] Řešení přepisovacích pravidel je u lighttpd pro WordPress poměrně otevřený problém, doporučuji přečíst tento článek. [...]