Project

General

Profile

Actions

Conditional Request Headers

Module: mod_setenv

Description

mod_setenv modifies request headers (from clients), response headers (to clients), and the environment (for CGI).

Note: mod_setenv needs to be listed prior to mod_redirect in the server.modules list in lighttpd.conf so that mod_setenv can set headers prior to the redirect. (Listing modules alphabetically is a common mistake. e.g. #2946)

To set "Cache-Control" and "Expires" caching response headers, prefer mod_expire instead of mod_setenv.
To set "Content-Encoding", prefer mod_deflate or mod_compress

To use mod_setenv: server.modules += ( "mod_setenv" )

Options

setenv.add-response-header
Adds a header to the HTTP response sent to the client:

setenv.add-response-header = ("My-Custom-Header" => "my-custom-value")

setenv.add-request-header
Adds a header to the HTTP request that was received from the client:

setenv.add-request-header = ("X-Proxy" => "my.server.name")

setenv.add-environment
Adds a value to the process environment (aka environment variables) that is passed to the external applications:

setenv.add-environment = ( 
  "TRAC_ENV" => "lighttpd",
  "RAILS_ENV" => "production" 
)

setenv.set-request-header (since 1.4.46)
setenv.set-response-header (since 1.4.46)
setenv.set-environment (since 1.4.46)
These directives set the given values, rather than appending the given values to the headers or environment. These directives take precedence over the setenv.add-* counterparts. Set a blank value for request or response header to cause the header to be removed.

HTTP Strict Transport Security (HSTS)

A typical HSTS configuration sets max-age to 365 days (31536000 seconds). If testing, please use a shorter max-age (e.g. max-age=600) until you are more confident with your configuration. Do not append ; preload to the header value unless you understand the consequences.

setenv.set-response-header = ("Strict-Transport-Security" => "max-age=31536000; includeSubDomains")

See also "Using setenv in multiple configuration conditions" below for setting HSTS along with other setenv directives.

Using setenv in multiple configuration conditions

The way that lighttpd processes its configuration syntax may not be intuitive to some, but the results must be deterministic. lighttpd parses its configuration at startup. lighttpd does not merge lists from multiple matching conditions. For each specific configuration directive, the last condition that matches a client request and contains that specific directive is the configuration used for that specific directive for that client request. setenv-add-response-header and setenv-set-response-header are distinct configuration directives.

For example: a request for "/abc/def/ghi" will match all three conditions, and even though the directive is setenv-add-response-header, only the last one will be used for the request, adding the response header "Custom-Header: value-C"

$HTTP["url"] =~ "^/" {
    setenv.add-response-header = ("Custom-Header" => "value-A")
}
$HTTP["url"] =~ "^/abc/" {
    setenv.add-response-header = ("Custom-Header" => "value-B")
}
$HTTP["url"] =~ "^/abc/def/" {
    setenv.add-response-header = ("Custom-Header" => "value-C")
}

Order matters. The order in which you write the configuration matters. For the same request for "/abc/def/ghi" but with the configuration directives listed in a different order, again, the last matching condition will be used for the request, in this case adding the response header "Custom-Header: value-A"

$HTTP["url"] =~ "^/abc/def/" {
    setenv.add-response-header = ("Custom-Header" => "value-C")
}
$HTTP["url"] =~ "^/abc/" {
    setenv.add-response-header = ("Custom-Header" => "value-B")
}
$HTTP["url"] =~ "^/" {
    setenv.add-response-header = ("Custom-Header" => "value-A")
}

The same is true for +=. The += applies only to the list within the current scope, within the current configuration condition. The += does not have an effect across different configuration conditions. For the same request for "/abc/def/ghi" but with the configuration directives listed below, again, the last matching condition will be used for the request, in this case adding the response headers "Custom-Header1: value-C" and "Custom-Header2: value-C"

$HTTP["url"] =~ "^/" {
    setenv.add-response-header = ("Custom-Header1" => "value-A")
    setenv.add-response-header+= ("Custom-Header2" => "value-A")
}
$HTTP["url"] =~ "^/abc/" {
    setenv.add-response-header = ("Custom-Header1" => "value-B")
    setenv.add-response-header+= ("Custom-Header2" => "value-B")
}
$HTTP["url"] =~ "^/abc/def/" {
    setenv.add-response-header = ("Custom-Header1" => "value-C")
    setenv.add-response-header+= ("Custom-Header2" => "value-C")
}

The following is one method to define a setenv set of policy headers into a variable and to reuse the set:

var.response_header_policy = (
  #"Strict-Transport-Security" => "max-age=31536000; includeSubDomains", # preferred for sites to designate HSTS
  "Strict-Transport-Security" => "max-age=300; includeSubDomains",       # minimize damage for those who ignorantly cut-n-paste
  "Content-Security-Policy" => "default-src https:" 
  "X-Frame-Options" => "SAMEORIGIN",
  "X-Content-Type-Options" => "nosniff",
  "X-Xss-Protection" => "1; mode=block" 
)

$HTTP["url"] =~ "^/" {
    setenv.set-response-header = var.response_header_policy
    setenv.set-response-header+= ("Custom-Header" => "value-A")
}
$HTTP["url"] =~ "^/abc/" {
    setenv.set-response-header = var.response_header_policy
    setenv.set-response-header+= ("Custom-Header" => "value-B")
}
$HTTP["url"] =~ "^/abc/def/" {
    setenv.set-response-header = var.response_header_policy
    setenv.set-response-header+= ("Custom-Header" => "value-C")
}

Some policy response headers should be sent in all responses, but some need not be sent in all responses, e.g. for images, scripts, stylesheets, etc. You might save some bandwidth by omitting them. Reference Scott Helme's: Micro-optimisation for fun!

Automatic Decompression

If you have a lot text-files compressed with gzip on disk and want the browser to decompress them on retrieval, you can use setenv to inject the Content-Encoding header, but should not do so unless all of your clients support Accept-Encoding: gzip. You should instead prefer mod_compress, and pre-fill the mod_compress cache location with compressed content.

  $HTTP["url"] =~ "(README|ChangeLog|\.txt)\.gz$" {
    setenv.add-response-header  = ( "Content-Encoding" => "gzip")
    mimetype.assign = ("" => "text/plain" )
  }

Updated by gstrauss 3 months ago · 21 revisions