lighttpd - ArchWiki

Jump to content

# lighttpd

From ArchWiki

"lighttpd (pronounced /lighty/) is a secure, fast, standards compliant, and very flexible web server that has been optimized for high-performance environments. lighttpd supports a wide variety of features while using memory and CPU efficiently, making lighttpd an ideal web server for all systems, small and large."

## Installation

Install the lighttpd package.

## Configuration

### Basic setup

The lighttpd configuration file is: `/etc/lighttpd/lighttpd.conf`. By default it should produce a working test page.

To check your `lighttpd.conf` for bugs you can use this command (helps finding misconfigurations very quickly):

    $ lighttpd -tt -f /etc/lighttpd/lighttpd.conf

The default configuration file specifies `/srv/http/` as the document directory served. To test the installation, create a dummy file:

    /srv/http/index.html

    Hello world!

Then start/enable the `lighttpd.service` and point your browser to `localhost`, where you should see the test page.

Example configuration files are available in `/usr/share/doc/lighttpd/`.

#### Basic logging

lighttpd can write out both errors and access to log files. The error log is enabled by default (controlled by the `server.errorlog` option). To enable the access log, edit `/etc/lighttpd/lighttpd.conf` as follows:

    server.modules += (
       "mod_accesslog",
    )

    accesslog.filename = "/var/log/lighttpd/access.log"

#### Enabling HTTPS

Warning Users planning to implement SSL/TLS should know that some variations and implementations are vulnerable to attacks. See the OpenSSL article for details.
Tip

- Mozilla has an SSL configuration generator that can be used with lighttpd.
- After setting up SSL, you can use Qualys SSL Labs SSL Server Check to check your configuration.

##### Self-signed certificate

Self-signed certificates can be generated by following OpenSSL#Generate a self-signed certificate with private key in a single command.

Create the `/etc/lighttpd/certs` directory and move the key and certificate files there.

    # mkdir -m0700 /etc/lighttpd/certs/

Modify `/etc/lighttpd/lighttpd.conf` adding the following lines to enable HTTPS:

    server.modules += ( "mod_openssl" )

    $SERVER["socket"] == ":443" {
       ssl.engine                  = "enable"
       ssl.privkey                 = "/etc/lighttpd/certs/key_filename"
       ssl.pemfile                 = "/etc/lighttpd/certs/cert_filename"
    }

See lighttpd TLS configuration for details.

##### Let's Encrypt

Alternatively, acquire a certificate signed from Let's Encrypt.

Edit `/etc/lighttpd/lighttpd.conf` by adding the following lines:

    $SERVER["socket"] == ":443" {
        ssl.engine                  = "enable"
        ssl.privkey                 = "/etc/letsencrypt/live/domain/privkey.pem"
        ssl.pemfile                 = "/etc/letsencrypt/live/domain/fullchain.pem"
    }

See bootstrap Let's Encrypt in the lighttpd documentation for details.

#### Redirect HTTP requests to HTTPS

You should add `"mod_redirect"` in server.modules array in `/etc/lighttpd/lighttpd.conf`:

    server.modules += ( "mod_redirect" )

    $HTTP["scheme"] == "http" {
      url.redirect = ("" => "https://${url.authority}${url.path}${qsa}")
    }

    $SERVER["socket"] == ":443" {
      ssl.engine = "enable"
      ssl.pemfile = "/etc/lighttpd/certs/server.pem"
      server.document-root = "..."
    }

To redirect all hosts for part of the site (e.g. secure or phpmyadmin):

    $HTTP["url"] =~ "^/secure" {
      $HTTP["scheme"] == "http" {
        url.redirect = ("" => "https://${url.authority}${url.path}${qsa}")
      }
    }

#### Password protecting a directory

