简介

运行 lighttpd2

lighttpd 需要两个配置文件,通常位于以下两个位置

源码中的 contrib/ 目录包含示例配置文件。

然后使用以下命令启动 lighttpd2

/usr/sbin/lighttpd2 -c /etc/lighttpd2/angel.conf

此进程不会fork到后台,如果您需要,则必须自行操作。
我们推荐的 lighttpd2 运行方式是 runit (请查看 contrib/service 目录)。

主配置文件

每个 Web 服务器的核心都是配置文件。它控制着所有的行为,因此必须强大,同时又要足够简单,以便轻松获得所需的结果。
在 lighttpd 配置中,您控制它如何响应请求。为了实现这一点,您必须表达某种逻辑——就像在编程语言中一样。

基本语法

lighttpd 2.0 配置文件的语法与各种编程语言有些相似——一种混合体。但别害怕,它真的非常简单。不涉及指针 :)
基本块是变量函数调用条件

布尔值

有两个布尔值

  • true
  • false

整数

整数存储为带符号的 64 位整数(最大值约为 9 * 10^18)。有三种基本使用方式

  • 十进制整数:以任何非零数字开头,如 128
  • 八进制整数:以零开头,如 0644
  • 十六进制整数:以 0x 开头,如 0xff

这三种都可以带一个后缀,表示一个乘数因子

  • byte: 1
  • kbyte: 1024
  • mbyte: 1024*1024
  • gbyte: 1024*1024*1024
  • tbyte: 1024*1024*1024*1024
  • pbyte: 1024*1024*1024*1024*1024
  • bit: 1 / 8
  • kbit: 1024 / 8
  • mbit: 1024*1024 / 8
  • gbit: 1024*1024*1024 / 8
  • tbit: 1024*1024*1024*1024 / 8
  • pbit: 1024*1024*1024*1024*1024 / 8
  • sec: 1
  • min: 60
  • hours: 3600
  • days: 24*3600

对于大小,基本单位是字节,对于时间间隔,基本单位是秒。

字符串

有 4 种方式指定字符串

  • 'hello world'
  • "hello world"
  • e'hello world'
  • e"hello world"

基本转义规则两者相同

  • "\n" 是换行符,"\r" 是回车符,"\t" 是制表符
  • "\\" 是一个 \"\"" 是一个双引号 ""\'" 是一个单引号 '
  • 如果符号未用于终止字符串,则转义单引号/双引号是可选的,即 '\"' = '"'"\'" = "'"
  • "\xNN": NN 必须是十六进制字符,字符串将被替换为解码后的 8 位值,作为单个字节
  • 所有其他 \ 出现次数都**不**从字符串中移除。

e'..'e"..." 变体不允许出现最后一种情况。

允许所有其他字符(字符串解析为 8 位二进制;lighttpd2 通常不关心编码)。

列表

列表是其他值的有序集合

  • [1, true, "foo"] (简单列表)
  • [] (空列表)
  • [1] (含一个元素的列表)
  • [[1,2],[3,4],5] (嵌套列表)
  • [1,2,] (最后一个值也可以有尾随 ,)
  • (1, 2, 3) (具有多个元素的替代括号)

请注意 (1) 不是列表;括号也可以用于分组表达式,如 1*(2+3),因此建议只使用 [] 来指定列表。

键值列表

键值列表将键与值关联(两者可以是任何类型);语法是

  • [ "a" => 1, "b" => 10 ]

与普通列表一样,最后一个值也可以有尾随的 ,。您不能在一个列表中混合简单值和键值关联(嵌套它们可以)。

key => value 运算符也只是 [key, value] 列表的语法糖,上面的例子与

  • [ [a, 1], [b, 10] ]

这尤其意味着键值列表也是有序的,尽管它们可以在某些函数调用内部被转换为哈希表。

表达式

有一些可用于某些值类型的运算符

  • 对于整数:+-*/
  • 对于字符串:+(连接两个字符串)
  • 对于列表:+(追加列表)

您还可以将字符串和布尔值转换为整数,并将任何值转换为字符串

  • cast(int) "256"(仅支持十进制表示,不支持上述后缀)
  • cast(int) truetrue 映射到 1false 映射到 0
  • cast(string) 5

表达式可以分组以覆盖默认关联

  • 3 * (1 + 2) vs. 3 * 1 + 2

动作块

一个动作块由一个函数调用列表(在动作上下文中)和条件语句组成;它被视为一个值,即可以赋值给变量并在函数调用中用作参数。

动作块也可以包含变量赋值和设置块/函数调用,这些不属于“动作块值”本身,但在解析配置时进行评估。

语法是

{ log "hello world"; if req.path =$ ".hidden" { static; } }

完整的配置也是一个动作块(但没有周围的花括号);条件语句也使用动作块作为其分支。

每个非条件分支的动作块都会启动一个新的嵌套变量作用域;

变量

变量名以字母字符(a-zA-Z)或下划线 _ 开头,后跟字母数字字符、下划线 _ 和点 .;关键字不允许作为变量名。

变量存储值,并且名称可以代替实际值使用;后续对变量的修改对之前的用法没有影响(即只在**解析**配置时进行评估)。

变量使用 = 赋值(以 ; 结尾)

my_types = [".txt" => "text/html"]; php = { if phys.path =$ ".php" { fastcgi "unix:/var/run/lighttpd/php.sock"; } };

默认情况下,变量赋值会覆盖现有变量(在其先前作用域中),如果变量不存在,则在本地作用域中创建新变量(即,它将仅在当前作用域和嵌套后代中可用)。

您可以通过在赋值前加上 local 来显式地在本地作用域中创建新变量(隐藏父作用域中同名变量)

local wwwpath = "/var/www/example.com";

您还可以通过在赋值前加上 global 来在全局作用域中创建变量。
主配置文件已经处于嵌套作用域中(即**不是**全局作用域)。全局作用域在配置加载后不会被销毁,将来可以在延迟配置加载(例如从 SQL)中使用。

如果变量名在上下文中被使用,它将始终使用最近作用域中的定义。

示例

本例说明了变量在解析配置时进行评估。

foo = "bar";
if req.path == "/somepath" {
	foo = "baz";
}

# at this point foo will ALWAYS contain "baz" no matter if "/somepath" was requested or not

示例

此示例说明了作用域。

foo = "bar";
php = {
	local foo = "baz";
	# in this block (and nested blocks within) foo is now "baz"
	# ...
};
# foo is now "bar" again

特殊变量

