Goto Top

Lighttpd, Rewrite and a strange Error-handler

From the everyday life of an admin: Actually I wanted to do something completely different, but when I got a mail with an update request for Matomo, my day changed. The update went through cleanly as usual, but in the end there was an error message about public accesses to the /config/ and /tmp/ directory. Huh?

back-to-topProblem access-deny?

Of course, the directories are locked by "access-deny" in the web server's configuration, so why are they showing as readable to me? First I checked the configuration (web server, PHP, etc.), it was fine, then I tested the access to the directories and yes, damn, it looks like they are really accessible from outside. Not a big deal in principle, since they are PHP files that don't display any content. But what happens if the PHP praser times does not work, after all, the configuration of Matomo is in here!

Then I had the idea to compare the versions of the web server. As a web server we run a Lighttpd and that for over 20 years. This is a small, fine and very fast webserver, which can handle FPM-PHP perfectly. It is very similar to "nginx", but older. Due to the change from Ubuntu 20.04 to 22.04 LTS we had a big version jump.

Here are the different versions in Ubuntu: Lighttpd version 1.4.55, Ubuntu 20.04 LTS vs Lighttpd version 1.4.63, Ubuntu 22.04 LTS.

In the configuration you lock complete directories (and the files behind them) with the following code:

$HTTP["url"] =~ "^/config/.*" {  
    url.access-deny = ("")  

It looked like this would only work properly if there was no global rewrite in the configuration. Matomo has a global rewrite for all files to the "index.php" file in its configuration. In the Lighttpd configuration it looks like this:

url.rewrite-if-not-file = (
        "" => "/index.php${url.path}${qsa}"  

If the rewrite is set up, the web server seems to ignore the "url.access-deny". This leads to the actual protected path /config/ being displayed with the contents of the rewrite file "index.php". This in turn confuses Matomo's check scripts, since they actually expect the HTTP code 403, but instead get an HTTP code 200 OK as response. If I remove the global rewrite, it works as usual: The typical 403 message appears and everything is fine. If I activate the global rewrite again, the directory /config/ is displayed with the content of the global redirect "index.php".

This is not a security vulnerability. It only looks from the outside as if you have access to the protected directories, in reality only the content of the redirection file "index.php" is displayed. If there is no "index.php", the protection by "url.access-deny" still works.

If the Matomo system checker hadn't nagged with big red notices, I wouldn't have noticed this behavior at all.

back-to-topError found

After some testing and intense discussion with a Lighttpd developer I find the reason for the error: In the configuration for the 404 page. There is the setting "error-handler-404":

server.error-handler-404  = "/404.php"  

If the "error-handler-404" is set, it also reacts to all 403 errors (according to lighttpd developers a historical decision) and the file "404.php" is called. The given file "404.php" does not exist anymore and so the "rewrite-if-not-file" rule comes into play, which does a rewrite to the global "index.php". This in turn leads to the HTTP status 200-OK being output and not the expected HTTP status 403 Forbidden. But even if the "404.php" file would exist, a 200 status would appear instead of the 403, unless you add an error status to the error page via HEADER.


Just remove the obsolete configuration "server.error-handler-404" or replace it with the better "server.errorfile-prefix" (see the Lighttpd documentation).

Another solution with "mod_magnet" can be found in the ticket with the developer.

Our solution prefers the way via the HAProxy. This is located before the web server and takes over the protection of the directories instead. There, as probably with every web proxy, you can set your own "deny" rules for directories and domains. With the ACLs (from version 1.8) this was simplified.

Here is our HAProxy configuration (only the most important part of it). The rule only applies to the domain and refers to Matomo:

front end https in
      acl evil path_beg -i /tmp/
      acl evil path_beg -i /config/
      acl evil path_beg -i /lang/
      acl evil path_beg -i /core/
      acl evil path_beg -i /.git/
      http-request deny if evil { hdr(host) -i }

If you want, you can also expand this globally with certain endings. Then the web server doesn't have to do it anymore (it's more efficient if the HAProxy does it). The following is just a sample of endings:

front end https in
      acl bad path_end -i .htpasswd
      acl bad path_end -i .sh
      acl bad path_end -i .log
      acl bad path_end -i .idea
      acl bad path_end -i ~
      http request deny if bad

I hope my contribution can help a desperate admin who has a similar configuration. It took me about 8 hours (detect, check, fix, test, deliver).


Content-Key: 3552309279


Printed on: December 9, 2023 at 07:12 o'clock

Member: Frank
Frank Aug 05, 2022, updated at Aug 06, 2022 at 22:45:57 (UTC)
Goto Top
I created a ticket for this:

Member: Frank
Frank Aug 06, 2022 updated at 22:47:18 (UTC)
Goto Top
Update after some re-tests:

If you have a global rewrite as described above, this leads to the fact that the actual protected path "/config/" is displayed with the content of the rewrite file "index.php".

This in turn confuses Matomo's check scripts, since they actually expect the "HTTP code 403", but instead get an "HTTP code 200 OK" as a response.

This is not a security hole. It only looks from the outside as if you have access to the protected directories, but in reality only the content of the redirect file "index.php" is displayed. As soon as the "index.php" is not present, or it is not delivered correctly, the protection by "url.access-deny" still exists.

As it looks, the error is due to a setting of the "error-handler-404".

I have adjusted the text above.