Configuration syntax


lighttpd configuration syntax is basic and many configurations can be expressed simply in the configuration syntax.

However, the configuration syntax is not a full programming language, nor does it pretend to be. For any complex logic, it is recommended to create a script which produces lighttpd configuration syntax as output.

BNF like notation of the basic syntax

  option   : NAME = VALUE
  merge    : NAME += VALUE
  replace  : NAME := VALUE    (replace/overwrite earlier value) (since 1.4.46)
  NAME     : modulename.key
  VALUE    : ( <string> | <integer> | <boolean> | <array> | VALUE [ + VALUE ]*)
  <string> : "text" 
  <integer>: digit+
  <boolean>: ( "enable" | "disable" )
  <array>  : "(" [ <string> "=>" ] <value> [, [ <string> "=>" ] <value> ]* ")" 
  INCLUDE  : "include" VALUE
  INCLUDE_SHELL : "include_shell" STRING_VALUE


  # default document-root
  server.document-root = "/var/www/" 

  # TCP port
  server.port = 80

  # selecting modules
  server.modules = ( "mod_access", "mod_rewrite" )

  # variables, computed when config is read.
  var.mymodule = "foo" 
  server.modules += ( "mod_" + var.mymodule )
  # var.PID is initialised to the pid of lighttpd before config is parsed

  # include, relative to dirname of main config file
  include "mime.types.conf" 

  # read configuration from output of a command
  include_shell "/usr/local/bin/ /etc/mime.types" 

Conditional Configuration