sys.* 变量是只读的。目前有以下 sys.* 变量可用

  • sys.pid: lighttpd 的进程 ID
  • sys.cwd: 当前工作目录
  • sys.env.X: 名称为 X 的系统环境变量(对于任何 X

函数调用

函数调用分为三种类型

  • 动作
  • 设置
  • 选项

动作只能在动作(块)上下文中使用,设置只能在设置(块)上下文中使用,选项两者皆可。

设置上下文以关键字 setup 开头,后跟单个设置函数调用或设置块。

设置函数调用在发生时立即运行(它们用于“设置”Web 服务器环境,如监听 TCP 套接字和设置默认选项),而动作函数调用则针对每个请求运行(将请求 URL 映射到物理路径、处理请求、修改默认选项)。

动作、设置和选项由模块提供。

包含

包含的语法与函数调用相似,但它们由配置解析器直接处理。它们只允许在动作上下文中,因为它们在被使用的地方插入一个对动作块的引用。

包含文件有三种类型

  • include "/etc/lighttpd/vhosts/*.conf";: 包含文件,就像主配置文件本身一样;路径可以包含通配符
  • include_shell "/etc/lighttpd/config_generator.sh";: 运行指定的命令,并将其输出解析为配置文件
  • include_lua "/etc/lighttpd/complex.lua": 包含一个 Lua 配置文件。要执行的单个动作必须在全局 actions 变量中返回(或留空不执行任何操作)。另请参阅 lua.handler

包含也会创建一个新的嵌套作用域。

调试打印

与 includes 类似,__print 是一个特殊函数,但在动作和设置上下文中都可用。它以“debug”日志级别记录其参数的字符串值。

条件

条件(Lighttpd 1.x 中已知)等同于大多数编程语言中的“if”。也有“else”和“elseif”的等价物。
它们通过对条件变量和在运行时(针对每个请求)评估的值进行比较来创建。
条件可以嵌套,您可以使用 andor 运算符将它们分组。andor 绑定更强,尽管更倾向于使用括号将它们分组。

示例

if req.host == "mydomain.tld" {
	if req.path == "/" or req.path == "/index.html" {
		static;
	} else if req.path == "/upload" {
		if req.content_length > 100mbyte {
			access.deny;
		} else {
			proxy "127.0.0.1:8080";
		}
	}
}

语法

基本语法形式是

  • if <expr> { ... }
  • if <expr> { ... } else { ... }
  • if <expr> { ... } else if <expr2> { ... }
  • if <expr> { ... } else if <expr2> { ... } ... (继续使用 elseelse if)

条件表达式 <expr>

  • (<expr>)
  • <expr1> and <expr2>
  • <expr1> or <expr1> (<expr1> and <expr2> or <expr3> = (<expr1> and <expr2>) or <expr3>; and 具有更高的优先级)
  • <condvar> <op> <value>,其中 <condvar> 是条件变量(类型与布尔值不同),<op> 是条件运算符,<value> 是字符串或数字。
  • <condvar>!<condvar> 用于布尔条件变量。

条件变量

条件变量分为三类

  • request.xyz(可缩写为 req.xyz)
  • physical.xyz(可缩写为 phys.xyz)
  • response.xyz(可缩写为 resp.xyz)
变量 描述
request.localip 监听套接字的 IP 地址,客户端连接到的(unix 套接字的文件名)
request.localport 监听套接字的端口号,unix 套接字为 -1
request.remoteip 客户端的 IP 地址
request.remoteport 客户端的端口号,unix 套接字为 -1
request.path 请求 URL 的路径部分。不包括查询字符串。
request.raw_path 请求 URL 的原始路径(未进行 URL 解码,未简化),包括查询字符串。
request.host 请求的主机名
request.scheme 请求方案。“http”或“https”
request.query 请求 URL 的查询字符串
request.method 请求方法。“GET”、“POST”、“HEAD”等。
request.length 整数。内容长度,例如 POST 方法
request.header[“name”] 请求头name,例如 request.header[“referer”]
request.is_handled 布尔条件,请求是否已由处理程序处理(static, fastcgi..)
request.environment[“name”] (或简称 request.env[“name”])CGI 环境
physical.path 要提供服务的文件的物理路径。例如,文档根目录 + 路径
physical.exists 布尔条件,指示请求的文件(普通文件、目录甚至特殊文件)是否存在
physical.size 整数。请求文件的大小。如果文件不存在则为 -1
physical.is_dir 布尔条件,指示请求的文件是否为目录
physical.is_file 布尔条件,指示请求的文件是否为普通文件(例如,非 Unix 套接字等)
physical.docroot 文档根目录
physical.pathinfo 路径信息
response.status 响应状态码(阻止请求直到响应头可用)
response.header[“name”] 响应头(阻止请求直到响应头可用)

条件运算符

op 描述 op 描述
== 比较两个值是否相等 != 负数 ==
<= 小于或等于 < 小于
>= 大于或等于 > 大于
=~ 正则表达式匹配 !~ 负数 =~
=^ 前缀匹配 !^ 负数 =^
=$ 后缀匹配 !$ 负数 =$
=/ CIDR 匹配 !/ 负数 =/

Angel 配置

lighttpd2 由两个主要二进制文件组成:天使 (lighttpd2) 和工作进程 (lighttpd2-worker)。主配置文件由工作进程使用,本章描述了天使的配置。
标准发行版应在 /etc/lighttpd2/angel.conf 中安装一个 Angel 配置,其中包含合理的默认值,适用于大多数基本设置。

Angel 概念

您可以不带 Angel 启动工作进程,但 Angel 提供了一些有用的功能

  • Angel 本身通常以 root 身份运行(例如绑定到特权端口所需),但会以降低的权限(通常使用 www-data 等用户)启动工作进程。工作进程本身不进行任何权限降低。
  • Angel 可以为工作进程以 root 权限打开/创建日志文件
  • Angel 支持工作进程的优雅重启以重新加载配置:将启动一个新实例,如果它成功启动(检查配置等),它将替换旧实例。旧实例将完成剩余的请求。
    由于 Angel 负责创建监听网络套接字,它可以始终保持它们打开,并且不会丢失任何请求。
  • Angel 还进行简单的监督:如果工作进程崩溃,Angel 会重新启动它。

配置项

配置语法与主配置文件非常相似,尽管它没有动作块、设置块、条件和作用域。

用户

放弃特权以启动工作进程

user username;
用户名
启动工作进程时要放弃特权的用户名称

此项只能指定一次;如果未指定,则根本不会放弃特权,这在 Angel 本身不以 root 身份运行时很有用。不言而喻,您绝不应以 root 身份运行工作进程。
用户名还用于查找用户所属的所有组。

示例

user "www-data";

放弃特权以启动工作进程

group groupname;
组名
启动工作进程时要放弃特权的组名称

指定要放弃特权的主组;一个进程可以有多个组,其他组由 user 指定的用户所属的组给出。
默认是 user 指定用户的主组,或者根本不放弃特权。

示例

group "www-data";

二进制文件

指定工作二进制文件的路径

binary path;
路径
lighttpd2-worker 二进制文件的路径

此项仅在您根本未安装二进制文件时才需要(用于测试)。

示例

binary "/home/source/lighttpd2/autobuild/src/main/lighttpd2-worker";

配置

指定主配置文件的路径

config path;
路径
主配置文件的路径

默认使用 /etc/lighttpd2/lighttpd.conf

示例

config "/etc/lighttpd2-test/lighttpd.conf";

Lua 配置

指定 Lua 配置文件的路径

luaconfig path;
路径
Lua 配置文件的路径

默认使用普通配置文件;您必须使用普通配置文件或 Lua 配置文件。

示例

luaconfig "/etc/lighttpd2/lighttpd.lua";

模块路径

指定包含工作进程模块的目录路径

modules_path path;
路径
包含工作进程模块的目录路径

此项仅在您根本未安装二进制文件时才需要(用于测试)。对于自动工具构建,“实际”模块二进制文件位于 .libs 子目录中。

示例

modules_path "/home/source/lighttpd2/autobuild/src/modules/.libs";

包装器

在工作进程命令前添加其他命令

wrapper wrappers;
包装器
包装器命令及其参数的路径

此项将所有给定字符串附加到命令前缀列表(该列表最初为空)。在启动工作进程之前,工作进程的二进制路径及其参数(配置、模块路径)将被附加。
包装器可用于通过 valgrind、strace 等工具运行工作进程。

示例

# in multiple lines
wrapper [ "/usr/bin/valgrind" ];
wrapper [ "--leak-check=full", "--show-reachable=yes" ]
wrapper [ "--leak-resolution=high" ];

# or as one
wrapper [ "/usr/bin/valgrind", "--leak-check=full", "--show-reachable=yes", "--leak-resolution=high" ];

环境变量

为工作进程添加环境变量

env vars;
变量
要为工作进程添加的环境变量列表

追加给定的环境变量列表(最初为空),可以是 "var=xyz" 形式的字符串,也可以是键值对 "var" => "xyz"(键不能包含任何 =)。

示例

# helps debugging with valgrind:
env [ "G_SLICE=always-malloc", "G_DEBUG=gc-friendly,fatal_criticals" ];

复制环境变量

从当前环境复制环境变量到工作进程

copy_env varnames;
变量名
要复制的环境变量名称列表

从当前环境添加变量副本。默认情况下,所有变量都将被丢弃。

示例

env_copy [ "PATH" ];

最大核心文件大小

设置工作进程核心文件大小限制

max_core_file_size limit;
限制
限制(字节)

工作进程可能创建的核心文件的最大大小,以字节为单位。核心文件在工作进程崩溃时创建。
0 禁用核心文件,默认情况下不更改限制。

最大打开文件数

设置工作进程最大打开文件数限制

max_open_files limit;
限制
最大打开文件数

工作进程根据最大打开文件数限制最大连接数(最大连接数 = 最大打开文件数 / 4)。
默认情况下不更改限制。

示例

# max 4096 connections
max_open_files 16384;

允许监听

允许工作进程监听套接字

allow_listen list;
列表
网络掩码 (CIDR) + 可选端口或 Unix 域套接字地址的列表

工作进程使用 angel 绑定 TCP/Unix 套接字;angel 检查这些绑定是否允许。如果未指定 allow_listen,则允许所有使用端口 80 或 443 的 TCP 绑定(IPv4 和 IPv6)。
IPv4 和 IPv6 使用不同的掩码(无 IPv4 到 IPv6 映射),CIDR 掩码的网络长度是可选的(默认为主机地址),端口也是可选的(如果省略则允许 80 和 443)。
格式

  • IPv4 上的 TCP: ipv4, ipv4:port, ipv4/net, ipv4/net:port
  • IPv6 上的 TCP: ipv6, ipv6/net, [ipv6], [ipv6/net], [ipv6]:port, [ipv6/net]:port
  • Unix 域: unix:/wildcard/path/to/*.socket

示例

仅允许 IPv4 和 IPv6 的 TCP 端口 8080 以及 unix 域套接字 /run/lighttpd/internal.sock

allow_listen [ "0.0.0.0/0:8080", "[::/0]:8080" ];
allow_listen "unix:/run/lighttpd/internal.sock";

模式

lighttpd 配置在各种位置(docroot、redirect、rewrite、env.set 等)支持“模式”;它们共享以下结构。

有两种“捕获”可用;一种来自动作本身(如 redirect/rewrite 中正则表达式的捕获,或 docroot 中主机名的标签),另一种来自动作栈中先前匹配的正则表达式条件。如果所选类型的捕获不存在,则值将为空字符串。

语法

模式是由以下部分组成的字符串

  • 纯文本。只在用 \ 转义时才能包含特殊字符 $ 和 % —— 请记住,\ 在配置中也必须被转义,因此您可能需要使用 \\ 来转义。您也可以转义 ?(用于 rewrite 中的特殊“split”)。
  • “%”捕获引用(先前匹配的正则表达式条件);后跟单个数字或范围(范围语法见下文)
  • “$”捕获引用(取决于动作);后跟单个数字或范围(范围语法见下文)
  • “%”引用到条件变量,例如:%{req.path};条件可以带有“enc:”前缀(%{enc:req.path}),在这种情况下,值将被 urlencoded。

范围

范围可以是单个元素 [n]n 可以有多个数字),闭合范围 [n-m],或开放范围 [n-][-m]
开放端始终替换为“G_MAXUINT”(一个非常大的正整数)。范围可以“反转”,即 n > m

现在有两种不同的范围使用方式

  • 正则表达式捕获范围:捕获将为范围中的所有值插入;如果范围反转,它将从范围中的最高索引开始。
  • 主机名中的标签范围:与第一个范围类似,但插入的标签用“.”分隔;索引 0 代表“完整主机名”,包含 0 的范围将缩减为完整主机名;标签从顶层开始编号,范围反向解释(只需查看示例,就会清楚)。

示例:简单重定向

redirect "http://%{req.host}%{req.path}?redirected=1";

示例:文档根目录

  • 对“http://example.com/project/trunk”的请求将导致 docroot “/var/www/project/trunk/htdocs”
  • 对“http://sub.example.com/”的请求将导致 docroot “/var/www/vhosts/com/sub.example”
if req.path =~ "^/project/([^/]*)" {
	docroot "/var/www/projects/%1/htdocs";
} else {
	docroot "/var/www/vhosts/$1/${2-}/htdocs";
}

正则表达式

lighttpd2 使用 GLib 的“Perl 兼容正则表达式”实现,请参阅其正则表达式语法文档。

配置格式有不同的方式提供字符串(您可以使用 '" 引号;用于引用的字符如果在字符串内部使用,则必须用 \ 转义)。
简单(标准)方式 "text" 具有以下转义规则

  • "\n" 是换行符,"\r" 是回车符,"\t" 是制表符
  • "\\" 是一个 \"\"" 是一个双引号 ""\'" 是一个单引号 '
  • 如果符号未用于终止字符串,则转义单引号/双引号是可选的,即 '\"' = '"'"\'" = "'"
  • "\xNN": NN 必须是十六进制字符,字符串将被替换为解码后的 8 位值,作为单个字节
  • 所有其他 \ 出现次数都**不**从字符串中移除。

这种方式是正则表达式的首选;只有实际匹配 \ 时才需要额外的转义("\\\\""\x5C" = "\\" 不起作用),并且 \\ 通常不会产生您想要的结果(匹配数字:"\\d" = "\d")。所有其他转义规则都与 pcre 的行为兼容。

第二种方式是在字符串前加一个 e,像这样:e"text"。它与普通字符串有相同的规则,但不允许未知的转义序列(上面最后一条规则)。要用 pcre 匹配一个数字,您必须写 e"\\d" 而不是 "\d"

Fetch API

Fetch API 为 lighttpd 模块提供了一个通用的接口,用于在数据库中查找条目。查找键和数据都是简单的(二进制)字符串。

到目前为止,只有 fetch.files_static 提供数据库,并且只有 gnutls 使用它来查找 SNI 证书。

Lua API

Lua 可以用于生成配置(类似于 include_shell 的快捷方式)或编写实际的响应处理程序。

使用 Lua 生成配置不会对性能产生任何影响;在这种情况下,Lua 只在启动时运行以生成配置,处理请求时不涉及 Lua。

由于 lua_State 本身不是线程安全的,您有两种方法使用 Lua 配置

  • include_lualua.plugin:使用全局服务器锁,但在所有工作进程中共享同一个 lua_State
  • lua_handler:无锁,每个工作进程有自己的 lua_State(它们不能共享其全局上下文)。

Lua 配置

本节描述如何将主配置中的概念转换为 Lua。您可以完全用 Lua 编写整个配置,也可以只编写部分并将其包含进来(例如使用 include_lua)。

示例 - debug.lua

以下 Lua 片段保存为“debug.lua”,例如可以使用 include_lua "debug.lua" 包含。

function mydebug(vr)
	local url_fields = { "raw", "raw_path", "raw_orig_path", "scheme", "authority", "path", "query", "host" }
	local phys_fields = { "path", "doc_root", "pathinfo" }
	if vr:handle_direct() then
		vr.resp.status = 200
		vr.resp.headers["Content-Type"] = "text/plain"
		vr.out:add("Hello World!\n\n")
		vr.out:add("http method: " .. vr.req.http_method .. "\n")
		vr.out:add("http version: " .. vr.req.http_version .. "\n")
		for k, v in vr.env:pairs() do
			vr.out:add("Env['" .. k .. "'] = '" .. v .. "'\n")
		end
		vr.out:add("\n")
		for k, v in pairs(url_fields) do
			vr.out:add("vr.req.uri['" .. v .. "'] = '" .. vr.req.uri[v] .. "'\n")
		end
		vr.out:add("\n")
		for k, v in pairs(phys_fields) do
			vr.out:add("vr.phys['" .. v .. "'] = '" .. vr.phys[v] .. "'\n")
		end
		vr.out:add("\n")
		for k, v in vr.req.headers:pairs() do
			vr.out:add("vr.req.headers['" .. k .. "'] = '" .. v .. "'\n")
		end
	end
end

actions = mydebug

  • 布尔值:Lua 直接支持 truefalse
  • 整数:Lua 有自己的数字类型(通常是 double),并且不认识任何后缀。
  • 字符串:Lua 直接支持字符串。请查阅 Lua 参考手册了解各种引用样式。
  • 列表和键值列表:Lua 有一个“table”类型;它可以包含顺序列表和关联映射。使用 {1, 2, 3} 创建简单列表,使用 {a=1, b=2} 创建唯一映射(将转换为键值列表),或使用 {{"a",1},{"a",2}} 显式创建键值列表(其中一个键可以多次使用且顺序很重要)。
    不要混合使用顺序列表和关联映射。
    如果您从 lighttpd 获取一个列表(可能是键值列表),它表示为一个顺序列表,但有一个特殊的 __index 元表方法支持字符串和 nil 作为查找参数,即您可以在 Lua 中将键值列表视为关联映射(例如,请参阅 contrib/secdownload.lua 中的选项处理)。
  • 表达式和变量就是通常的 Lua 东西;目前还没有直接访问 lighttpd 配置变量的方法。
  • 动作块:您可以使用list actionact = action.list(act1, act2))从动作列表中创建一个动作

函数调用

动作上下文通过在函数名前加上 action. 来指定,设置上下文通过在函数名前加上 setup. 来指定。不要尝试在请求处理中调用设置。

此外,每个 Lua 函数都可以作为动作(参见上面的 debug.lua 示例),将一个虚拟请求对象作为参数。

不支持包含文件,也不支持调试 __print(有其他可用的日志记录方法)。

条件

条件是最丑陋的部分:无法将原生 Lua if 语句翻译成 lighttpd 配置,因此需要手动构建它们。

只有条件变量的长名称在 Lua 中可用。条件运算符都赋予名称并附加到条件变量,然后用要比较的值调用它们。

op Lua 名称 op Lua 名称
== :eq != :ne
<= :le < :lt
>= :ge > :gt
=~ :match !~ :nomatch
=^ :prefix !^ :notprefix
=$ :suffix !$ :notsuffix
=/ :ip !/ :notip

布尔条件变量使用 :is():isnot() 调用。

此类调用的结果(一个“条件”)随后作为第一个参数传递给 action.when

示例 - 仅限管理员

if req.env["REMOTE_USER"] != "admin" { auth.deny; } 翻译为 Lua

actions = action.when(request.environment["REMOTE_USER"]:ne("admin"), action.auth.deny())

示例 - 仅物理文件

if !phys.exists { auth.deny; } 翻译为 Lua

actions = action.when(physical.exists:isnot(), action.auth.deny())

API

本节介绍了处理请求所需的对象类型;您可能会从作为处理程序参数获得的虚拟请求对象开始。

对象字段应使用 .field["field"] 访问,例如

e = vr.env e["XXX"] = "abc"

标记为 (ro) 的字段是只读的;这并不意味着字段值不能修改,只是您不能用另一个对象覆盖该字段。然而,只读字符串/数字属性确实是只读的。

使用 :method(...) 调用对象方法

vr:print("Hello World")

注意obj:method(par1, par2, ...) 语法只是 obj["method"](obj, par1, par2, ...) 的另一种写法(但 obj 只被评估一次),因此字段名和方法名位于同一命名空间中。
这意味着我们的容器类型无法提供对与方法同名字段的访问(并且此处未列出以“__”开头的方法),因此您必须使用显式访问方法来读取此类容器中的通用字段(写入不是问题,因为我们不允许写入方法)。
所有容器类型都应提供 getset 方法,以提供对容器内容的“干净”访问。

pairs()

某些对象可能提供 :pairs() 方法来遍历字段(而不是方法);这适用于简单的情况,例如

for k, v in vr.env:pairs() do vr:print("env['" .. k .. "'] = '" .. v .. "'") end

lua 期望 :pairs 方法返回一个 next, obj, startkey 元组,并使用 k = startkey; while k, v = next(obj, k) do ... end 遍历列表;但 next() 方法应该将 k 用作前一个键,并返回下一个键。
我们的 next 方法将在内部对象中保持当前位置(与 next 函数作为 upvalue 关联),并且每次调用都会前进,忽略 objk 参数。

全局常量

liHandlerResult 枚举值

  • lighty.HANDLER_GO_ON
  • lighty.HANDLER_COMEBACK
  • lighty.HANDLER_WAIT_FOR_EVENT
  • lighty.HANDLER_ERROR

全局方法

  • lighty.print (和 lighty.errorprint): 通过 lua “tostring” 方法以 ERROR 级别在全局服务器上下文中打印参数
  • lighty.warning: 通过 lua “tostring” 方法以 WARNING 级别在全局服务器上下文中打印参数
  • lighty.info: 通过 lua “tostring” 方法以 INFO 级别在全局服务器上下文中打印参数
  • lighty.debug: 通过 lua “tostring” 方法以 DEBUG 级别在全局服务器上下文中打印参数
  • lighty.filter_in(class): 创建一个新动作,如果在运行时调用,该动作将从 class:new(vr) 添加一个输入过滤器
  • lighty.filter_out(class): 创建一个新动作,如果在运行时调用,该动作将从 class:new(vr) 添加一个输出过滤器
  • lighty.md5(str): 计算字符串 str 的 md5 校验和(以十六进制字符串形式返回摘要)
  • lighty.sha1(str): 计算字符串 str 的 sha1 校验和(以十六进制字符串形式返回摘要)
  • lighty.sha256(str): 计算字符串 str 的 sha256 校验和(以十六进制字符串形式返回摘要)
  • lighty.path_simplify(str): 返回简化路径

示例

lighty.print("Hello World!")

示例

local MyFilterclass = { }
MyFilterClass.__index = MyFilterClass

function MyFilterClass:new(vr)
  local o = { }
  setmetatable(o, self)
  return o -- return nil if you want to skip the filter this time
end

function MyFilterClass:handle(vr, outq, inq) ... end

actions = lighty.filter_out(MyFilterClass)

虚拟请求

字段

  • con(ro): 连接
  • in(ro): 块队列,读取请求 POST 内容
  • out(ro): 块队列,写入响应内容
  • env(ro): 环境,(fast)cgi 环境
  • req(ro): 请求,请求头中的数据
  • resp(ro): 响应,响应头数据
  • phys(ro): 物理,路径和文件名
  • is_handled(ro): vrequest 是否已处理
  • has_response(ro): 响应头(和状态)是否可用

方法

  • print(...): 通过 lua tostring 方法在虚拟请求上下文中以 ERROR 级别打印参数
  • warning(...): 通过 lua tostring 方法在虚拟请求上下文中以 WARNING 级别打印参数
  • info(...): 通过 lua tostring 方法在虚拟请求上下文中以 INFO 级别打印参数
  • debug(...): 通过 lua tostring 方法在虚拟请求上下文中以 DEBUG 级别打印参数
  • handle_direct(): 处理虚拟请求(即提供头部和正文);如果尚未处理,则返回 true。
  • enter_action(act): 将新动作压入动作栈(如果推入的动作完成后需要重新运行,则返回 HANDLER_WAIT_FOR_EVENT,如果已完成则返回 HANDLER_GO_ON)
  • st, res, errno, msg = stat(filename): 异步 stat(filename)。以下结果可能
    • st 是 stat 结果,如果文件被找到,res == HANDLER_GO_ON。errno 和 msg 为 NIL。在所有其他情况下,st 为 NIL 且 res != HANDLER_GO_ON。
    • res == HANDLER_WAIT_FOR_EVENT: stat() 正在进行中,稍后重试即可(同时返回 HANDLER_WAIT_FOR_EVENT)
    • res == HANDLER_ERROR: 如果 stat() 失败,errno 包含错误号,msg 包含错误号的代码消息。
  • add_filter_in(obj): 将 obj 添加为 lua 输入过滤器(需要响应 obj:handle(vr, outq, inq) 和可选的 obj:finished());返回一个 Filter 对象
  • add_filter_out(obj): 将 obj 添加为 lua 输出过滤器(需要响应 obj:handle(vr, outq, inq) 和可选的 obj:finished());返回一个 Filter 对象

连接

  • local: 本地套接字地址
  • remote: 远程主机地址

环境

字段是环境中的键,因此它的行为类似于 Lua 表;如果您使用以“__”开头的键或名称与以下方法之一相同的键,则必须使用 get 方法读取它们,例如

x = env["set"]      -- doesn't work, returns the set method instead
x = env:get("set")  -- use this instead

x = env[y]          -- don't do this, as y may be a special key like "set"
x = env:get(y)      -- just do it the safe way if you are not sure

方法

  • get(k): env[k] 的安全方式
  • set(k, v): env[k] = v 的安全方式
  • unset(k): env[k] = nil 的安全方式
  • weak_set(k, v): 不覆盖旧值,env[k] = env[k] or v 的安全方式
  • pairs(): 用于遍历键:for k, v in env:pairs() do ... end
  • clear(): 移除所有条目

块队列

字段

  • is_closed: 块队列是否已关闭

方法

  • add(s): 将字符串追加到队列
  • add({filename="/..."}): 将文件追加到队列(只允许普通文件)
  • reset(): 移除所有块,重置计数器
  • steal_all(from): 从另一个队列窃取所有块(如果您决定通过过滤器传递所有数据,这很有用)
  • skip_all(): 跳过所有块(移除所有块,但**不**重置计数器)

请求

字段

  • headers(ro): HTTP 头
  • http_method(ro): HTTP 方法字符串(“GET”、“POST”、“HEAD”等)
  • http_version(ro): HTTP 版本字符串(“HTTP/1.0”、“HTTP/1.1”)
  • content_length(ro): Content-Length 头部的数值(如果有人更改头部值,则不会自动更新),如果未指定则为 -1
  • uri: 请求 URI

请求 URI

字段

  • raw: HTTP 请求行中(或重写结果中)的请求 URI 原样
  • raw_path: 未解码的带查询字符串的路径(对于大多数请求,将与 raw 相同,除非有人执行类似 GET http://example.com/test?abc HTTP/1.1 的操作)
  • raw_orig_path: 与 raw_path 相同,但在任何重写发生之前保存
  • scheme: “http”或“https”
  • authority: 完整主机名头(或绝对 URL 中的权限),例如“user@www.example.com.:8080”
  • path: 解码并简化的路径名,不含权限、方案、查询字符串;例如“/index.php”
  • host: 简单主机名,不含认证信息、不含端口、不含尾随点;例如“www.example.com”
  • query: 查询字符串,例如“a=1&b=2”

响应

字段

  • headers(ro): HTTP 头
  • status: HTTP 状态码

物理路径

字段

  • path: 物理路径
  • doc_root: 文档根目录
  • pathinfo: 路径信息

HTTP 头

字段与环境的限制相同。

方法

  • get(k): 将键 k 的所有头部值用 “, “ 连接起来(正如 rfc 允许的那样)
  • set(k, v): 移除所有键为 k 的头部,如果 v 不为 nil,则追加新的 “k: v” 头部
  • append(k, v): 如果键 k 的最后一个头部值已存在,则在其后追加 “, v”,否则 insert(k, v)
  • insert(k, v): 将新的 “k: v” 头部追加到列表
  • unset(k): 移除所有键为 k 的头部
  • pairs(): 遍历所有头部。请注意,键不唯一!
  • list(k): 遍历键为 k 的所有头部
  • clear(): 移除所有头部

过滤器

表示一个“liFilter”。

字段

  • in(ro): 块队列,传入流
  • out(ro): 块队列,传出流

Stat 结构体

表示“struct stat”。大多数字段应该是不言自明的(如果您不了解,请查阅 man 2 stat (debian manpage))。

字段

  • is_file(ro): S_ISREG(mode)
  • is_dir(ro): S_ISDIR(mode)
  • is_char(ro): S_ISCHR(mode)
  • is_block(ro): S_ISBLK(mode)
  • is_socket(ro): S_ISSOCK(mode)
  • is_link(ro): S_ISLNK(mode)
  • is_fifo(ro): S_ISFIFO(mode)
  • mode(ro)
  • mtime(ro)
  • ctime(ro)
  • atime(ro)
  • uid(ro)
  • gid(ro)
  • size(ro)
  • ino(ro)
  • dev(ro)

模块索引

模块

名称 描述
plugin_core 包含通用请求处理、静态文件、日志文件和缓冲区限制的核心功能。
mod_access 允许您按 IP 地址过滤客户端。
mod_accesslog 将 lighttpd 处理的请求记录到文件、管道或 syslog。日志格式可以使用 printf 风格的占位符进行自定义。
mod_auth 要求客户端使用用户名和密码进行身份验证。它支持基本(尚不支持摘要)身份验证方法以及纯文本、htpasswd 和 htdigest 后端。
mod_balance 在不同后端之间进行负载均衡。
mod_cache_disk_etag 如果设置了 etag 响应头,则将生成的缓存内容缓存到磁盘;如果后端发送了已缓存的 etag,则关闭后端并直接发送文件。
mod_debug 提供各种实用工具来帮助您调试问题。
mod_deflate mod_deflate 实时压缩内容
mod_dirlist 列出目录中的文件。输出可以通过多种方式自定义,从通过 CSS 设置样式到排除某些条目。
mod_expire 向响应添加“Expires”和“Cache-Control”头
mod_fastcgi 连接到 FastCGI 后端以生成响应内容
mod_flv 提供 flash 伪流式传输
mod_fortune 从文件中加载语录(又称 fortune cookies),并提供动作来将随机语录添加为响应头 (X-fortune) 或将其显示为页面。
mod_gnutls 使用 GnuTLS 监听单独的套接字进行 TLS 连接 (https)
mod_limit 限制并发连接或每秒请求数。
mod_lua 加载 lua 插件和动作
mod_core (lua) 提供一些用 lua 编写的有用辅助程序
mod_secdownload (lua) 使用有时限的代码保护文件
mod_memcached 在 memcached 服务器上缓存内容
mod_openssl 使用 OpenSSL 监听单独的套接字进行 TLS 连接 (https)
mod_progress 通过唯一标识符跟踪连接进度(状态)
mod_proxy 连接到 HTTP 后端以生成响应内容
mod_redirect 通过发送 HTTP 状态码 301 和 Location 头重定向客户端
mod_rewrite 修改请求路径和查询字符串
mod_scgi 连接到 SCGI 后端以生成响应内容
mod_status 显示一个包含内部统计信息的页面,例如请求总量(总数或每秒)、活动连接数等。
mod_throttle 限制出站带宽使用
mod_userdir 允许您通过 http://domain/~user/ 访问用户特定的文档根目录
mod_vhost 提供各种实现虚拟主机的方式

动作

名称 模块 描述
access.check mod_access 根据客户端 IP 地址允许或拒绝访问
access.deny mod_access 通过返回 403 状态码拒绝访问
alias plugin_core 根据匹配的前缀设置文档根目录
auth.deny mod_auth 以“401 未授权”处理请求
auth.htdigest mod_auth 要求使用 htdigest 文件进行身份验证
auth.htpasswd mod_auth 要求使用 htpasswd 文件进行身份验证
auth.plain mod_auth 要求使用纯文本文件进行身份验证
auth.require_user mod_core (lua) 要求特定已验证用户
balance.rr mod_balance 以轮询方式在动作之间进行负载均衡(列表或单个动作)
balance.sqf mod_balance 以 SQF 在动作之间进行负载均衡(列表或单个动作)
cache.disk.etag mod_cache_disk_etag 根据 ETag 响应头缓存响应
core.cached_html mod_core (lua) 如果我们尚未找到 URL 的静态文件,并且 URL 还没有“.html”后缀,则尝试为当前 URL 查找带有“.html”后缀的文件。
core.wsgi mod_core (lua) 将 URL 分割为 SCRIPT_NAME(Web 应用程序挂载的子目录)和 PATH_INFO(Web 应用程序应路由的路径)
core.xsendfile mod_core (lua) 提供简单的 X-Sendfile 功能;从您的后端发送“X-Sendfile: /path/to/file”响应头
debug.profiler_dump mod_debug 如果启用了性能分析,则将所有已分配内存转储到性能分析输出文件
debug.show_connections mod_debug 显示一个与 mod_status 类似的页面,列出所有活动连接
debug.show_events mod_debug 显示所有事件的纯文本列表
deflate mod_deflate 等待响应头;如果响应可以压缩,deflate 会添加一个过滤器来压缩它
dirlist mod_dirlist 列出目录中的文件
docroot plugin_core 设置文档根目录,并为请求的文件构建物理路径
env.add plugin_core 如果尚未设置,则设置连接环境变量
env.clear plugin_core 移除所有连接环境变量
env.remove plugin_core 移除连接环境变量
env.set plugin_core 设置连接环境变量
expire mod_expire 向响应添加“Expires”头部
fastcgi mod_fastcgi 连接到 FastCGI 后端
flv mod_flv 将当前文件伪流式传输为 flash
fortune.header mod_fortune 将随机名言作为响应头“X-fortune”添加。
fortune.page mod_fortune 显示随机 cookie 作为响应文本
header.add plugin_core 添加新的响应头行
header.append plugin_core 将值追加到响应头行
header.overwrite plugin_core 覆盖响应头行或添加新行
header.remove plugin_core 移除现有响应头
index plugin_core 目录中显示的默认文件名
io.buffer_in plugin_core 设置传入块队列的内存限制(默认为 256KB)
io.buffer_out plugin_core 设置传出块队列的内存限制(默认为 256KB)
io.throttle mod_throttle 为当前连接设置出站限制
io.throttle_ip mod_throttle 将当前连接添加到基于 IP 的出站限制池中
io.throttle_pool mod_throttle 将当前连接添加到出站限制池中
limit.con mod_limit 将并发连接总数限制为指定限制。
limit.con_ip mod_limit 将每个 IP 的并发连接总数限制为指定限制。
limit.req mod_limit 将每秒请求数限制为指定限制。
limit.req_ip mod_limit 将每个 IP 的每秒请求数限制为指定限制。
列表 plugin_core (lua) 将动作列表合并为一个动作,仅在 lua 中需要
log plugin_core 覆盖所有日志级别的日志目标
log.write plugin_core 将日志消息写入“信息”日志级别
lua.handler mod_lua 将文件作为 lua 配置加载
map plugin_core 将模式结果映射到用户定义的动作
memcached.lookup mod_memcached 在 memcached 数据库中搜索内容
memcached.store mod_memcached 将生成的响应存储在 memcached 数据库中
openssl.setenv mod_openssl 设置 SSL 环境变量字符串
路径信息 plugin_core 将物理路径分割为现有文件/目录和剩余的 PATH_INFO
progress.show mod_progress 返回由 X-Progress-ID 查询字符串参数指定的请求的状态信息
progress.track mod_progress 如果提供了 X-Progress-ID 查询字符串键,则跟踪当前请求
proxy mod_proxy 连接到 HTTP 后端
redirect mod_redirect 重定向客户端
req_header.add plugin_core 添加新的请求头行
req_header.append plugin_core 将值追加到请求头行
req_header.overwrite plugin_core 覆盖请求头行或添加新行
req_header.remove plugin_core 移除现有请求头
respond plugin_core 返回带可选正文的快速响应
rewrite mod_rewrite 修改请求路径和查询字符串
rewrite_raw mod_rewrite 修改请求路径和查询字符串,匹配和写入原始路径
scgi mod_scgi 连接到 SCGI 后端
secdownload mod_secdownload (lua) 使用有时限的代码保护文件
set_status plugin_core 修改 HTTP 状态码
static plugin_core 处理带有静态文件的 GET 和 HEAD 请求
static_no_fail plugin_core 处理带有静态文件的 GET 和 HEAD 请求
status.info mod_status 向客户端返回状态页面
userdir mod_userdir 通过将路径中的某些占位符替换为用户名(部分)来构建文档根目录。
vhost.map mod_vhost 将给定的主机名映射到动作块
vhost.map_regex mod_vhost 将匹配的主机名模式映射到动作块
when plugin_core (lua) 构建条件块 (仅在 lua 中可用)

设置

名称 模块 描述
debug.show_events_after_shutdown mod_debug 关机开始后记录剩余活动事件的时间(秒)
fetch.files_static plugin_core 启动 Fetch API 提供程序
fortune.load mod_fortune 从文件中加载 cookie,可以多次调用以从多个文件加载数据
gnutls mod_gnutls 设置 TLS 套接字
io.timeout plugin_core 设置全局 I/O 超时(等待网络读写)
listen plugin_core 监听一个套接字地址,接受的格式见上文(默认 TCP 端口为 80)
log plugin_core 设置所有日志级别的默认日志目标
log.timestamp plugin_core 设置日志中时间戳的格式字符串
lua.plugin mod_lua 将文件作为 lua 插件加载
module_load plugin_core 加载给定模块
openssl mod_openssl 设置 TLS 套接字
progress.ttl mod_progress 内部查找表中条目断开连接后的存活时间(秒)
stat_cache.ttl plugin_core 设置 stat 缓存条目的 TTL
tasklet_pool.threads plugin_core 设置阻塞任务的后台线程数
workers plugin_core 设置工作进程数量;每个工作进程在自己的线程中运行,并处理从主工作进程分配的连接
workers.cpu_affinity plugin_core 将工作线程绑定到 CPU,仅在 Linux 系统上可用

选项

名称 模块 描述
access.log_blocked mod_access 是否在访问被拒绝时记录日志(日志级别为“info”)
access.redirect_url mod_access 如果访问被拒绝,重定向到的 URL(尚未实现)
accesslog mod_accesslog 定义日志目标
accesslog.format mod_accesslog 定义日志格式
auth.debug mod_auth 启用调试输出
balance.debug mod_balance 启用调试输出
buffer_request_body plugin_core 在磁盘上启用请求体缓冲
debug.log_request_handling plugin_core 启用请求处理的调试输出
deflate.debug mod_deflate 启用调试输出
etag.use plugin_core 用于计算 etag 的属性列表;指定空列表以禁用 etag。可用值:“inode”、“mtime”、“size”
fastcgi.log_plain_errors mod_fastcgi 是否在“backend”日志中,在 FastCGI stderr 行前添加时间戳和其他信息
keepalive.requests plugin_core 客户端在一个连接中允许发出的最大请求数
keepalive.timeout plugin_core 保持活动连接的开放时间(秒)
mime_types plugin_core 将文件扩展名映射到 MIME 类型
progress.debug mod_progress 启用调试输出
progress.methods mod_progress 要跟踪的请求方法
redirect.debug mod_redirect 启用调试输出
rewrite.debug mod_rewrite 启用调试输出
server.name plugin_core 服务器名称;在某些情况下,如果 HTTP 请求主机名未指定(在 HTTP/1.0 请求中),则使用此名称代替
server.tag plugin_core 用于在不同位置(HTTP 响应头、CGI 环境、mod_dirlist 页脚等)显示服务器名称 + 版本
stat.async plugin_core 启用异步 stat() 调用
static.exclude_extensions plugin_core 不提供具有列出扩展名之一的静态文件
static.range_requests plugin_core 启用范围请求
status.css mod_status 定义要使用的样式表。可用值:未设置(默认)、"blue" 或您希望的任何 URL
strict.post_content_length plugin_core 要求 POST 请求的 Content-Length
vhost.debug mod_vhost 启用调试输出

plugin_core

plugin_core 包含通用请求处理、静态文件、日志文件和缓冲区限制的核心功能。

套接字地址

可以使用以下地址格式

IPv4

带端口 192.168.0.1:80 或不带端口 192.168.0.1;您可以使用真实 IP 或 0.0.0.0 监听所有网络接口。

IPv6

与 IPv4 类似;只需将 IPv6 放在“[”和“]”之间,像这样:[::1]:80(端口 80 的 IPv6 本地主机)。

请注意,lighttpd 始终只监听 IPv6(某些平台在 [::] 上默认也监听 IPv4)。

Unix 域套接字

Unix 域套接字需要一个套接字存放的文件名;使用 unix:/path/to/socket 作为套接字地址。

请勿将 Unix 域套接字放置在 /tmp 中。请使用 /var/run/lighttpd/ 或类似路径,只有 root 用户或选定的“受信任”用户才能在此处创建文件。

并非所有可以指定套接字地址的地方都支持此功能。

选项

debug.log_request_handling (选项)

启用请求处理的调试输出

debug.log_request_handling value;
默认值: false

示例

debug.log_request_handling true;

static.range_requests (选项)

启用范围请求

static.range_requests value;
默认值: true

示例

static.range_requests false;

keepalive.timeout (选项)

保持活动连接的开放时间(秒)

keepalive.timeout timeout;
默认值: 5

示例

keepalive.timeout 30;

keepalive.requests (选项)

客户端在一个连接中允许发出的最大请求数

keepalive.requests requests;
默认值: 0

示例

keepalive.requests 10;

etag.use (选项)

用于计算 etag 的属性列表;指定空列表以禁用 etag。可用值:“inode”、“mtime”、“size”

etag.use properties;
默认值: ("inode", "mtime", "size")

示例

etag.use ();

stat.async (选项)

启用异步 stat() 调用

stat.async value;
默认值: true

如果文件名在 lighttpd 的 stat“缓存”中,lighttpd 会假定内核仍然在内存中保留该条目,因此 stat() 不太可能阻塞。
否则,它将要求后台线程调用 stat(),这样主工作线程就不会等待慢速磁盘(或网络文件系统),但前提是 stat.async 已启用。

如果您知道您的磁盘足够快(也许是内存盘?),并且想要节省到后台线程的上下文切换,您可以禁用此功能。

buffer_request_body (选项)

在磁盘上启用请求体缓冲

buffer_request_body value;
默认值: true

某些后端喜欢在转发/处理响应之前等待完整的响应。为此,它们需要此选项以节省一些内存。

strict.post_content_length (选项)

要求 POST 请求的 Content-Length

strict.post_content_length value;
默认值: true

某些客户端在发送空正文的 POST 请求时不会发送 Content-Length;它们应该发送 Content-Length: 0。启用此检查后,它们将收到 411 Length required 错误。

static.exclude_extensions (选项)

不提供具有列出扩展名之一的静态文件

static.exclude_extensions extensions;
默认值: []

示例

static.exclude_extensions [ ".php", ".htaccess", ".htpasswd" ];

server.name (选项)

服务器名称;在某些情况下,如果 HTTP 请求主机名未指定(在 HTTP/1.0 请求中),则使用此名称代替

server.name hostname;
默认值: ""

即使是 HTTP/1.0 客户端通常也会指定 Host: 头;如果没有 Host: 头,您只能在一个 IP 地址上运行一个域。
此选项适用于您希望以友好的方式处理不支持 Host: 头的客户端的罕见情况。

示例

server.name "lighttpd.net";

server.tag (选项)

用于在不同位置(HTTP 响应头、CGI 环境、mod_dirlist 页脚等)显示服务器名称 + 版本

server.tag tag;
默认值: "lighttpd/2.0.0"

默认值为“lighttpd/”+当前版本。

mime_types (选项)

将文件扩展名映射到 MIME 类型

mime_types mapping;
默认值: []

默认 MIME 类型是“application/octet-stream”。源代码包含一个 mimetypes 示例配置,其中包含许多标准映射。

使用最长匹配的后缀(".tar.gz" 始终优先于 ".gz"),如果存在重复条目,则使用最后一个。

示例

mime_types [ ".htm" => "text/html", ".txt" => "text/plain; charset=utf-8" ];

Lua 中需要的动作

这些操作在非 Lua 配置中不需要(或不可用)。

list (动作)

(lua) 将动作列表合并为一个动作,仅在 lua 中需要

list actions;
动作
要组合的操作列表

when (动作)

(lua) 构建条件块 (仅在 lua 中可用)

when (condition, action1, action2);
条件
一个条件;只能在 Lua 中构建
操作1
如果条件为 true 或 Lua “nil”时运行的操作
操作2
(可选)如果条件为 false 时运行的操作

将 URL 路径映射到文件名

docroot (动作)

设置文档根目录,并为请求的文件构建物理路径

docroot patterns;
模式
用于构建文档根目录的一个或多个模式

使用 模式 来构建文档根目录(要服务文件的基础位置)。
docroot 使用第一个结果为现有目录的模式;否则使用最后一个条目。
您会希望 docroot 操作在 alias 操作之前

示例

docroot ("/var/www/vhosts/$0/htdocs", "/var/www/default/htdocs");

alias (动作)

根据匹配的前缀设置文档根目录

alias mapping;
映射
将前缀映射到磁盘上的基本位置

前缀会从 URL 路径中移除,然后才附加到基本位置。
您会希望 docroot 操作在 alias 操作之前

模式 目标支持 模式,与 docroot 类似。由于每个前缀只能指定一个模式,alias 不检查目标是否存在。

前缀中的尾部斜杠曾用于表示“目录处理”并在匹配时被忽略;现在“目录处理”始终开启。
这意味着 URL 路径只在分隔符边界匹配;前缀 /a(和 /a/)匹配路径 /a/a//a/b,但不匹配 /ab

示例

docroot ("/var/www/vhosts/$0/htdocs", "/var/www/default/htdocs");
alias [
	"/phpmyadmin/" => "/usr/share/phpmyadmin",
	"/pma/" => "/usr/share/phpmyadmin",
	"/.well-known/openpgpkey/" => "/var/lib/gnupg/wks/$0/",
];
alias "/favicon.ico" => "/var/www/favicon.ico";

index (动作)

目录中显示的默认文件名

index filenames;
文件名
要查找的文件名

如果物理路径是目录,则搜索指定的文件名;在文件名前加上‘/’以在文档根目录中搜索。

它这样工作:

  • 如果当前物理路径指向常规文件,则不执行任何操作
  • 遍历要查找的文件名列表
    • 如果文件名不是以‘/’开头且当前物理路径不指向目录,则忽略该条目
    • 如果文件名不是以‘/’开头且 URL 没有以‘/’结尾,则将请求重定向到附加了‘/’的 URL
    • 如果文件名不是以‘/’开头,则在当前物理路径(该路径是一个目录)中搜索它
    • 如果文件名以‘/’开头,则在文档根目录中搜索它

示例

setup {
	module_load "mod_dirlist";
}

# if a directory was requested, first search for some default files
index ["index.php", "index.html", "/index.php"];
# if none of them did exists show a simple directory listing
dirlist;
# ... + handle PHP and static files

pathinfo (动作)

将物理路径分割为现有文件/目录和剩余的 PATH_INFO

pathinfo;

搜索存在的物理路径名中最长的前缀,仅在目录分隔符 / 处拆分;同时永不离开文档根目录(技术上讲,文件名不能比文档根目录更短)。

示例

以下示例将 http://example.com/index.php/some/site 映射到文件 /var/www/index.php,并带有 PATH_INFO=/some/site(假设 /var/www/index.php 是一个普通文件)。

docroot "/var/www";
pathinfo;
if phys.path =$ ".php" { fastcgi "unix:/var/run/lighttpd/php.sock"; }

示例

以下示例将 http://example.com/some/site 映射到文件 /var/www/index.php,并带有 PATH_INFO=/some/site(假设 /var/www/index.php 是一个普通文件,且 /var/www/some 不存在)。

docroot "/var/www";
pathinfo;
index ("index.php");
if phys.path =$ ".php" { fastcgi "unix:/var/run/lighttpd/php.sock"; }

生成响应

static (动作)

处理带有静态文件的 GET 和 HEAD 请求

static;

此操作会自动附加到全局配置中(除非在命令行指定了 Lua 配置)。

在以下情况下不执行任何操作:

  • 请求已被处理
  • 未设置物理路径(缺少 docrootalias 等)
  • 物理路径指向一个目录

所有其他问题都会导致错误页面,例如:

  • 错误的请求方法 (405)
  • 文件未找到 (404)
  • 无法打开文件 (403)
  • 文件名匹配 static.exclude_extensions (403)

static_no_fail (动作)

处理带有静态文件的 GET 和 HEAD 请求

static_no_fail;

static 相同,但不返回任何错误页面;相反,请求处理继续进行。

respond (动作)

返回带可选正文的快速响应

respond (status, content);
状态
HTTP 响应状态码
内容
(可选)响应正文的模式

生成一个简单的响应(我们最喜欢的基准测试处理程序)。
正文被解析为 模式

示例

respond 403 => "Forbidden";

示例

respond 200 => "benchmark content!";

日志

日志级别

对于标准日志记录(“error.log”),lighttpd 知道以下级别:

  • 调试
  • 信息
  • 警告
  • 错误
  • abort (在终止进程之前)
  • backend (用于来自后端,如 FastCGI stderr 流的日志数据)

日志目标

已知以下日志目标:

  • 不记录:空字符串
  • 文件:file:/var/log/error.log 或仅 /var/log/error.log
  • 标准错误:stderr:stderr
  • 系统日志:syslog: (暂不支持)
  • 管道:pipe:command| command (暂不支持)

未知字符串映射到 stderr

log (动作)

覆盖所有日志级别的日志目标

log map;
map
将日志级别(或默认级别)映射到日志目标

示例

log [
	"error" => "/var/log/lighttpd/error.log",
	"abort" => "/var/log/lighttpd/error.log",
	"backend" => "/var/log/lighttpd/backend.log",
	default => "/var/log/lighttpd/debug.log",
];

log.write (动作)

将日志消息写入“信息”日志级别

log.write message;
消息
消息模式字符串

使用 info 级别将指定消息写入日志;消息被解析为 模式

示例

log.write "hello world";

log (设置)

设置所有日志级别的默认日志目标

log map;
map
将日志级别(或默认级别)映射到日志目标

示例

setup {
	log [
		"error" => "/var/log/lighttpd/error.log",
		"abort" => "/var/log/lighttpd/error.log",
		"backend" => "/var/log/lighttpd/backend.log",
		default => "/var/log/lighttpd/debug.log",
	];
}

log.timestamp (设置)

设置日志中时间戳的格式字符串

log.timestamp format;
格式
一个 strftime 格式字符串

请参阅 strftime 以了解格式字符串语法。

默认格式字符串为 "%d/%b/%Y %T %Z"

连接环境

连接环境是一组具有名称和值(均为简单字符串)的变量。CGI 后端除了标准的 CGI 环境变量外,还会转发此环境。
连接环境会覆盖标准的 CGI 值。

env.set (动作)

设置连接环境变量

env.set (name, value);
名称
要设置的变量名
要设置的模式值

该值被解析为 模式

示例

env.set "INFO" => "%{req.path}";

env.add (动作)

如果尚未设置,则设置连接环境变量

env.add (name, value);
名称
要设置的变量名
要设置的模式值

该值被解析为 模式env.add 不会覆盖已存在的值。

示例

env.add "INFO" => "%{req.path}";

env.remove (动作)

移除连接环境变量

env.remove name;
名称
要移除的变量名

示例

env.remove "INFO";

env.clear (动作)

移除所有连接环境变量

env.clear;

示例

env.clear;

响应头

所有设置的头值都被解析为 模式

header.add (动作)

添加新的响应头行

header.add (name, value);
名称
头名称
模式头值

HTTP 规范要求同名的多个头可以通过使用“,”连接其值来合并。
在实际中,这并非总是有效,特别是对于“Cookie”头;所以此操作实际上会添加一个单独的头行。

示例

header.add "Cache-Control" => "public";

header.append (动作)

将值追加到响应头行

header.append (name, value);
名称
头名称
模式头值

如果头已存在,则将新值以“, “分隔追加;否则添加一个新头行。

header.overwrite (动作)

覆盖响应头行或添加新行

header.overwrite (name, value);
名称
头名称
模式头值

如果头已存在,则覆盖其值;否则添加一个新行。

header.remove (动作)

移除现有响应头

header.remove name;
名称
头名称

示例

# ... some PHP handling
# wait for response headers to be ready
if resp.status >= 0 {
	header.remove "X-Powered-By";
}

set_status (动作)

修改 HTTP 状态码

set_status;

修改 HTTP 状态码,但不以任何方式处理请求。
后续操作可能会覆盖状态,或者如果响应稍后被解析,后端(FastCGI、代理等)也可能覆盖它。
仅当某个操作实际处理了请求时才有效。

如果处理请求的操作未生成响应正文且允许生成正文,Lighttpd 将生成错误页面(如果它知道代码)。

示例

# hide all 404s at end of config by setting 403
static;
if resp.status == 404 { set_status 403; }

请求头

所有设置的头值都被解析为 模式

req_header.add (动作)

添加新的请求头行

req_header.add (name, value);
名称
头名称
模式头值

与请求头的 header.add 相同。

req_header.append (动作)

将值追加到请求头行

req_header.append (name, value);
名称
头名称
模式头值

与请求头的 header.append 相同。

req_header.overwrite (动作)

覆盖请求头行或添加新行

req_header.overwrite (name, value);
名称
头名称
模式头值

与请求头的 header.overwrite 相同。

req_header.remove (动作)

移除现有请求头

req_header.remove name;
名称
头名称

与请求头的 header.remove 相同。

示例

移除 Accept-Encoding 请求头以解决 HTTPS 中的 BREACH 漏洞。

if request.scheme == "https" {
	# create a copy of the header value
	req_header.add "HTTPS-Accept-Encoding" => '%{req.header[Accept-Encoding]}';
	req_header.remove "Accept-Encoding";
}

io.buffer_out (动作)

设置传出块队列的内存限制(默认为 256KB)

io.buffer_out limit;
限制
以字节为单位的限制(0 表示无限制)

示例

io.buffer_out 512kbyte;

io.buffer_in (动作)

设置传入块队列的内存限制(默认为 256KB)

io.buffer_in limit;
限制
以字节为单位的限制(0 表示无限制)

示例

io.buffer_in 512kbyte;

map (动作)

将模式结果映射到用户定义的动作

map (pattern, mapping);
模式
此模式的评估结果用作映射中的键
映射
将字符串(或默认值)映射到操作

模式被解析为 模式。有关主机名的特殊映射,请查看 mod_vhost

示例

map "%{req.path}" => [
	"/" => {
		respond 200 => "root";
	},
	"/news" => {
		respond 200 => "news";
	},
	default => {
		respond 404;
	},
];

listen (设置)

监听一个套接字地址,接受的格式见上文(默认 TCP 端口为 80)

listen socket-address;
套接字地址
要监听的套接字地址

示例

setup {
	listen "0.0.0.0";
	listen "[::]";
	listen "127.0.0.1:8080";
}

workers (设置)

设置工作进程数量;每个工作进程在自己的线程中运行,并处理从主工作进程分配的连接

workers count;
计数
工作进程数量(默认值为 1)

示例

setup {
	workers 2;
}

workers.cpu_affinity (设置)

将工作线程绑定到 CPU,仅在 Linux 系统上可用

workers.cpu_affinity mapping;
映射
整数列表或整数列表的列表

示例

workers.cpu_affinity [0, 1];

module_load (设置)

加载给定模块

module_load names;
名称
模块名称的字符串或字符串列表

模块可以多次“加载”而不会出错

示例

setup {
	module_load "mod_rewrite";
}

io.timeout (设置)

设置全局 I/O 超时(等待网络读写)

io.timeout timeout;
超时
超时值(秒),默认值为 300 秒

stat_cache.ttl (设置)

设置 stat 缓存条目的 TTL

stat_cache.ttl ttl;
生存时间
生存时间(秒),默认值为 10 秒

tasklet_pool.threads (设置)

设置阻塞任务的后台线程数

tasklet_pool.threads threads;
线程
线程数量

例如,统计缓存使用此类后台线程。

如果 threads = 0,任务将在前台运行(无后台线程)。
如果 threads < 0,所有工作进程共享一个 GThreadPool。
如果 threads > 0,每个工作进程都有自己的线程池,其中包含 threads 个线程。

fetch.files_static (设置)

启动 Fetch API 提供程序

fetch.files_static (name, filename-pattern);
名称
存储名称
文件名模式
包含且只包含一个 * 的文件名模式

将所有匹配通配符模式(必须包含且只包含一个 *)的文件名加载到抓取存储中。

示例

setup {
	fetch.files_static "sni" => "/etc/certs/lighttpd_sni_*.pem";
}

mod_access

mod_access 允许您按 IP 地址过滤客户端。

access.deny (动作)

通过返回 403 状态码拒绝访问

access.deny;

access.check (动作)

根据客户端 IP 地址允许或拒绝访问

access.check rules;
规则
一个键值列表,将“access”和/或“deny”键映射到 CIDR 地址列表或“all”。

根据规则检查客户端 IP 地址。默认是拒绝所有地址。最精确的匹配规则定义结果(“192.168.100.0/24”优先于“192.168.0.0/16”;类似于路由表);如果相同的 CIDR 在两个列表中,则执行第二个操作。“all”是“0.0.0.0/0”和“::/0”的同义词,匹配所有 IPv4 和 IPv6 地址。

示例:限制对本地网络的访问

限制对本地网络客户端的访问。拒绝规则并非严格要求,因为默认情况下本来就拒绝。较小的本地网络 CIDR 字符串会覆盖全局拒绝规则。

setup {
	module_load "mod_access";
}

access.check (
	"allow" => ("127.0.0.0/8", "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"),
	"deny" => ("all")
);

示例:限制对子网的访问,带例外

限制对“192.168.10.0/24”客户端的访问,但拒绝访问“192.168.10.1”。由于“192.168.10.1”(相当于“192.168.10.1/32”)是更精确的匹配,它会覆盖包含它的子网“192.168.10.0/24”的允许规则。

setup {
	module_load "mod_access";
}

access.check (
	"allow" => ("192.168.10.0/24"),
	"deny" => ("192.168.10.1")
);

access.redirect_url (选项)

如果访问被拒绝,重定向到的 URL(尚未实现)

access.redirect_url url;
默认值: 未设置

尚未实现

access.log_blocked (选项)

是否在访问被拒绝时记录日志(日志级别为“info”)

access.log_blocked url;
默认值: false

mod_accesslog

mod_accesslog 将 lighttpd 处理的请求记录到文件、管道或 syslog 中。日志格式可以使用 printf 风格的占位符进行自定义。

accesslog.format (选项)

定义日志格式

accesslog.format format;
默认值: "%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""

一些格式说明符需要一个强制键,该键用大括号括起来,位于百分号和实际说明符之间。CLF 表示“通用日志格式”,如果值为零,则使用‘-’代替。

说明符 描述
%% 百分号本身
%a 远程 IP 地址
%A 本地 IP 地址
%b 响应大小(字节),不包括 HTTP 头 (CLF)
%B 响应大小(字节),不包括 HTTP 头
%{foobar}C 尚未实现)请求中 cookie foobar 的内容
%D 处理请求所花费的时间(微秒)
%{foobar}e 请求环境变量 foobar 的内容
%f 物理文件路径
%h 远程 IP 地址(与 %a 相同)
%{foobar}i 请求头 foobar 的内容
%m 请求方法 (GET, POST 等)
%{foobar}o 响应头 foobar 的内容
%p 本地端口
%q 查询字符串
%r 请求的第一行 (GET /foo.html?bar HTTP/1.1)
%s 响应状态码
%t 收到请求的时间/日期,采用标准英文格式
%T 处理请求所花费的时间(秒)
%u 已认证用户(来自 mod_auth)。与 %{REMOTE_USER}e 相同
%U 请求路径(不包括查询字符串)
%v 通过 server.name 选项设置的服务器名称,或如果未设置 server.name 则为请求主机名
%V 请求主机名
%X 响应后的连接状态:“X”表示在完成前中止,“+”表示保持活动,“-”表示不保持活动
%I 接收到的字节数,包括 HTTP 头和请求正文
%O 发送的字节数,包括 HTTP 头和响应正文

Apache 提供的百分号后的修饰符不支持。“<”或“>”被忽略,其他所有内容都会导致解析错误。Apache 支持但 lighty 不支持的说明符有:%l, %n, %P

示例

accesslog.format "%h %V %u %t \"%r\" %>s %b";

accesslog (选项)

定义日志目标

accesslog target;
默认值: 日志记录已禁用

通过设置日志目标来启用日志记录。支持与 log 相同的日志目标。

示例

setup {
	module_load "mod_accesslog";

	accesslog "/var/log/lighttpd/access.log";
}

mod_auth

mod_auth 要求客户端使用用户名和密码进行身份验证。它支持基本(摘要暂不支持)身份验证方法,以及纯文本、htpasswd 和 htdigest 后端。

重要提示:您需要在生成内容之前放置身份验证操作!如果内容处理程序已激活(例如 php、static 或 dirlist),则身份验证将被忽略!

  • 基本
    “基本”方法通过网络以明文(base64 编码)传输用户名和密码,如果不与客户端和服务器之间的加密通信通道结合使用,可能会导致安全问题。
    建议将 HTTPS 与基本身份验证结合使用。
  • 摘要 (暂不支持)
    “摘要”方法仅通过网络传输哈希值,这在不安全的网络(如互联网)中为加强身份验证过程做了大量工作。
    “摘要”方法不适用于 htpasswd 后端,仅适用于纯文本和 htdigest。

注意:Internet Explorer < 7 中的摘要方法存在问题。如果这对您来说是个问题,请改用基本方法。(无论如何,目前尚不支持)

auth.plain (动作)

要求使用纯文本文件进行身份验证

auth.plain options;
选项
一个包含以下条目的键值表
方法
“basic”或“digest”——目前只支持“basic”,但您仍然必须指定它。
领域
在“需要身份验证”响应中发送给浏览器的领域名称;也在 htdigest 的哈希中使用。
文件
(可选)在多少秒后,如果密码文件被更改并且再次需要时,lighty 会重新加载它(默认为 10 秒)
生存时间
需要使用包含以换行符 (\n) 分隔的用户:密码对的纯文本文件进行身份验证。

仅支持“basic”

auth.htpasswd (动作)

要求使用 htpasswd 文件进行身份验证

auth.htpasswd options;
选项
一个包含以下条目的键值表
方法
需要使用包含以换行符 (\n) 分隔的用户:加密密码对的 htpasswd 文件进行身份验证
领域
在“需要身份验证”响应中发送给浏览器的领域名称;也在 htdigest 的哈希中使用。
文件
(可选)在多少秒后,如果密码文件被更改并且再次需要时,lighty 会重新加载它(默认为 10 秒)
生存时间
需要使用包含以换行符 (\n) 分隔的用户:密码对的纯文本文件进行身份验证。
  • 密码使用 crypt(3) 加密,使用 Apache 的 htpasswd 二进制文件管理该文件
  • 支持以“$apr1$”开头的哈希 (htpasswd -m)
    • 支持以“{SHA}”开头的哈希(后跟 sha1_base64(password),htpasswd -s)
    • 需要使用包含以换行符 (\n) 分隔的用户:领域:哈希密码元组的 htdigest 文件进行身份验证

auth.htdigest (动作)

要求使用 htdigest 文件进行身份验证

auth.htdigest options;
选项
一个包含以下条目的键值表
方法
“basic”或“digest”——目前只支持“basic”,但您仍然必须指定它。
领域
在“需要身份验证”响应中发送给浏览器的领域名称;也在 htdigest 的哈希中使用。
文件
(可选)在多少秒后,如果密码文件被更改并且再次需要时,lighty 会重新加载它(默认为 10 秒)
生存时间
需要使用包含以换行符 (\n) 分隔的用户:密码对的纯文本文件进行身份验证。
  • 哈希值绑定到领域,因此您无法在不重置密码的情况下更改领域
  • 密码保存为(修改过的)md5 哈希
  • md5hex(用户名 + ":" + 领域 + ":" + 密码)
    您也可以使用 mod_lua 插件 contrib/core.lua 中的 auth.require_user 进行 REMOTE_USER 检查

auth.deny (动作)

以“401 未授权”处理请求

auth.deny;

auth.debug (选项)

启用调试输出

auth.debug value;
默认值: false

示例

setup {
	module_load "mod_auth";
}

#/members/ is for known users only
if request.path =^ "/members/" {
	auth.plain [ "method" => "basic", "realm" => "members only", "file" => "/etc/lighttpd/users.txt"];
	if req.env["REMOTE_USER"] !~ "^(admin1|user2|user3)$" { auth.deny; }
}

示例

mod_balance 在不同的后端之间进行负载均衡。

setup {
	module_load ("mod_auth", "mod_lua");
	lua.plugin "contrib/core.lua";
}

#/members/ is for known users only
if request.path =^ "/members/" {
	auth.plain [ "method" => "basic", "realm" => "members only", "file" => "/etc/lighttpd/users.txt"];
	auth.require_user ("admin1", "user2", "user3");
}

mod_balance

使用 mod_balance 的操作还会激活一个积压队列:如果后端不可用,lighttpd2 会将请求放入积压队列,稍后再尝试。

请注意:引用的操作可能会执行多次(直到成功为止!),所以不要在其中进行循环重写或类似操作。

要在其间进行负载均衡的操作

balance.rr (动作)

以轮询方式在动作之间进行负载均衡(列表或单个动作)

balance.rr actions;
动作
循环 (rr) 方式下,请求均匀分布到所有后端。

最短队列优先 (sqf) 类似于循环方式,并优先选择等待队列最短的后端。

示例

balance.rr { fastcgi "127.0.0.1:9090"; };

示例

balance.rr ({ fastcgi "127.0.0.1:9090"; }, { fastcgi "127.0.0.1:9091"; });

balance.sqf (动作)

以 SQF 在动作之间进行负载均衡(列表或单个动作)

balance.sqf actions;
动作
循环 (rr) 方式下,请求均匀分布到所有后端。

mod_cache_disk_etag 会在设置了 etag 响应头时将生成的内容缓存到磁盘;如果后端发送了一个已缓存的 etag,则关闭后端并直接发送文件。

示例

balance.sqf { fastcgi "127.0.0.1:9090"; };

balance.debug (选项)

启用调试输出

balance.debug value;
默认值: false

mod_cache_disk_etag

请注意:这不会跳过后端,因为它至少需要响应头。

提示

使用如下 cron 任务来删除旧的缓存数据,例如在 crontab 中每日执行:
find /var/cache/lighttpd/cache_etag/ -type f -mtime +2 -exec rm -r {} \;

请查看 mod_deflate 以了解此模块的实际应用。

使用如下 cron 任务来删除旧的缓存数据,例如在 crontab 中每日执行:
存储缓存结果的目录

cache.disk.etag (动作)

根据 ETag 响应头缓存响应

cache.disk.etag path;
路径
这会阻塞操作进度,直到响应头完成(即,在此之前必须有一个内容生成器,例如 fastcgi/dirlist/静态文件)。您当然可以多次插入它(例如在 deflate 之前和之后)。

mod_debug 提供各种实用工具来帮助您调试问题。

示例

setup {
	module_load "mod_cache_disk_etag";
}

cache.disk.etag "/var/lib/lighttpd/cache_etag"

mod_debug

通过查询字符串(参数“con”)指定一个或多个“连接 ID”,可以请求特定连接的额外调试输出。

debug.show_connections (动作)

显示一个与 mod_status 类似的页面,列出所有活动连接

debug.show_connections;

lighttpd2 需要编译时支持分析器,并且必须通过将环境变量 LIGHTY_PROFILE_MEM 设置为目标日志文件的路径来启用分析。

示例

if req.path == "/debug/connections" { debug.show_connections; }

debug.profiler_dump (动作)

如果启用了性能分析,则将所有已分配内存转储到性能分析输出文件

debug.profiler_dump;

这是一个非常底层的开发者调试工具。

debug.show_events (动作)

显示所有事件的纯文本列表

debug.show_events;

显示事件的超时时间(默认:禁用)

示例

if req.path == "/debug/events" { debug.show_events; }

debug.show_events_after_shutdown (设置)

关机开始后记录剩余活动事件的时间(秒)

debug.show_events_after_shutdown (timeout, repeat);
超时
重复
重复显示事件的超时时间(默认:禁用)
这是一个非常底层的开发者调试工具;它显示了当 lighttpd2 应该停止时,哪些事件监听器使其保持活跃。

mod_deflate mod_deflate 实时压缩内容

示例

setup { debug.show_events_after_shutdown 5; }
setup { debug.show_events_after_shutdown 5, 15; }

mod_deflate

编码

deflate (动作)

等待响应头;如果响应可以压缩,deflate 会添加一个过滤器来压缩它

deflate options;
选项
一个包含以下条目的键值表
支持的方法,取决于编译时包含的(默认:“deflate,gzip,bzip2”)
块大小
blocksize 是每次压缩的千字节数,它允许 Web 服务器在压缩之间执行其他工作(网络 I/O)(默认:4096)
输出缓冲区
output-buffer 是每个连接用于压缩输出的缓冲区,它可以帮助减小响应大小(减少要编码的块)。如果设置为零,将使用共享缓冲区。(默认:4096)
压缩级别
0-9:数字越低表示压缩速度越快但文件/输出越大,数字越高可能压缩时间更长但文件/输出越小(取决于文件的可压缩能力),此选项用于所有选定的编码变体(默认:1)
重要:由于 deflate; 会等待响应头,您必须在此之前处理请求(请参阅下方如何检查请求是否已处理)。如果请求未被处理,您将收到“500 - 内部错误”以及 error.log 中的一条消息。

示例

deflate [ "encodings" => "deflate,gzip,bzip2", "blocksize" => 4096, "output-buffer" => 4096, "compression-level" => 1 ];

示例

deflate [ "compression-level" => 6 ];

deflate.debug (选项)

启用调试输出

deflate.debug value;
默认值: false

注意事项

不压缩

响应状态:100, 101, 204, 205, 206, 304

  • 已压缩内容
  • 如果发送了多个 etag 响应头
  • 如果未找到通用编码
  • 支持的编码

gzip, deflate (需要 zlib)

  • bzip2 (需要 bzip2)
  • deflate

修改 etag 响应头(如果存在)

  • 添加“Vary: Accept-Encoding”响应头
  • 重置 Content-Length 头
  • mod_dirlist 列出目录内的文件。输出可以通过各种方式自定义,从通过 CSS 设置样式到排除某些条目。

简单配置

setup {
	module_load "mod_deflate";
}

# define our own "action"
do_deflate = {
	# make sure static files get handled before we try deflate
	static;
	# we can only wait for response headers if we already have a request handler! (static only handles GET/HEAD requests)
	if request.is_handled {
		# limit content-types we want to compress -> see mimetypes
		if response.header["Content-Type"] =~ "^(.*/javascript|text/.*)(;|$)" {
			deflate;
		}
	}
};

