主配置
每个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)
对比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
。
包含文件也会创建一个新的嵌套作用域。
调试打印
与包含文件类似,__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”] | 响应头(阻止请求直到响应头可用) |
条件运算符
操作符 | 描述 | 操作符 | 描述 |
---|---|---|---|
== | 比较两个值是否相等 | != | 不等于 |
<= | 小于或等于 | < | 小于 |
>= | 大于或等于 | > | 大于 |
=~ | 正则表达式匹配 | !~ | 正则表达式不匹配 |
=^ | 前缀匹配 | !^ | 前缀不匹配 |
=$ | 后缀匹配 | !$ | 后缀不匹配 |
=/ | CIDR 匹配 | !/ | CIDR 不匹配 |