A passwd file which is lighttpd's equivalent to the system's `/etc/passwd` is needed for user authentication. The setup requires a specific format and md5sum hashed password but users can quickly and easily create an entry using the following as an example:

    $ user=foo
    $ password=b@R102
    $ realm='Password Required'
    $ hash=`echo -n "$user:$realm:$password" | md5sum | cut -b -32`

    # echo "$user:$realm:$hash" >> /etc/lighttpd/lighttpd.user

Modify `/etc/lighttpd/lighttpd.conf` adding the following lines to enable the directory protection:

    server.modules += ( "mod_auth", "mod_authn_file" )

    auth.backend = "htdigest"
    auth.backend.htdigest.userfile = "/etc/lighttpd/lighttpd.user"

    # note this entry is relative to the server.document-root
    auth.require = ( "/secret" =>
       (
        "method" => "basic",
        "realm" => "Password Required",
        "require" => "valid-user"
       )
    )

Note The realm entered into `/etc/lighttpd/lighttpd.conf` must match the value chosen in `/etc/lighttpd/lighttpd.user` for authentication to work.

#### Block AI crawlers

Insert this into your configuration, ideally after retrieving an up-to-date match for known AI crawlers from the ai.robots.txt project. This will filter out some old browsers (likely bots) and any useragent claiming to be a browser but not supporting modern browser HTTP headers. Non-browser useragents like curl/wget are allowed.

    # Regex for URLs that are always allowed
    var.allowURLs = "^(/robots\.txt|/favicon\.ico|/\.well-known/)"
    # Allow bots that declare themselves as such
    var.allowBotUA = "(?i)bot|spider|crawl"
    # Block old browsers (Chrome/Firefox < 100, Opera < 15, MSIE, Safari < 15)
    var.oldUA = "(?:Chrome|Firefox)/\d\d?\.| Presto/| Trident/| MSIE |Version/(?:[1-9]|1[0-4])\..{1,20} Safari/"
    # Block iPhone/iPad useragents with a non-iOS-version of Safari
    var.fakeAppleUA = "(?:iPhone|iPad; CPU) OS (?!18_[67])(\d+).{0,200}Version/(?!\1)"
    # Browser-like useragents
    var.browserUA = "(?:Chrome|Firefox|Safari|WebKit)/\d"

    $HTTP["url"] !~ allowURLs {

      # Paste the $HTTP["useragent"] match from this URL here (regularly updated):
      # https://raw.githubusercontent.com/ai-robots-txt/ai.robots.txt/refs/heads/main/lighttpd-block-ai-bots.conf

      $HTTP["useragent"] !~ allowBotUA {
        $HTTP["useragent"] =~ oldUA {
          url.access-deny = ( "" )
        }
        else $HTTP["useragent"] =~ fakeAppleUA {
          url.access-deny = ( "" )
        }
        else $HTTP["useragent"] =~ browserUA {
          $HTTP["language"] == "" {
            url.access-deny = ( "" )
          }
          else $REQUEST_HEADER["Accept-Encoding"] !~ "(br|deflate)(,|$)" {
            url.access-deny = ( "" )
          }
          else {
            # https://blog.sicuranext.com/sec-fetch-and-client-hints-a-powerful-tool-against-automation/
            $REQUEST_HEADER["Sec-Fetch-Dest"] == "" {
              $HTTP["useragent"] !~ "(Android| Version/15\.)" {
                url.access-deny = ( "" )
              }
            }
            $REQUEST_HEADER["Sec-Ch-Ua-Platform"] == "\"Windows\"" {
              $HTTP["useragent"] !~ "Win" {
                url.access-deny = ( "" )
              }
            }
            else $REQUEST_HEADER["Sec-Ch-Ua-Platform"] == "\"macOS\"" {
              $HTTP["useragent"] !~ "[Mm]ac" {
                url.access-deny = ( "" )
              }
            }
            else $REQUEST_HEADER["Sec-Ch-Ua-Platform"] == "\"Linux\"" {
              $HTTP["useragent"] !~ "Linux" {
                url.access-deny = ( "" )
              }
            }
            else $REQUEST_HEADER["Sec-Ch-Ua-Platform"] == "\"Android\"" {
              $HTTP["useragent"] !~ "Android" {
                url.access-deny = ( "" )
              }
            }
          }
        }
      }
    }