# now add do_deflate; in places where you want deflate. for example at the end of your config:

do_deflate;

扩展配置(使用 mod_cache_disk_etag)

setup {
	module_load ("mod_deflate", "mod_cache_disk_etag");
}

# define our own "action"
do_deflate = {
	# make sure static files get handled before we try deflate
	static;
	# we can only wait for response headers if we already have a request handler! (static only handles GET/HEAD requests)
	if request.is_handled {
		# limit content-types we want to compress -> see mimetypes
		if response.header["Content-Type"] =~ "^(.*/javascript|text/.*)(;|$)" {
			deflate;
			# the following block needs mod_cache_disk_etag (and is optional)
			# only cache compressed result of static files
			if physical.is_file {
				cache.disk.etag "/var/cache/lighttpd/cache_etag";
			}
		}
	}
};

# now add do_deflate; in places where you want deflate. for example at the end of your config:

do_deflate;

mod_dirlist

css

dirlist (动作)

列出目录中的文件

dirlist options;
选项
一个包含以下条目的键值表
字符串:外部样式表的 URL(默认:内联内部 CSS)
隐藏点文件
布尔值:隐藏以点开头的条目(默认:true)
隐藏波浪号文件
布尔值:隐藏以波浪号 (~) 结尾的条目,常用于备份(默认:true)
隐藏目录
布尔值:从目录列表中隐藏目录(默认:false)
包含头文件
布尔值:在目录列表上方包含 HEADER.txt(默认:false)
隐藏头文件
布尔值:从目录列表中隐藏 HEADER.txt(默认:false)
编码头文件
布尔值:HTML 编码 HEADER.txt(如果包含),如果包含真正的 HTML,则设置为 false(默认:true)
包含自述文件
布尔值:在目录列表下方包含 README.txt(默认:true)
隐藏自述文件
布尔值:从目录列表中隐藏 README.txt(默认:false)
编码自述文件
布尔值:HTML 编码 README.txt(如果包含),如果包含真正的 HTML,则设置为 false(默认:true)
排除后缀
字符串列表:隐藏以所提供字符串之一结尾的条目(默认:空列表)
排除前缀
字符串列表:隐藏以所提供字符串之一开头的条目(默认:空列表)
布尔值:输出调试信息到日志(默认:false)
调试
内容类型
字符串:要在 HTTP 响应头中返回的内容类型(默认:“text/html; charset=utf-8”)
显示目录列表,包括列表上方的 HEADER.txt 内容并将其自身从列表中隐藏;同时隐藏所有以“.bak”结尾的文件