Most options can be configured conditionally by using the following syntax (including nesting).

  <field> <operator> <value> {
    <field> <operator> <value> {
      ... nesting: match only when parent match
  else <field> <operator> <value> {
    ... the "else if" block
  else { # (since 1.4.46)
    ... the "else" block

where <field> is one of one of the following:

Field name Description
$REQUEST_HEADER["..."] (since 1.4.46) match on arbitrary HTTP request header (case-insensitive)
$HTTP["request-method"] (Introduced in version 1.4.19) match on the request method.
$HTTP["scheme"] (Introduced in version 1.4.19) match on the scheme used by the incoming connection. This is either "http" or "https".
$HTTP["host"] match on host
$HTTP["url"] match on url path (not including host or query-string)
$HTTP["querystring"] match on querystring, eg, after the ? in this type url: index.php?module=images..
$HTTP["remoteip"] match on the remote IP or a remote Network (Warning: doesn't work with IPv6 enabled)
$HTTP["cookie"] (subsumed by $REQUEST_HEADER["Cookie"] since 1.4.46) match on Cookie
$HTTP["useragent"] (subsumed by $REQUEST_HEADER["User-Agent"] since 1.4.46) match on User-Agent
$HTTP["language"] (subsumed by $REQUEST_HEADER["Accept-Language"] since 1.4.46) (since 1.4.21) match on Accept-Language
$HTTP["referer"] (subsumed by $REQUEST_HEADER["Referer"] since 1.4.46) match on Referer
$SERVER["socket"] match on socket. Only equal match (==) is supported. Value must be on the format "ip:port", where ip is an IP address(optional) and port a port number. If IP address is omitted, then use INADDR_ANY (, unless server.use-ipv6 = "enable" inside this block, in which case use in6addr_any ([::]). Setting this directive also binds the daemon to this socket. Use this if you want to do IP/port-based virtual hosts.
$PHYSICAL["path"] (Introduced in version 1.5.0 (note: abandoned; never released)) - match on the mapped physical path of the file / cgi script to be served.
$PHYSICAL["existing-path"] (Introduced in version 1.5.0 (note: abandoned; never released)) - match on the mapped physical path of the file / cgi script to be served only if such a file exists on the local filesystem.

<operator> is one of:

Operator Value
== string equal match
!= string not equal match
=~ perl style regular expression match
!~ perl style regular expression not match

and <value> is either a quoted ("") literal string or regular expression.


  # disable directory-listings for /download/*
  dir-listing.activate = "enable" 
  $HTTP["url"] =~ "^/download/" {
    dir-listing.activate = "disable" 

  # handle virtual hosting
  # map all domains of a top-level-domain to a single document-root
  $HTTP["host"] =~ "(^|\.)example\.org$" {
    server.document-root = "/var/www/htdocs/" 

  # multiple sockets
  $SERVER["socket"] == "" {
    server.document-root = "..." 

  $SERVER["socket"] == "" {
    ssl.pemfile = "/var/www/certs/localhost.pem" 
    ssl.engine = "enable" 

    server.document-root = "/var/www/htdocs/" 

  # deny access for all googlebot
  $HTTP["useragent"] =~ "Google" {
    url.access-deny = ( "" )

  # deny access for all image stealers (anti-hotlinking for images)
  $HTTP["referer"] !~ "^($|http://www\.example\.org)" {
    url.access-deny = ( ".jpg", ".jpeg", ".png" )

  # deny the access to to all user which 
  # are not in the network
  $HTTP["host"] == "" {
    $HTTP["remoteip"] != "" {
     url.access-deny = ( "" )

  # Allow only and to
  # have access to
  $HTTP["host"] == "" {
    #!~ is a perl style regular expression not match
    $HTTP["remoteip"] !~ "^(200\.19\.1\.5|210\.45\.2\.7)$" {
      $HTTP["url"] =~ "^/admin/" {
        url.access-deny = ( "" )

Conditional Configuration Merging

lighttpd configuration is parsed and optimized at startup. The configuration is static after startup.

At runtime, dynamic configuration selection is limited to matching the lighttpd condition syntax and to matching the static configuration, e.g. matching against static lists parsed at startup.

Put another way, various configurations objects are static after startup, including backend server configuration. When parsing requests at runtime, a backend server may be selected, but the configuration of the backend is static after startup.

Different sections of the configuration are not merged dynamically at runtime. For a given option, the value of that option in the last matching condition is the value that is applied. Within the same lighttpd condition { ... } and same nesting level of { ... }, you can use +=, which is parsed at startup, but += does not apply across different lighttpd conditions { ... } or different nesting levels { ... } within a condition.


If you're not running on the default port, $HTTP["host"] will have the port appended to it, so regular expressions ending in $ (without allowing for a port) won't match.
To match with or without a port, change


Note that some earlier versions of lighttpd do not support the full configuration file syntax listed here. In particular, some versions do not support "var." variables, appending with "+=", nested conditionals, or "else" blocks. The names of some options (for example, "server.dir-listing") have also changed (i.e. to "dir-listing.activate") between versions of lighttpd.

If you're having trouble configuring lighttpd, consider using the "-t" or "-p" options to debug your configuration. Note that some earlier versions of lighttpd not support the "-t" or "-p" options.

Advanced usage

Check the blog:

Using variables

You can set your own variables in the configuration to simplify your config.

Note: Variables are expanded at startup when the configuration is parsed; variables are not expanded at runtime for each request.

  var.basedir = "/home/www/servers/" 
  $HTTP["host"] == "" { = "" 
     include "incl-base.conf" 

In incl-base.conf:

  server.document-root = basedir + + "/pages/" 
  accesslog.filename   = basedir + + "/logs/access.log" 

You can also use environment variables or the default variables var.PID and var.CWD.

  var.basedir = env.LIGHTTPDBASE

  $HTTP["host"] == "" { = "" 
     include "incl-base.conf" 
     include "incl-fastcgi.conf" 

In incl-fastcgi.conf:

  fastcgi.server = ( ... => ((
     "socket" => basedir + + "/tmp/fastcgi-" + PID + ".sock" 
  )) )

Or like the lighttpd script for rails does:

  var.basedir = var.CWD
  server.document-root = basedir + "/public/" 

Some useful things that can NOT be done in lighttpd config (you need to create a script in a real programming language and then use include_shell):

  # testing if a variable has been set is NOT possible
  var.not_sure_if_it_exists == undefined { ... set to default value ... }

  # removing from arrays is NOT possible
  server.modules -= ( "mod_idontwantyou" )

Global context

  global {

You don't need it in the main configuration file.
But you might have difficulty setting a server wide configuration inside a included-file from conditionals.


In lighttpd.conf:

  server.modules = ()
  $HTTP["host"] == "" {
    include "incl-php.conf" 

In incl-php.conf:

  global {
    server.modules += ("mod_fastcgi")
    static-file.exclude-extensions += (".php")
  fastcgi.server = "..." 


All Configuration Options can be found at: Configuration Options

Updated by gstrauss about 1 month ago · 51 revisions