You can use the `server.error-handler` directive to show users a custom error page, or replace `url.access-deny = ( "" )` with `url.rewrite-once = ( "" => "/blocked.html" )` . Your custom error page could include an option to set a cookie if the user is human, and disable the block by appending:

    $HTTP["cookie"] =~ "human=true" {
      url.access-deny = ()
      url.rewrite-once = ()
    }

### CGI

Common Gateway Interface (CGI) scripts just need to enable the CGI module; include the configuration file and make sure your chosen programming language interpreter is installed. (i.e. for python you would install python)

Create the file `/etc/lighttpd/conf.d/cgi.conf` and add the following to it:

    server.modules += ( "mod_cgi" )

    cgi.assign                 = ( ".pl"  => "/usr/bin/perl",
                                   ".cgi" => "/usr/bin/perl",
                                   ".rb"  => "/usr/bin/ruby",
                                   ".erb" => "/usr/bin/eruby",
                                   ".py"  => "/usr/bin/python",
                                   ".php" => "/usr/bin/php-cgi" )

    index-file.names           +=( "index.pl",   "default.pl",
                                   "index.rb",   "default.rb",
                                   "index.erb",  "default.erb",
                                   "index.py",   "default.py",
                                   "index.php",  "default.php" )

For PHP scripts, you will need to make sure the following is set in `/etc/php/php.ini`

    cgi.fix_pathinfo = 1

In your lighttpd configuration file, `/etc/lighttpd/lighttpd.conf` add:

    include "conf.d/cgi.conf"

### FastCGI

Note New default user and group: Instead of group `nobody` lighttpd now runs as user/group `http` by default.

First, copy the example configuration file from `/usr/share/doc/lighttpd/config/conf.d/fastcgi.conf` to `/etc/lighttpd/conf.d`

Edit `/etc/lighttpd/conf.d/fastcgi.conf` to configure `fastcgi.server`. Examples: [1]

Then in `/etc/lighttpd/lighttpd.conf`:

    include "conf.d/fastcgi.conf"

If mod_cgi is configured, it is common to `include conf.d/fastcgi.conf` before `include conf.d/cgi.conf`

Note Remember that the order in which the modules are loaded is important. The correct order is listed in `/usr/share/doc/lighttpd/config/modules.conf`.

Reload `lighttpd.service`.

#### Ruby on Rails

The following needs adding to the configuration file, `/etc/lighttpd/conf.d/fastcgi.conf`

    server.modules += ( "mod_fastcgi" )

    index-file.names += ( "dispatch.fcgi" ) #dispatch.fcgi if rails specified

    server.error-handler-404   = "/dispatch.fcgi" #too
    fastcgi.server = (
        ".fcgi" => (
          "localhost" => (
            "socket" => "/run/lighttpd/rails-fastcgi.sock",
            "bin-path" => "/path/to/rails/application/public/dispatch.fcgi"
          )
        )
    )

#### PHP

##### Using php-cgi

Install php and php-cgi (see also PHP and LAMP).

Check that php-cgi is working `php-cgi --version`

    PHP 5.4.3 (cgi-fcgi) (built: May  8 2012 17:10:17)
    Copyright (c) 1997-2012 The PHP Group
    Zend Engine v2.4.0, Copyright (c) 1998-2012 Zend Technologies

If you get a similar output, php is installed correctly.