示例

mod_expire 添加“Expires”和“Cache-Control”头到响应

setup {
	module_load ("mod_dirlist");
}

if req.path =^ "/files/" {
	dirlist ("include-header" => true, "hide-header" => true, "hide->suffix" => (".bak"));
}

mod_expire

这允许您根据简单的规则/公式控制客户端的响应缓存。

如果响应使用“Expires”和“Cache-Control”头进行缓存,则客户端在达到头中指定的日期之前不会为其发出新的请求。
为 CSS、JavaScript、图像或类似静态内容添加过期头可以大大减少您收到的请求数量,从而节省资源。

如果您的内容以特定间隔(例如每 15 分钟)更改,请使用“modification”作为 <base>
规则

expire (动作)

向响应添加“Expires”头部

expire rule;
用于计算“Expires”头值的规则
此处使用的规则/公式符合 Apache mod_expire 的使用方式

<base> 是“access”、“now”或“modification”之一;“now”等同于“access”。

<base> [plus] (<num> <type>)+
  • plus”是可选的,不执行任何操作。
  • <num> 是任何正整数。
  • <type> 是“seconds”、“minutes”、“hours”、“days”、“weeks”、“months”或“years”之一。
  • <type> 中的尾随“s”是可选的。

如果您使用“modification”作为 <base> 且文件不存在或无法访问,mod_expire 将不执行任何操作,请求处理将继续进行。

