简介
运行 lighttpd2
lighttpd 需要两个配置文件,通常位于以下两个位置
-
/etc/lighttpd2/lighttpd.conf
: 主配置文件,参见主配置文件。它可以分成多个文件,参见包含。 -
/etc/lighttpd2/angel.conf
: Angel 配置文件,参见Angel 配置。
源码中的 contrib/
目录包含示例配置文件。
然后使用以下命令启动 lighttpd2
/usr/sbin/lighttpd2 -c /etc/lighttpd2/angel.conf
此进程不会fork到后台,如果您需要,则必须自行操作。
我们推荐的 lighttpd2 运行方式是 runit (请查看 contrib/service
目录)。
主配置文件
每个 Web 服务器的核心都是配置文件。它控制着所有的行为,因此必须强大,同时又要足够简单,以便轻松获得所需的结果。
在 lighttpd 配置中,您控制它如何响应请求。为了实现这一点,您必须表达某种逻辑——就像在编程语言中一样。
值
布尔值
有两个布尔值
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) true
(true
映射到1
,false
映射到0
) cast(string) 5
表达式可以分组以覆盖默认关联
-
3 * (1 + 2)
vs.3 * 1 + 2
等
动作块
一个动作块由一个函数调用列表(在动作上下文中)和条件语句组成;它被视为一个值,即可以赋值给变量并在函数调用中用作参数。
动作块也可以包含变量赋值和设置块/函数调用,这些不属于“动作块值”本身,但在解析配置时进行评估。
语法是
{ log "hello world"; if req.path =$ ".hidden" { static; } }
完整的配置也是一个动作块(但没有周围的花括号);条件语句也使用动作块作为其分支。
每个非条件分支的动作块都会启动一个新的嵌套变量作用域;
变量
变量名以字母字符(a-z
和 A-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”的等价物。
它们通过对条件变量和在运行时(针对每个请求)评估的值进行比较来创建。
条件可以嵌套,您可以使用 and
和 or
运算符将它们分组。and
比 or
绑定更强,尽管更倾向于使用括号将它们分组。
示例
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> { ... } ...
(继续使用else
或else 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_lua
和lua.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 直接支持
true
和false
- 整数: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 action(
act = 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
只被评估一次),因此字段名和方法名位于同一命名空间中。
这意味着我们的容器类型无法提供对与方法同名字段的访问(并且此处未列出以“__”开头的方法),因此您必须使用显式访问方法来读取此类容器中的通用字段(写入不是问题,因为我们不允许写入方法)。
所有容器类型都应提供 get
和 set
方法,以提供对容器内容的“干净”访问。
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 关联),并且每次调用都会前进,忽略 obj
和 k
参数。
全局常量
liHandlerResult
枚举值
lighty.HANDLER_GO_ON
lighty.HANDLER_COMEBACK
lighty.HANDLER_WAIT_FOR_EVENT
lighty.HANDLER_ERROR
全局方法
-
lighty.print
(和lighty.error
和print
): 通过 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(...)
: 通过 luatostring
方法在虚拟请求上下文中以 ERROR 级别打印参数 -
warning(...)
: 通过 luatostring
方法在虚拟请求上下文中以 WARNING 级别打印参数 -
info(...)
: 通过 luatostring
方法在虚拟请求上下文中以 INFO 级别打印参数 -
debug(...)
: 通过 luatostring
方法在虚拟请求上下文中以 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 系统上可用 |
选项
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;
示例
debug.log_request_handling true;
static.range_requests (选项)
启用范围请求
static.range_requests value;
示例
static.range_requests false;
keepalive.timeout (选项)
保持活动连接的开放时间(秒)
keepalive.timeout timeout;
示例
keepalive.timeout 30;
keepalive.requests (选项)
客户端在一个连接中允许发出的最大请求数
keepalive.requests requests;
示例
keepalive.requests 10;
etag.use (选项)
用于计算 etag 的属性列表;指定空列表以禁用 etag。可用值:“inode”、“mtime”、“size”
etag.use properties;
示例
etag.use ();
stat.async (选项)
启用异步 stat() 调用
stat.async value;
如果文件名在 lighttpd 的 stat“缓存”中,lighttpd 会假定内核仍然在内存中保留该条目,因此 stat()
不太可能阻塞。
否则,它将要求后台线程调用 stat()
,这样主工作线程就不会等待慢速磁盘(或网络文件系统),但前提是 stat.async
已启用。
如果您知道您的磁盘足够快(也许是内存盘?),并且想要节省到后台线程的上下文切换,您可以禁用此功能。
buffer_request_body (选项)
在磁盘上启用请求体缓冲
buffer_request_body value;
某些后端喜欢在转发/处理响应之前等待完整的响应。为此,它们需要此选项以节省一些内存。
strict.post_content_length (选项)
要求 POST 请求的 Content-Length
strict.post_content_length value;
某些客户端在发送空正文的 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/”+当前版本。
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 配置)。
在以下情况下不执行任何操作:
- 请求已被处理
- 未设置物理路径(缺少
docroot
、alias
等) - 物理路径指向一个目录
所有其他问题都会导致错误页面,例如:
- 错误的请求方法 (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.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;
mod_accesslog
mod_accesslog 将 lighttpd 处理的请求记录到文件、管道或 syslog 中。日志格式可以使用 printf 风格的占位符进行自定义。
accesslog.format (选项)
定义日志格式
accesslog.format format;
一些格式说明符需要一个强制键,该键用大括号括起来,位于百分号和实际说明符之间。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;
示例
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;
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;
注意事项
不压缩
响应状态: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;
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-backend
、sni-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 手册)
- GnuTLS 优先级字符串
- gnutls-cli -l --priority "SECURE:-VERS-SSL3.0:-SHA1:+SHA1:-RSA:+RSA:%SERVER_PRECEDENCE"
OCSP 装订 用于向客户端保证证书仍然有效(即未被撤销);您可以将 OCSP 响应放入证书文件中的“OCSP RESPONSE”-PEM 块中(可能没有标准,只需将您拥有的 DER 响应进行 base64 编码),或者在“pemfile”块中使用“ocsp”将(DER 或 PEM 格式的)OCSP 响应指定为单独的文件。
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_NAME
和 PATH_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;
示例
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 状态码。
-
received
、request_size
、sent
和response_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;
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;
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.path
和 request.query
;这意味着查询字符串总是被覆盖。
在这两种情况下,request.path
之后都会被简化。
mod_scgi 连接到 SCGI 后端以生成响应内容
rewrite.debug (选项)
启用调试输出
rewrite.debug value;
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
burst
是magazine
的初始和最大值;进行 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;
示例
它的作用(例如)
如果请求 example.com
或 www.example.com
,则执行名为“examplesite”的块
- 如果请求
mydomain.tld
,则执行名为“mydomain”的块 - 如果请求
mydomain.com
或www.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
];
}
];