Create a new configuration file:

    /etc/lighttpd/conf.d/fastcgi.conf

    # Make sure to install php and php-cgi. See:
    # https://wiki.archlinux.org/index.php/Fastcgi_and_lighttpd#PHP

    server.modules += ("mod_fastcgi")

    # FCGI server
    # ===========
    #
    # Configure a FastCGI server which handles PHP requests.
    #
    index-file.names += ("index.php")
    fastcgi.server = (
        # Load-balance requests for this path...
        ".php" => (
            # ... among the following FastCGI servers. The string naming each
            # server is just a label used in the logs to identify the server.
            "localhost" => (
                "bin-path" => "/usr/bin/php-cgi",
                "socket" => "/tmp/php-fastcgi.sock",
                # breaks SCRIPT_FILENAME in a way that PHP can extract PATH_INFO
                # from it
                "broken-scriptfilename" => "enable",
                # Launch (max-procs + (max-procs * PHP_FCGI_CHILDREN)) procs, where
                # max-procs are "watchers" and the rest are "workers". See:
                # https://wiki.lighttpd.net/frequentlyaskedquestions#How-many-php-CGI-processes-will-lighttpd-spawn
                "max-procs" => "4", # default value
                "bin-environment" => (
                    "PHP_FCGI_CHILDREN" => "1" # default value
                )
            )
        )
    )

Note

- If you receive errors like `No input file found` when attempting to access .php files, there are several possible explanations. See this FAQ for more information.
- Make sure that no other module (e.g. `mod_cgi`) will try to handle the .php extension.

##### Using php-fpm

For dynamic management of PHP processes, you can install php-fpm and then start and enable `php-fpm.service`.

Note You can configure the number of servers in the pool and tweak other configuration options by editing the file `/etc/php/php-fpm.conf`. More details on php-fpm can be found on the php-fpm website. Remember that when you make changes to `/etc/php/php.ini`, you will need to restart `php-fpm.service`.

In `/etc/lighttpd/conf.d/fastcgi.conf` add:

    server.modules += ( "mod_fastcgi" )

    index-file.names += ( "index.php" )

    fastcgi.server = (
        ".php" => (
          "localhost" => (
            "socket" => "/run/php-fpm/php-fpm.sock",
            "broken-scriptfilename" => "enable"
          ))
    )

### uWSGI

In `/etc/lighttpd/lighttpd.conf` add

    server.modules += ("mod_scgi")

    $HTTP["url"] =~ "^/uwsgi/" {
        scgi.protocol = "uwsgi"
        scgi.server   = (
            "/uwsgi/foo" => ((
                "socket"            => "/path/to/socket",
                "check-local"       => "disable"
            )),
            "/uwsgi/bar" => ((
                "host"              => "127.0.0.1",
                "port"              => "8080",
                "check-local"       => "disable"
            ))
        )
    }

You can than start the uwsgi application either as a systemd unit or direct. [2] is a neat guide from digitalocean on how to setup a flask application from the scratch.

### Output compression

Copy example configuration file:

    # mkdir /etc/lighttpd/conf.d
    # cp /usr/share/doc/lighttpd/config/conf.d/deflate.conf /etc/lighttpd/conf.d/

Add following in `/etc/lighttpd/lighttpd.conf`:

    include "conf.d/deflate.conf"

Finally, reload `lighttpd.service`, and it will dynamically compress plain text and HTML content.

Note You can not do this (copy `deflate.conf`) and add a needed content in `/etc/lighttpd/lighttpd.conf` instead.

It is also possible to select the type of content that should be compressed. Modify `/etc/lighttpd/conf.d/deflate.conf` on the parameter `deflate.mimetypes`:

    deflate.mimetypes = ("text/plain", "text/html", "text/javascript", "text/css", "text/xml")

You can also create a cache directory to store compressed files:

    # mkdir /var/cache/lighttpd/compress
    # chown http:http /var/cache/lighttpd/compress

Then uncomment and modify the `deflate.cache-dir` option in `/etc/lighttpd/conf.d/deflate.conf`:

    deflate.cache-dir = "/var/cache/lighttpd/compress"

## See also

- lighttpd wiki

Category:

- Web server

lighttpd
Add topic