过期操作将覆盖任何现有的“Expires”头。

它会将 max-age 值附加到任何现有的“Cache-Control”头。
缓存图片、CSS、TXT 和 JS 文件 1 周。

示例

mod_fastcgi 连接到 FastCGI 后端以生成响应内容

setup {
	module_load "mod_expire";
}

if req.path =~ "\.(jpe?g|png|gif|txt|css|js)$" {
	expire "access plus 1 week";
}

mod_fastcgi

套接字

fastcgi (动作)

连接到 FastCGI 后端

fastcgi socket;
要连接的套接字,可以是“ip:port”或“unix:/path”
不要混淆 FastCGI 和 CGI!并非所有 CGI 后端都可以用作 FastCGI 后端(但您可以使用 fcgi-cgi 来让 lighttpd2 运行 CGI 后端)。

例如,使用 spawn-fcgi 启动 PHP:spawn-fcgi -n -s /var/run/lighttpd2/php.sock -- /usr/bin/php5-cgi

示例

fastcgi "127.0.0.1:9090"

示例

mod_flv 提供 Flash 伪流媒体

setup {
	module_load "mod_fastcgi";
}

if phys.path =$ ".php" and phys.is_file {
	fastcgi "unix:/var/run/lighttpd2/php.sock";
}

fastcgi.log_plain_errors (选项)

是否在“backend”日志中,在 FastCGI stderr 行前添加时间戳和其他信息

fastcgi.log_plain_errors value;
默认值: false

mod_flv

允许 Flash 播放器使用“start”查询字符串参数定位文件中的(字节)偏移量,并在从该偏移量流式传输文件之前,预先添加一个简单的 Flash 头。

flv (动作)

将当前文件伪流式传输为 flash

flv;

使用“video/x-flv”作为硬编码的内容类型。

使用缓存和带宽限制来节省流量。使用较小的突发阈值以防止播放器在开始时缓冲。

示例

if phys.path =$ ".flv" {
	flv;
}

示例

此配置将使浏览器缓存视频 1 个月,并在传输 500 千字节后将带宽限制为 150 千字节/秒。

mod_fortune 从文件中加载引言(又称“幸运饼干”),并提供操作以将随机引言作为响应头 (X-fortune) 添加,或将其显示为页面。

if phys.path =$ ".flv" {
	expire "access 1 month";
	io.throttle 500kbyte => 150kbyte;
	flv;
}

mod_fortune

文件名

fortune.load (设置)

从文件中加载 cookie,可以多次调用以从多个文件加载数据

fortune.load filename;
加载 cookie 的文件
mod_gnutls 使用 GnuTLS 监听独立套接字上的 TLS 连接 (https)

fortune.header (动作)

将随机名言作为响应头“X-fortune”添加。

fortune.header;

fortune.page (动作)

显示随机 cookie 作为响应文本

fortune.page;

示例

setup {
	module_load "mod_fortune";
	fortune.load "/var/www/fortunes.txt";
}

if req.path == "/fortune" {
	fortune.page;
} else {
	fortune.header;
}

mod_gnutls

(强制)要监听的套接字地址(与“listen”:plugin_core.html#plugin_core__setup_listen 相同),可以指定多次以使用相同选项设置多个套接字

gnutls (设置)

设置 TLS 套接字

gnutls options;
选项
一个包含以下条目的键值表
listen
pem文件
(强制)包含私钥、证书、中间证书(通常不包含根证书)和 OCSP 响应的文件;或者它也可以是一个键值列表,其中包含“key”和“cert”条目,以及可选的“ocsp”条目。
PIN
使用 PKCS #11 模块或加密密钥时要使用的 PIN(或密码)。PIN 保留在内存中。
优先级
GnuTLS 优先级字符串,指定密码和其他 GnuTLS 选项(默认:“NORMAL”)
dh参数
包含生成的 dh-params 的文件名(默认:固定的 4096 位参数)
是否通过在优先级字符串后添加“:-CIPHER-ALL:+ARCFOUR-128”来强制 TLS1.0 和 SSL3.0 连接使用 RC4(默认:false)
防范 Beast 攻击
会话数据库大小
会话数据库大小,0 表示禁用会话支持(如果 GnuTLS 支持,TLS ticket 支持始终启用)
SNI 后端
用于以 SNI 服务器名称作为键来搜索证书的“fetch”后端名称(仅当 lighttpd2 中启用了 SNI 时可用)
SNI 回退 PEM 文件
如果请求包含 SNI 服务器名称,但 SNI 后端未找到任何内容时使用的证书;如果请求不包含 SNI,则使用标准的“pemfile”(s);与“pemfile”类似,它也可以是一个包含“key”和“cert”条目的键值列表。
IPv4 和 IPv6 上的简单 TLS

带简单 SNI 的 TLS

setup {
	module_load "mod_gnutls";
	gnutls (
		"priority" => "PFS:-3DES-CBC:-ARCFOUR-128:-VERS-SSL3.0:-SHA1:+SHA1:+RSA:%SERVER_PRECEDENCE",
		"listen" => "0.0.0.0:443",
		"listen" => "[::]:443",
		"pemfile" => "/etc/certs/lighttpd.pem"
	);
}

从 fetch 后端获取 SNI 的 TLS

setup {
	module_load "mod_gnutls";
	gnutls (
		"priority" => "PFS:-3DES-CBC:-ARCFOUR-128:-VERS-SSL3.0:-SHA1:+SHA1:+RSA:%SERVER_PRECEDENCE",
		"listen" => "0.0.0.0:443",
		"listen" => "[::]:443",
		"pemfile" => "/etc/certs/www.example.com.pem"
		"pemfile" => "/etc/certs/mail.example.com.pem"
	);
}

对于 SNI 主机名 example.com,lighttpd2 将尝试在 /etc/certs/lighttpd_sni_example.com.pem 中查找私钥和证书。

IPv4 和 IPv6 上的简单 TLS,使用单独的文件存储密钥和证书,以及加密密钥

setup {
	fetch.files_static "sni" => "/etc/certs/lighttpd_sni_*.pem";

	module_load "mod_gnutls";
	gnutls (
		"priority" => "PFS:-3DES-CBC:-ARCFOUR-128:-VERS-SSL3.0:-SHA1:+SHA1:+RSA:%SERVER_PRECEDENCE",
		"sni-backend" => "sni",
		"listen" => "0.0.0.0:443",
		"listen" => "[::]:443",
		"pemfile" => "/etc/certs/lighttpd.pem"
	);
}

IPv4 和 IPv6 上的简单 TLS,使用 SoftHSM

setup {
	module_load "mod_gnutls";
	gnutls (
		"priority" => "PFS:-3DES-CBC:-ARCFOUR-128:-VERS-SSL3.0:-SHA1:+SHA1:+RSA:%SERVER_PRECEDENCE",
		"listen" => "0.0.0.0:443",
		"listen" => "[::]:443",
		"pin" => "passwordForEncryptedKey",
		"pemfile" => (
			"key" => "/etc/certs/lighttpd_key.pem",
			"cert" => "/etc/certs/lighttpd_cert.pem"
		)
	);
}

IPv4 和 IPv6 上的简单 TLS,带 OCSP 装订

setup {
	module_load "mod_gnutls";
	gnutls (
		"priority" => "PFS:-3DES-CBC:-ARCFOUR-128:-VERS-SSL3.0:-SHA1:+SHA1:+RSA:%SERVER_PRECEDENCE",
		"listen" => "0.0.0.0:443",
		"listen" => "[::]:443",
		"pin" => "SoftHSM-pin",
		"pemfile" => (
			"key" => "pkcs11:model=SoftHSM;manufacturer=SoftHSM;serial=1;token=master-key;id=%ac%d5%52%69%16%09%2c%0c%9c%b0%ec%6c%3d%3b%c6%4d%55%4c%40%49;object=my-key;object-type=private",
			"cert" => "pkcs11:model=SoftHSM;manufacturer=SoftHSM;serial=1;token=master-key;id=%ac%d5%52%69%16%09%2c%0c%9c%b0%ec%6c%3d%3b%c6%4d%55%4c%40%49;object=my-key;object-type=cert"
		)
	);
}

TLS SNI 意味着客户端可以在 TLS 握手过程中未加密地发送其尝试连接的服务器主机名。

setup {
	module_load "mod_gnutls";
	gnutls (
		"priority" => "PFS:-3DES-CBC:-ARCFOUR-128:-VERS-SSL3.0:-SHA1:+SHA1:+RSA:%SERVER_PRECEDENCE",
		"listen" => "0.0.0.0:443",
		"listen" => "[::]:443",
		"pemfile" => (
			"key" => "/etc/certs/lighttpd.pem",
			"cert" => "/etc/certs/lighttpd.pem",
			"ocsp" => "/etc/certs/lighttpd-ocsp.der",
		)
	);
}

服务器名称指示 (SNI)

如果您想在同一个 IP 地址上托管多个主机名(这很常见),有一些选项可以实现(它们可以组合使用)
在证书中使用通配符作为“CommonName”(CN),例如 *.example.com(尽管这通常不匹配 example.com

  • 在证书中使用“主题备用名称”
  • 根据 TLS 握手中的 SNI 主机名提供不同的证书。
  • 支持 SNI 的客户端通常也支持其他选项,但并非所有客户端都支持 SNI。

GnuTLS 内置了一些基本的 SNI 支持;如果您在选项中指定了多个 pemfile,它将选择第一个与 SNI 主机名匹配的证书。

lighttpd2 具有可选的扩展 SNI 支持(必须在编译时启用,并且是 sni-* 选项可用的前提)。它旨在根据需求,使用 fetch API 从后端(文件、SQL 等)异步加载证书。

在这种情况下,lighttpd2 将在 GnuTLS 为连接启动之前,根据 SNI 主机名从给定的 sni-backend 获取证书。
如果客户端提供了 SNI 主机名,但在后端未找到证书,它将使用 sni-fallback-pemfile(如果已设置)而不是 pemfile
组合使用 sni-backendsni-fallback-pemfile 和多个 pemfile 不会起作用——它只会使用第一个配置的 pemfile(如果客户端未提供 SNI 主机名,否则使用 sni-* 证书)。

另请注意,lighttpd2 不会验证 SNI 主机名是否与 HTTP 请求中的主机名匹配。SNI 仅由客户端用于告诉服务器应发送哪个主机名的证书(即客户端用于验证的证书)。

GnuTLS 优先级字符串配置了可用的密码和协议版本,以及少量选项(激活的变通方法等)。

GnuTLS 优先级字符串

示例:"SECURE:-VERS-SSL3.0:-SHA1:+SHA1:-RSA:+RSA:%SERVER_PRECEDENCE"

SECURE:以 SECURE 级别开始:仅安全密码和安全曲线

  • -VERS-SSL3.0:禁用 SSL3.0 支持(所有客户端现在至少应支持 TLS1.0)
  • -SHA1:SHA1 将 SHA1 重新放回 MAC 算法列表(优先选择其他 SHA 变体)
  • -RSA:+RSA:优先选择 (RSA) DHE/ECDHE 密钥交换而不是简单的 RSA
  • %SERVER_PRECEDENCE 一个标志,告诉 GnuTLS 使用其自身的偏好顺序,而不是客户端提供的顺序。
  • 另请参阅

优先级字符串 (GnuTLS 手册)

OCSP 装订

服务器名称指示 (SNI) 应该正常工作,因为 OCSP 响应仅在与连接中使用的证书匹配时才会被使用。

如果 OCSP 响应以 PEM 块形式附加,则 fetch 后端支持 OCSP 装订。

Lighttpd 不会自动重新加载 OCSP 响应;您必须重启才能加载新的 OCSP 响应(cron 任务可能是正确的方法)。

如果您的证书和颁发者证书(签署您的证书的那个)在单独的文件中,您可以使用 GnuTLS 的“ocsptool”像这样请求 OCSP 响应

转换为 PEM 格式可以这样做

ocsptool --ask --load-issuer issuer.pem --load-cert cert.pem --outfile ocsp.der

如果您难以确定需要哪些证书,这里有更详细的解释

(echo "-----BEGIN OCSP RESPONSE-----"; base64 --wrap=64 ocsp.der; echo "-----END OCSP RESPONSE-----") > ocsp.pem

您通常在传递给 lighttpd 的 PEM 文件中有一个证书列表。第一个证书通常有一个指向您的服务器名称(CN)的“Subject”,例如:“Subject: CN=lighttpd.net”。它还有一个“Issuer”属性(例如“C=US, O=Let’s Encrypt, CN=Let’s Encrypt Authority X3”)。颁发者证书需要一个与该“Issuer”匹配的“Subject”,并且应该是 PEM 文件中的第二个证书(除非它已经是根 CA,在这种情况下通常省略)。

ocsptool 总是使用文件中的第一个证书并忽略其他证书,因此您可以在 --load-cert 之后将传递给 lighttpd 的普通 PEM 文件作为参数使用,但如果您没有单独存储颁发者证书,则需要提取它。以下 awk 脚本从文件中提取第二个 PEM 块

BEAST 被许多人认为在客户端已得到缓解,因此此变通方法不再推荐且默认禁用。

awk '
	BEGIN { block = 0 }
	/^-----BEGIN / { ++block; }
	{ if (block > 1) print; }
' "certs.pem" > "issuer.pem"

防范 Beast 攻击

如果启用,它将在 TLS1.0 及更早版本(TLS1.1 和 TLS1.2 不受影响)上强制使用 RC4;但 RC4 本身存在问题。

DHE_RSA 密钥交换需要参数(类似于 ECDHE_RSA 中使用的曲线);这些参数指定了模 p 整数乘法群的素数 p 和群生成器 g(即对于 1..p-1 中的所有 x,都存在一个 e 使得 g^e = x);有时 g 可能只创建一个足够大的子群(例如大小为 (p-1)/2 的子群)。

DH 参数

DH 密钥交换的安全性(除其他因素外)取决于 p 的位长度;因此 lighttpd 包含了默认的 4096 位参数(由 GnuTLS certtool 在 3.0.22 版本中使用 certtool --get-dh-params --bits=4096 提供),这些参数应该是安全的(一些旧客户端不支持大于 1024 位的密钥长度;如果您需要支持这些客户端,则必须禁用 DH 密钥交换或指定 1024 位参数)。

您可以使用 GnuTLS 或 OpenSSL 生成您自己的参数

certtool --generate-dh-params --bits=2048

  • openssl dhparam -dsaparam 2048
  • openssl dhparam -2 2048
  • openssl dhparam -5 2048
  • GnuTLS certtool 只生成“DSA”参数(任何带大生成器的素数),而 openssl 可以生成“DH”参数,其生成器为 2 或 5,结合 Sophie Germain 素数 (p-1)/2(即 p(p-1)/2 都是素数),或者使用 -dsaparam 选项生成“DSA”参数。

“DH”参数需要更长的时间来生成,但您可以重用其密钥(尽管不推荐,请在 openssl 手册中搜索 SSL_CTX_set_tmp_dh_callback 中的 SSL_OP_SINGLE_DH_USE)。“DSA”参数的密钥不应重复使用,即每个连接都应生成一个新的私钥,mod_gnutls 就是这种情况。lighttpd 提供的默认参数是“DH”参数。

Diffie-Hellman(-Merkle) 密钥交换

优先级字符串 (GnuTLS 手册)

mod_limit

两种限制都可以是“总数”或“每 IP”。

最大并发连接数

limit.con (动作)

将并发连接总数限制为指定限制。

limit.con (limit, action);
限制
操作
(可选)达到限制时要执行的操作
如果没有定义操作,将返回 503 错误页面。如果指定了操作,则除了在达到限制时运行指定操作外,没有其他特殊处理。

每 IP 的最大并发连接数

示例

limit.con 10;

limit.con_ip (动作)

将每个 IP 的并发连接总数限制为指定限制。

limit.con_ip (limit, action);
限制
每秒最大请求数
(可选)达到限制时要执行的操作
如果没有定义操作,将返回 503 错误页面。如果指定了操作,则除了在达到限制时运行指定操作外,没有其他特殊处理。

每 IP 的最大并发连接数

示例

limit.con_ip 2;

limit.req (动作)

将每秒请求数限制为指定限制。

limit.req (limit, action);
限制
每 IP 每秒最大请求数
(可选)达到限制时要执行的操作
如果没有定义操作,将返回 503 错误页面。如果指定了操作,则除了在达到限制时运行指定操作外,没有其他特殊处理。

每 IP 的最大并发连接数

示例

limit.req 100;

limit.req_ip (动作)

将每个 IP 的每秒请求数限制为指定限制。

limit.req_ip (limit, action);
限制
此配置片段将允许总共 10 个活动下载,以及每 IP 1 个下载。如果超过限制,无论是由于超过 10 人尝试访问此资源,还是某人已有一个下载正在运行而再次尝试,他们都将被重定向到 /connection_limit_reached.html。
(可选)达到限制时要执行的操作
如果没有定义操作,将返回 503 错误页面。如果指定了操作,则除了在达到限制时运行指定操作外,没有其他特殊处理。

每 IP 的最大并发连接数

示例

limit.req_ip 100;

限制并发连接数

此配置片段将在 /login 页面每秒被访问超过一次时,向日志写入一条包含客户端 IP 地址的消息。然而,它不会执行任何其他操作。客户端将能够随意使用 /login 页面。

setup {
	module_load ("mod_limit","mod_redirect");
}

limit_reached = {
	redirect "/connection_limit_reached.html";
};

if req.path =^ "/downloads/" {
	limit.con 10 => limit_reached;
	limit.con_ip 1 => limit_reached;
}

限制每秒请求数

mod_lua 加载 Lua 插件和操作

setup {
	module_load "mod_limit";
}

if req.path == "/login" {
	limit.req_ip 1 => { log.write "Possible bruteforce from %{req.remoteip}"; };
}

mod_lua

另请参阅 Lua API

包含 Lua 代码的文件

lua.plugin (设置)

将文件作为 lua 插件加载

lua.plugin (filename, options, lua-args);
加载 cookie 的文件
一个带有选项的键值表;目前还没有可用选项
选项
lua-args
转发到 Lua 插件的参数
Lua 插件可以通过在全局 Lua 命名空间中创建设置/操作表来注册设置和操作回调(像任何 C 模块一样)。

文件名和第三个参数 lua-args 在 Lua 脚本中作为 ... 中的参数可用。

(请参阅 contrib/core.lua 获取实际示例)

示例

setup {
	module_load "mod_lua";
	lua.plugin "secdownload.lua";
}

插件示例

文件被检查修改并重新加载的秒数。0 禁用重新加载(默认 0)

local filename, args = ...

-- args are from the lua.plugin line

local function simple(actionarg)
	-- actionarg is the parameter from the 'single "/xxx";' action line

	-- create an action:
	return action.respond()
end

actions = {
	["simple"] = simple,
}

lua.handler (动作)

将文件作为 lua 配置加载

lua.handler (filename, options, lua-args);
加载 cookie 的文件
一个带有选项的键值表;目前还没有可用选项
选项
一个包含以下条目的键值表
生存时间
lua.handler 基本与 include_lua 相同,但有以下区别:
转发到 Lua 插件的参数
Lua 插件可以通过在全局 Lua 命名空间中创建设置/操作表来注册设置和操作回调(像任何 C 模块一样)。

每个工作进程自行加载 Lua 文件

  • 它在使用前不会被加载,因此您在加载时不会看到脚本中的错误
  • 它不能调用设置函数
  • 它支持脚本参数(local filename, args = ...
  • 不锁定全局 Lua 锁,因此在使用多个工作进程时性能更佳
  • 请参阅 contrib/core.lua 了解我们如何加载某些外部操作,例如 contrib/core__xsendfile.lua

mod_core.lua 提供了一些用 Lua 编写的有用辅助工具

示例

setup {
	module_load "mod_lua";
	lua.plugin "secdownload.lua";
}

if req.path =^ "/app" {
	lua.handler "/etc/lighttpd/pathrewrite.lua", [ "ttl" => 300 ], "/app";
}

mod_core (lua)

默认情况下,发行版(和 make install)应该提供必要的文件;但您总可以在 contrib 文件夹中找到它们

安装

core.lua

  • core__cached_html.lua
  • core__xsendfile.lua
  • 这样,您可以根据自己的需要修改它们(尽管建议更改文件和操作的名称,以免发生冲突)。

lighttpd 应该在正确的(安装)位置搜索 core.lua,因此您不需要在此处使用绝对路径。

前缀

core.wsgi (动作)

将 URL 分割为 SCRIPT_NAME(Web 应用程序挂载的子目录)和 PATH_INFO(Web 应用程序应路由的路径)

core.wsgi (prefix, action);
Web 应用程序挂载的 URL 前缀(“子目录”)
连接到 WSGI 后端的动作块
(可选)达到限制时要执行的操作
请参阅 WSGI 操作指南 获取示例。

WSGI 应用程序期望 URL 被拆分为 SCRIPT_NAMEPATH_INFO(CGI 环境变量);SCRIPT_NAME 是它们的“应用程序根”,而 PATH_INFO 是应用程序中请求的资源。

默认情况下,lighttpd 使用空的 PATH_INFO(除非您使用了“pathinfo;”操作,但这无济于事,因为我们这里不处理静态文件)。
重要:WSGI 是 CGI 的“扩展”;它不指定传输协议,您可以将其与普通 CGI、FastCGI 或 SCGI(或任何其他支持基本 CGI 协议的)一起使用

示例:/trac 中的 Trac,通过 FastCGI 监听 unix:/var/run/lighttpd/trac.socket

示例

(可选)文件所在的文档根目录

setup {
	module_load ("mod_lua", "mod_fastcgi");
	lua.plugin "core.lua";
}
core.wsgi ( "/trac", { fastcgi "unix:/var/run/lighttpd/trac.socket"; } );

core.cached_html (动作)

如果我们尚未找到 URL 的静态文件,并且 URL 还没有“.html”后缀,则尝试为当前 URL 查找带有“.html”后缀的文件。

core.cached_html;

示例

setup {
	module_load "mod_lua";
	lua.plugin "core.lua";
}
docroot "/some/dynamic/app/public";
core.cached_html;
if physical.is_file {
	header.add ("X-cleanurl", "hit");
} else {
	header.add ("X-cleanurl", "miss");
	fastcgi "/var/run/lighttpd/dynamic-app.sock";
}

core.xsendfile (动作)

提供简单的 X-Sendfile 功能;从您的后端发送“X-Sendfile: /path/to/file”响应头

core.xsendfile docroot;
docroot
用户列表

示例

setup {
	module_load ("mod_lua", "mod_fastcgi");
	lua.plugin "core.lua";
}
fastcgi "/var/run/lighttpd/dynamic-app.sock";
core.xsendfile "/some/dynamic/app/";

auth.require_user (动作)

要求特定已验证用户

auth.require_user userlist;
允许的用户名列表
此辅助工具构造一个正则表达式以匹配 request.environment[“REMOTE_USER”],因此下面的示例与以下内容相同

auth.plain [ "method" => "basic", "realm" => "test", "file" => "/etc/lighttpd2/test.plain" ]; if req.env["REMOTE_USER"] !~ "^(foo1|foo2)$" { auth.deny; }

此操作仅使用 Lua 创建操作,在这种情况下不执行 Lua 来处理请求。

请注意:空用户名匹配未经身份验证的用户。

mod_secdownload.lua 使用限时代码保护文件

示例

setup {
	module_load "mod_lua";
	lua.plugin "core.lua";
}
auth.plain [ "method" => "basic", "realm" => "test", "file" => "/etc/lighttpd2/test.plain" ];
auth.require_user ("foo1", "foo2");

mod_secdownload (lua)

secdownload.lua

安装

core.lua

  • secdownload__secdownload.lua
  • 要保护的 URL 路径前缀;默认“/”

lighttpd 应该在正确的(安装)位置搜索 core.lua,因此您不需要在此处使用绝对路径。

secdownload (动作)

使用有时限的代码保护文件

secdownload options;
选项
一个包含以下条目的键值表
Web 应用程序挂载的 URL 前缀(“子目录”)
文档根目录
秘密文件在磁盘上的存储位置
密钥
用于创建和验证 URL 的共享密钥。
生成的 URL 有效时长(秒)(最大允许时间差);默认值为 60
超时
prefix 不用于构建文件名;请手动将其包含在 document-root 中(其工作方式类似于 alias "/prefix" => "/docroot",请参阅 alias)。

secdownload 实际上不处理(有效)请求,它只是提供文件名映射(并拒绝无效请求)。
要生成对 secdownload 有效的 URL,您需要相同的密钥。

示例

setup {
	module_load "mod_lua";
	lua.plugin "secdownload.lua";
}
secdownload [ "prefix" => "/sec/", "document-root" => "/secret/path", "secret" => "abc", "timeout" => 600 ];

生成 URL

URL 形式为 prefix + md5hex(secret + filepath + timestamp) + '/' + timestamp + filepath;timestamp 是格式为十六进制数字的 Unix 时间
例如使用 PHP

上面的配置示例会将此 URL 映射到文件 /secret/path/secret-file.txt

$secret = "abc";
$uri_prefix = "/sec/";

# filename; please note file name starts with "/"
$f = "/secret-file.txt";

# current timestamp
$t = time();

$t_hex = sprintf("%08x", $t);
$m = md5($secret.$f.$t_hex);

# generate link
printf('<a href="%s%s/%s%s">%s</a>', $uri_prefix, $m, $t_hex, $f, $f);

更多示例请参阅 mod_secdownload (lighttpd 1.4.x)

mod_memcached 将内容缓存到 memcached 服务器上

mod_memcached

lookup 尝试查找与键相关的数据,如果找到,则以 HTTP 正文形式返回,状态码为 200。

store 将 HTTP 正文(由另一个后端生成)存储在 memcached 中。
缓存总是需要您考虑您想要什么;您不能缓存每次请求都会更改的内容!

因此,大多数时候您可能希望为 memcached 中存储的内容设置 TTL;您的用户可能不需要在下一秒就获取新内容,也许 60 秒仍然是不错的选择(显然聊天应用不是这样…)。

另一种方法是清除动态后端中的键;您也可以从后端设置 memcached 内容,这可能比 memcached.store 更快。

如果键的长度超过 255 字节或包含超出 0x21 - 0x7e 范围的字符,我们将改用其哈希值(目前是 sha1,但可能会更改)。

服务器

memcached.lookup (动作)

在 memcached 数据库中搜索内容

memcached.lookup (options, action-hit, action-miss);
选项
一个包含以下条目的键值表
套接字地址字符串(默认:127.0.0.1:11211)
(布尔值,暂不支持)是否也查找头。如果为 false,内容类型由 request.uri.path 决定(默认:false)
查找键的模式(默认:“%{req.path}”)
命中操作
缓存命中时运行的操作(查找成功)
未命中操作
缓存未命中时运行的操作(查找不成功)
标志

memcached.store (动作)

将生成的响应存储在 memcached 数据库中

memcached.store options;
选项
一个包含以下条目的键值表
套接字地址字符串(默认:127.0.0.1:11211)
(整数)存储数据的标志(默认 0)
存储的 TTL(默认 30;如果想“永久”缓存,请使用 0)
生存时间
最大尺寸
我们希望存储的最大大小(字节)(默认:64*1024)
(布尔值,暂不支持)是否也存储头(默认:false)
(布尔值,暂不支持)是否也查找头。如果为 false,内容类型由 request.uri.path 决定(默认:false)
存储键的模式(默认:“%{req.path}”)
查找键的模式(默认:“%{req.path}”)
mod_memcached 也向每个工作进程的 luaState 导出 Lua API(用于 lua.handler)

示例

setup {
	module_load "mod_memcached";
}

memcached.lookup (["key" => "%{req.scheme}://%{req.host}%{req.path}"], {
	header.add "X-Memcached" => "Hit";
}, {
	header.add "X-Memcached" => "Miss";
	docroot "/var/www";
#	important: You need a content handler before memcached.store
	static;
	memcached.store ["key" => "%{req.scheme}://%{req.host}%{req.path}"];
});

Lua API

memcached.new(address) 创建一个新的连接;一个连接提供

req = con:get(key, cb | vr)

  • req = con:set(key, value, cb | vr, [ttl])
  • con:setq(key, value, [ttl])
  • 如果提供了回调函数,则回调函数将与响应对象一起被调用;否则,响应将在 req.response 准备就绪时可用。

响应对象包含

code:1 – 成功,2 – 未存储,3 – 已存在,4 – 未找到,5 – 错误

  • error:错误消息
  • key:查找键
  • CAS
  • (整数)存储数据的标志(默认 0)
  • 生存时间
  • 数据
  • mod_openssl 使用 OpenSSL 监听独立套接字上的 TLS 连接 (https)

mod_openssl

(强制)包含私钥、证书和(可选)中间证书的文件(通常不包含根证书)

openssl (设置)

设置 TLS 套接字

openssl options;
选项
一个包含以下条目的键值表
listen
pem文件
(强制)包含私钥、证书、中间证书(通常不包含根证书)和 OCSP 响应的文件;或者它也可以是一个键值列表,其中包含“key”和“cert”条目,以及可选的“ocsp”条目。
CA 文件
包含中间证书的文件
密码
OpenSSL 密码字符串(默认:“HIGH !aNULL !3DES +kEDH +kRSA !kSRP !kPSK”)
ECDH 曲线
包含生成的 dh-params 的文件名(默认:固定的 4096 位参数)
是否通过在优先级字符串后添加“:-CIPHER-ALL:+ARCFOUR-128”来强制 TLS1.0 和 SSL3.0 连接使用 RC4(默认:false)
OpenSSL ecdh-curve 名称
OpenSSL 选项列表(默认:NO_SSLv2, NO_SSLv3, CIPHER_SERVER_PREFERENCE, NO_COMPRESSION, SINGLE_DH_USE, SINGLE_ECDH_USE)
选项
验证
启用客户端证书验证(默认:false)
验证任何
允许所有 CA 和自签名证书,用于手动检查(默认:false)
验证深度
设置客户端验证深度(默认:1)
验证要求
终止验证失败的客户端(默认:false)
客户端 CA 文件
包含客户端 CA 证书的文件(用于验证客户端证书)
对于 ciphers,请参阅 OpenSSL ciphers 字符串

有关 options,请参阅 options。通过切换“NO_”前缀来明确指定反向标志以覆盖默认值。

带客户端证书验证的 TLS

带简单 SNI 的 TLS

setup {
	module_load "mod_openssl";
	openssl [
		"listen" => "0.0.0.0:443",
		"listen" => "[::]:443",
		"pemfile" => "/etc/certs/lighttpd.pem",
		"options" => ["ALL", "NO_TICKET"],
	];
}

带任意客户端证书的 TLS

setup {
	module_load "mod_openssl";
	openssl (
		"listen" => "0.0.0.0:443",
		"listen" => "[::]:443",
		"pemfile" => "/etc/certs/lighttpd.pem",
		"client-ca-file" => "/etc/certs/myCA.pem",
		"verify" => true,
		"verify-require" => true
	);
}

要导出的子集列表

setup {
	module_load "mod_openssl";
	openssl (
		"listen" => "0.0.0.0:443",
		"listen" => "[::]:443",
		"pemfile" => "/etc/certs/lighttpd.pem",
		"verify" => true,
		"verify-any" => true,
		"verify-depth" => 9
	);
}
openssl.setenv "client-cert";

openssl.setenv (动作)

设置 SSL 环境变量字符串

openssl.setenv list;
列表
支持的子集

“client” – 设置 SSL_CLIENT_S_DN_ 短命名条目

  • “client-cert” – 将 SSL_CLIENT_CERT 设置为客户端证书 PEM
  • “server” – 设置 SSL_SERVER_S_DN_ 短命名条目
  • “server-cert” – 将 SSL_SERVER_CERT 设置为服务器证书 PEM
  • mod_progress 通过唯一标识符跟踪连接进度(状态)

mod_progress

mod_progress 允许您使用一个查找表来跟踪连接进度(或状态),其中连接通过请求中指定的随机唯一标识符进行注册。

它最常用于实现文件上传的进度条。
对 Web 服务器的请求通过 progress.track 操作注册,并由 X-Progress-Id 查询字符串参数提供的随机唯一标识符进行跟踪。

从那一刻起,其他请求可以通过 progress.show 操作,并指定之前使用的 X-Progress-Id 来获取第一个请求的状态。
即使跟踪的请求已完成且与客户端的连接已断开,请求仍可在有限时间内获取其状态,以将其视为“完成”。
请查看那里的源代码以获得更深入的了解。

生存时间(秒)(默认:30)

progress.ttl (设置)

内部查找表中条目断开连接后的存活时间(秒)

progress.ttl ttl;
生存时间
默认值: ("POST")

progress.methods (选项)

要跟踪的请求方法

progress.methods methods;
(可选)输出格式,可以是“legacy”、“json”或“jsonp”之一。默认为“json”。

示例

setup {
	module_load "mod_progress";
	progress.methods ("PUT", "POST");
}

progress.track (动作)

如果提供了 X-Progress-ID 查询字符串键,则跟踪当前请求

progress.track;

progress.show (动作)

返回由 X-Progress-ID 查询字符串参数指定的请求的状态信息

progress.show format;
格式
输出格式

legacy: new Object({"state": "running"", "received": 123456, "sent": 0, "request_size": 200000, "response_size": 0})

  • json: {"state": "running", "received": 123456, "sent": 0, "request_size": 200000, "response_size": 0}
  • jsonp: progress({"state": "running", "received": 123456, "sent": 0, "request_size": 200000, "response_size": 0})
  • 函数名(默认“progress”)可以通过提供 X-Progress-Callback 查询字符串参数进行更改。
    JSON 对象可以包含以下成员

状态 (state)"unknown""running""done""error" 之一。

  • 已接收 (received):lighty 接收或客户端上传的字节数。
  • 请求大小 (request_size):请求或上传文件的总大小,由 Content-Length 请求头指定。
  • 已发送 (sent):lighty 发送或客户端下载的字节数。
  • 响应大小 (response_size):响应的总大小。注意:如果从后端进行流式传输,此值可能会随时间增长。
  • 状态码 (status):响应的 HTTP 状态码。
  • receivedrequest_sizesentresponse_size 仅在 state"running""done" 时可用。status 仅在 state"error" 时可用。

mod_proxy 连接到 HTTP 后端以生成响应内容

示例

setup {
	module_load "mod_progress";
}

if req.path == "/upload.php" { progress.track; }
if req.path == "/progress" { progress.show; }

progress.debug (选项)

启用调试输出

progress.debug value;
默认值: false

mod_proxy

proxy 使用 request.raw_path 作为要发送到后端的 URL(包括查询字符串)。

proxy (动作)

连接到 HTTP 后端

proxy socket;
要连接的套接字,可以是“ip:port”或“unix:/path”
不要混淆 FastCGI 和 CGI!并非所有 CGI 后端都可以用作 FastCGI 后端(但您可以使用 fcgi-cgi 来让 lighttpd2 运行 CGI 后端)。

mod_redirect 通过发送 HTTP 状态码 301 和 Location 头来重定向客户端

示例

setup {
	module_load "mod_proxy";
}

proxy "127.0.0.1:8080";

mod_redirect

它支持匹配 正则表达式 和使用捕获的子字符串及其他占位符进行 替换

一个简单的目标字符串,或一个规则(将正则表达式映射到目标字符串),或一个规则列表。

redirect (动作)

重定向客户端

redirect rule;
用于计算“Expires”头值的规则
目标字符串是一个 模式
  • 正则表达式 用于匹配请求路径(始终以“/”开头!)
  • 如果给定规则列表,重定向将在第一个匹配项处停止。
  • 默认情况下,目标字符串被解释为绝对 URI;如果它以“?”开头,它将替换查询字符串;如果以“/”开头,它将替换当前路径;如果以“./”开头,则相对于路径中的当前“目录”进行解释。
  • 示例:始终重定向(HTTP 到 HTTPS)

示例:始终重定向(添加 www 前缀)

setup {
	module_load "mod_redirect";
}
if request.scheme == "http" {
	if request.query == "" {
		redirect "https://%{request.host}%{enc:request.path}";
	} else {
		redirect "https://%{request.host}%{enc:request.path}?%{request.query}";
	}
}

示例:如果匹配则重定向

setup {
	module_load "mod_redirect";
}
if request.host !~ "^www\.(.*)$" {
	if request.query == "" {
		redirect "http://www.%{request.host}%{enc:request.path}";
	} else {
		redirect "http://www.%{request.host}%{enc:request.path}?%{request.query}";
	}
}

重定向所有非 www. 的请求。例如:将 foo.tld/bar?x=y 重定向到 www.foo.tld/bar?x=y

setup {
	module_load "mod_redirect";
}
redirect "^/old_url$" => "http://new.example.tld/url"

示例

mod_rewrite 修改请求路径和查询字符串

if request.host !~ "^www\.(.*)$" {
	redirect "." => "http://www.%1/$0?%{request.query}";
}

redirect.debug (选项)

启用调试输出

redirect.debug value;
默认值: false

mod_rewrite

如果您的重写目标不包含任何问号(?),则查询字符串将不会被修改。

一个简单的目标字符串,或一个规则(将正则表达式映射到目标字符串),或一个规则列表。

如果它包含 ?,则查询字符串将被 ? 之后的部分覆盖。要追加原始查询字符串,请使用 %{request.query}
重要:重写只改变 URL,而不改变通过 docroot 或 alias 操作映射到的物理文件名。因此,您需要在重写之后再执行 docroot 和 alias 操作。

如果您有条件重写,例如 if !phys.is_file { rewrite ... },您需要在其之前(以便检查物理文件)和之后(以构建新的物理路径)都进行 docroot/alias 操作。
正则表达式 用于匹配请求路径(始终以“/”开头,且包含查询字符串!)

rewrite (动作)

修改请求路径和查询字符串

rewrite rule;
用于计算“Expires”头值的规则
目标字符串是一个 模式
  • 正则表达式 用于匹配请求路径(始终以“/”开头!)
  • 如果给定规则列表,重写将在第一个匹配项处停止。
  • 仅当目标字符串包含 ? 时替换查询字符串
  • 示例:始终重写

示例:如果匹配则重写

setup {
	module_load "mod_rewrite";
}
rewrite "/new/path";

示例:首次匹配时重写

setup {
	module_load "mod_rewrite";
}
rewrite "regex" => "/new/path";

示例:美观的 URL

setup {
	module_load "mod_rewrite";
}
rewrite ("regex1" => "/new/path1", ..., "regexN" => "/new/pathN");

注意:您应该将此类重写的逻辑实际移到您的应用程序中,并且只需将所有美观的 URL 重写到您的 index.php,而无需将操作放入查询字符串中。

rewrite 类似,但匹配原始路径(即 URL 解码和清理之前的路径),并且结果再次被解码。

setup {
	module_load "mod_rewrite";
}

# bad: routing login in webserver config:
rewrite (
	"^/article/(\d+)/.*$" => "/article.php?id=$1",
	"^/download/(\d+)/(.*)$" => "/download.php?fileid=$1&filename=$2"
);
rewrite "^/user/(.+)$" => "/user.php?name=$1";

# good: handle it in the backend (easier to port the config)
rewrite "^/(article|download|user)(/|$)" => "/index.php";

rewrite_raw (动作)

修改请求路径和查询字符串,匹配和写入原始路径

rewrite_raw rule;
用于计算“Expires”头值的规则
目标字符串是一个 模式

rewrite 将结果写入 request.path 和可能的 request.query,并使用 URL 编码从这些生成 request.raw_path

rewrite_raw 写入 request.raw_path 并将其解码为 request.pathrequest.query;这意味着查询字符串总是被覆盖。
在这两种情况下,request.path 之后都会被简化。
mod_scgi 连接到 SCGI 后端以生成响应内容

rewrite.debug (选项)

启用调试输出

rewrite.debug value;
默认值: false

mod_scgi

mod_status 显示一个包含内部统计信息的页面,例如请求数量(总数或每秒)、活动连接等。

scgi (动作)

连接到 SCGI 后端

scgi socket;
要连接的套接字,可以是“ip:port”或“unix:/path”
不要混淆 FastCGI 和 CGI!并非所有 CGI 后端都可以用作 FastCGI 后端(但您可以使用 fcgi-cgi 来让 lighttpd2 运行 CGI 后端)。

示例

setup {
	module_load "mod_scgi";
}

if req.path =^ "/RPC2" {
	scgi "127.0.0.1:5000";
}

mod_status

模式

status.css (选项)

定义要使用的样式表。可用值:未设置(默认)、"blue" 或您希望的任何 URL

status.css url;
默认值: 未设置

示例

status.css = "blue";

status.info (动作)

向客户端返回状态页面

status.info mode;
(可选)“short”
“short”模式会移除连接和运行时详情(推荐用于“公共”状态)。

状态页面接受以下查询字符串参数

?mode=runtime:显示运行时详情

  • format=plain:以纯文本格式显示“short”统计信息
  • 如果请求 /server-status,则显示一个包含 lighttpd 统计信息的页面。

示例

mod_throttle 限制传出带宽使用

setup {
	module_load "mod_status";
}

if req.path == "/server-status" {
	status.info;
}

mod_throttle

所有速率均以字节/秒为单位。缓冲池以固定间隔填充(编译时常量;默认为 200 毫秒)。

速率

io.throttle (动作)

为当前连接设置出站限制

io.throttle (rate, burst);
字节/秒限制
突发
可选,默认为 2*rate
burstmagazine 的初始和最大值;进行 IO 会耗尽 magazine,而 magazine 会随着时间以指定的 rate 再次填充。

同一池中的所有连接作为一个整体受到限制。每个 io.throttle_pool 操作都会创建自己的池。

io.throttle_pool (动作)

将当前连接添加到出站限制池中

io.throttle_pool rate;
字节/秒限制
突发

在多个地方使用同一个池

示例

同一池中来自同一 IP 地址的所有连接作为一个整体受到限制。每个 io.throttle_ip 操作都会创建自己的池。

setup {
	module_load "mod_throttle";
}
downloadLimit = {
	io.throttle_pool 1mbyte;
}
# now use it wherever you need it...
downloadLimit;

io.throttle_ip (动作)

将当前连接添加到基于 IP 的出站限制池中

io.throttle_ip rate;
字节/秒限制
突发

mod_userdir 允许您通过 http://domain/~user/ 访问用户特定的文档根目录

示例

同一池中来自同一 IP 地址的所有连接作为一个整体受到限制。每个 io.throttle_ip 操作都会创建自己的池。

setup {
	module_load "mod_throttle";
}
downloadLimit = {
	io.throttle_ip 200kbyte;
}
# now use it wherever you need it...
downloadLimit;

mod_userdir

文档根目录可以通过使用请求路径开头由 /~username/ 指定的用户主目录来构建。

或者,mod_userdir 可以从类似于 vhost.pattern 的模式构建文档根目录,但使用用户名代替主机名。
用于构建文档根目录的路径

userdir (动作)

通过将路径中的某些占位符替换为用户名(部分)来构建文档根目录。

userdir path;
路径
如果 path 不以斜杠 (/) 开头,则文档根目录将以 /etc/passwd 中指定的用户主目录作为前缀。

否则,path 指定要使用的绝对文档根目录。
占位符有

* 被完整用户名替换

  • $1-$9 被用户名的第 n 个字母替换,例如 $2 是第二个字母
  • 示例

请求 http://host/~lighty/foo.html(假设“/home/lighty”是“lighty”用户的主目录)

物理路径

路径 docroot “public_html”
/home/lighty/public_html/ /home/lighty/public_html/foo.html “/usr/web/*/”
/usr/web/lighty/ /usr/web/lighty/foo.html “/usr/web”
“/www/users/$1/$1$2/*/” /usr/web/lighty/foo.html “/usr/web”
/www/users/l/li/lighty/ /www/users/l/li/lighty/foo.html 注意:出于安全原因,不允许使用用户名“root”。

mod_vhost 提供了多种实现虚拟网站主机的方式

示例

setup {
	module_load "mod_userdir";
}

userdir "public_html";

mod_vhost

它可以将主机名映射到操作,并提供多种方式来实现。

这些方式在映射的灵活性(映射什么以及映射到什么)和性能上有所不同。
以主机名为键、操作为值的键值列表

vhost.map (动作)

将给定的主机名映射到动作块

vhost.map mapping;
映射
vhost.map 提供快速(通过哈希表查找)和灵活的映射,但只映射精确的主机名(不支持模式/正则表达式匹配)。服务器端口绝不被视为主机名的一部分。使用键 default(关键字,而非字符串)来指定默认操作。

以主机名的正则表达式为键、操作为值的键值列表

示例

vhost.map ["host1" => actionblock1, "host2" => actionblock2, ..., "hostN" => actionblockN, default => actionblock0];

vhost.map_regex (动作)

将匹配的主机名模式映射到动作块

vhost.map_regex mapping;
映射
vhost.map_regex 按照给定顺序遍历列表,并在第一个匹配项处停止;如果没有正则表达式匹配,它将使用 default 操作(如果已指定)。

两种操作也可以结合使用。

示例

vhost.map_regex ["host1regex" => actionblock1, "host2regex" => actionblock2, ..., "hostNregex" => actionblockN, default => actionblock0];

vhost.debug (选项)

启用调试输出

vhost.debug value;
默认值: false

示例

它的作用(例如)

如果请求 example.comwww.example.com,则执行名为“examplesite”的块

  • 如果请求 mydomain.tld,则执行名为“mydomain”的块
  • 如果请求 mydomain.comwww.mydomain.net,则执行名为“mydomain”的块(通过正则表达式匹配)
  • 如果请求 www.mydomain.tld 或其他完全不同的内容,则执行名为“defaultdom”的块
  • 如果请求的是 www.mydomain.tld 或其他完全不同的内容,则名为“defaultdom”的块将被执行
setup {
	module_load "mod_vhost";
}

examplesite = {
	#... more config here ...
};

mydomain = {
	#... more config here ...
};

defaultdom = {
	#... more config here ...
};

vhost.map [
	"example.com" => examplesite,
	"www.example.com" => examplesite,
	"mydomain.tld" => mydomain,
	default => {
		vhost.map_regex [
			"^(www\.)?mydomain\.(com|net|org)$" => mydomain,
			default => defaultdom
		];
	}
];