从 Apache 迁移到 lighttpd¶
配置基础¶
Lighttpd 是替代现有 Apache 或 Apache2 系统的绝佳选择。
请从阅读 配置:文件语法 开始。配置语法最初的学习曲线最为陡峭,但一旦熟悉它,您将看到它的灵活性。Lighttpd 配置最强大的功能之一是其条件语句。Lighttpd 允许您根据客户端请求设置配置选项。条件语句可以嵌套,因此您可以创建一些非常复杂但有效的配置选项。条件语句是人们从 Apache/Apache2 迁移时遇到的许多问题的关键解决方案。
您应该熟悉正则表达式,才能真正体会 Lighttpd 条件语句的灵活性。您将在配置文件中使用条件语句来处理多种事务,例如身份验证、URL 重写、虚拟主机等等。所有可在条件语句中使用的变量都列在 配置:文件语法 中,并附有关于匹配运算符的进一步说明。
问:如何在除 /download 目录之外的所有地方启用目录列表?
####### Enable dir listing for all directories dir-listing.activate = "enable" ####### If the URL is like ^/download/ then disable dir-listing $HTTP["url"] =~ "^/download/" { dir-listing.activate = "disable" }
问:如何限制状态页面仅在本地网络中可用?
$HTTP["remoteip"] == "10.0.0.0/8" { status.status-url = "/server-status" }
问:如何仅在主机是 www2.example.org 且 URL 在
/download/
下时启用目录列表?条件可以嵌套
$HTTP["host"] == "www2.example.org" { server.document-root = "/var/www/servers/www2.example.org/pages/" $HTTP["url"] =~ "^/download/" { dir-listing.activate = "enable" } }有关更多条件示例,请阅读
基本选项¶
Options +FollowSymLinks
变为 server.follow-symlink = "enable"
访问日志¶
mod_accesslogaccesslog.format = "..."
支持许多与 Apache 中相同的选项。日志文件轮换也与 Apache 中的处理方式类似,例如
- Debian 包中使用的 logrotate
如果您不使用 Debian 包,请将 ./debian/lighttpd.logrotate 复制到 /etc/logrotate.d/
当需要轮换日志时,logrotate 会向 lighttpd 发送 SIGHUP 信号,lighttpd 将相应地重新打开日志。 - cronolog
使用 cronolog,您可以将访问日志通过管道传输到一个外部程序,让该程序处理日志文件写入。
accesslog.filename = "|/usr/sbin/cronolog /web/logs/%Y/%m/%d/access.log"
重写¶
mod_rewrite 可能更复杂。Lighttpd 中规则的编写方式与 Apache 大相径庭。Lighttpd 始终匹配用户提交的完整相对请求 URI(且未进行 URL 解码)。- 在 lighttpd 1.4.50 及更高版本中,
${qsa}
可用于正则表达式替换中,以附加请求中的查询字符串,类似于 Apache 的 rewrite QSA 标志。 - 在 lighttpd 1.4.50 之前的版本中,我们可以通过匹配查询字符串并将其添加回目标来模拟 Apache 的 QSA 标志(“query string append”;参见 Apache 中的 mod_rewrite)。
url.rewrite = ( "^/something/(\d+)(?:\?(.*))?" => "/index.php?bla=$1&$2" )
重要的是(?:\?(.*))?
,它匹配查询字符串并使用$2
(正则表达式的第二个捕获括号)插入到目标 URL 中。?:
使周围的括号不捕获。
以下示例基于 dbird@freenode 发送的来自 dir.onlinesearch.ws 的一个问题。
RewriteEngine On RewriteBase /instadir/ RewriteCond %{REQUEST_FILENAME} -d # Fix trailing slash problem RewriteRule ^(.+[^/])$ $1/ [R,L] # Do not try to treat the following resources as parameters to index.php RewriteRule ^index\.php.*$ - [L] RewriteRule ^dmoz\.css$ - [L] RewriteRule ^admin[/]?.*$ - [L] RewriteRule ^img[/]?.*$ - [L] RewriteRule ^[/]{0,}(.*)$ index.php?area=browse&cat=$1 [QSA,L]
这些重写规则旨在将除 index.php、dmoz.css、admin-interface 或图像目录中的内容之外的所有内容重写为 index.php 页面的一个参数。此匹配的基本目录是
/instadir/
。下面的第一个模式使用了名为 零宽度负向先行断言 的正则表达式语法,这是您的 正则表达式书籍 中高级章节的内容。## for all URLs in /instadir/ that are not index.php, dmoz.css, admin or img, do ... url.rewrite-once = ( "^/instadir/(?!index\.php|dmoz\.css|admin|img).*" => "$0", "^/instadir/([^?]*)(?:\?(.*))?" => "/instadir/index.php?area=browse&cat=$1&$2")
在 lighttpd 1.4.50 及更高版本中,上述内容可以简化为
## for all URLs in /instadir/ that are not index.php, dmoz.css, admin or img, do ... url.rewrite-once = ( "^/instadir/(?!index\.php|dmoz\.css|admin|img)" => "", "^/instadir/([^?]*)" => "/instadir/index.php?area=browse&cat=$1${qsa}")
如果某些 Apache 重写规则的组合无法用 Lighttpd mod_rewrite 规则编写,那么另一个选项是 Lighttpd mod_magnet,它使用 Lua(一种真正的编程语言)。可以使用 Lighttpd mod_magnet 代替 mod_rewrite 编写任意复杂的逻辑。
FastCGI¶
如果您在 Apache 中为 FastCGI 处理程序分配了两个扩展名,例如AddType fastcgi-php .php .phtml
那么您需要告诉 lighttpd mod_fastcgi 将这些扩展名视为相同。
fastcgi.map-extensions = ( ".phtml" => ".php" ) fastcgi.server = ( ".php" => (( "bin-path" => "/my/fastcgi-php", "socket" => "/path/to/php.socket" )), )
如果您需要在同一设置中使用 PHP 和 Python,只需添加两个扩展名。
fastcgi.server = ( ".php" => (( "bin-path" => "/my/fastcgi-php", "socket" => "/path/to/php.socket" )), ".py" => (( "host" => "127.0.0.1", "port" => 3200 )) )
对于上面的示例,Python 是在外部生成的,正在等待来自 localhost 端口 3200 的请求。
!MultiViews¶
如何设置类似于 Apache 的 MultiViews 选项 的机制?
幸运的是,Christian Hoffman 编写了一个 Lua 脚本 来实现此功能。以下是使用方法:
server.modules = ( "mod_magnet", ) server.document-root = "/var/www" magnet.attract-physical-path-to = ( server.document-root + "/multiviews.lua" )
另一个选项是 content-negotiation.lua
目录 !ForceType 迁移¶
有几个 PHP 包和教程使用 Apache 的 ForceType 指令而不是 mod_rewrite。它们将其用作一种对搜索引擎友好的方式,将参数作为伪目录传递。
假设您有以下设置:- 您的脚本名为 news(注意没有 php 扩展名)
- 您的 URL 看起来像 /news/100/(/news/_新闻的 ID_)
- 您的脚本通过 $_GET!['PHP_SELF'] 获取新闻 ID
并且 Apache 配置了 Location 或 LocationMatch 条目,如下所示:
<Location /news> ForceType application/x-httpd-php </Location>最简单的迁移方式是:
- 首先使用 lighttpd 设置 PHP 并确保 .php 扩展名工作正常
- 将文件名 news 重命名为 news.php
- 使用 lighttpd 重写规则替换 Forcetype 条目
在 lighttpd 配置文件中:
url.rewrite-once = ("^/news/.*" => "/news.php")
如果您的脚本仍然无法工作,请尝试替换
$_GET!["PHP_SELF"] 为 $_GET!["REQUEST_URI"]。您通常可以在脚本顶部找到它。
PHP 在 FastCGI 中运行时无法正确注册 PHP_SELF。
美观的 URL(或“.php”脚本自动检测)¶
在迁移后,我遇到了一个问题,即复制我旧的 Apache1.x + PHP 设置时,原来 '''http://server.com/script/blah''' 可以顺利运行 ''script.php_ with arguments _/blah''。这对于轻松创建美观的 URL 非常有用。
我找不到一种简单的解决方案来复制这种行为,或者在这里的文档中也没有找到任何条目,所以我决定分享我的发现。本质上,有两种半通用方法可以复制这种行为,这样您就不必重新编码/重命名实际脚本。
如果您乐于重命名,您或许可以使用 lighttpd 的 forcetype 支持来使事情正常工作。
mod_rewrite 解决方案¶
这是我选择的方法,因为它更快,而且看起来更简洁。基本上我添加了:
include "mod_rewrite.conf"
... 然后创建该文件,内容为...
url.rewrite-repeat = ( "/script/(.*)" => "/script.php/$1" )
我想您也可以通过命名每个脚本来以半通用的方式实现这一点。
url.rewrite-repeat = ( "/(script|script2|script3)/(.*)" => "/$1.php/$2" )
404 处理程序解决方案¶
这可能速度会慢一点点,但如果您的 URL 重写中考虑了更复杂的(即:不纯粹的正则表达式)因素,这可能是一个更好的主意。您也可以使用 PHP preg_match() 复制上面的正则表达式。只需添加:
server.error-handler-404 = "/404.php"
... 然后在该文件中编写您的处理程序。
!ScriptAlias¶
$HTTP["host"] == "example.com" { alias.url = ( "/bin/" => "/path/to/my/bin/" ) $HTTP["url"] =~ "^/bin" { cgi.assign = ( ".pl" => "/usr/bin/perl" ) } }
另一种解决方案是使用 mod_alias,配合
cgi.assign = ( ".py" => "/usr/bin/python" ) alias.url = ( "/chrome" => var.basedir + "/foo.org/chrome", "" => var.basedir + "/foo.org/dispatch.py" )
缺少结尾的 '/' 将作为通配符。
在此脚本内部,获取环境变量 'REQUEST_URI' 以找出“美观的”结尾字符串。
在 Python 中,这将是:os.environ['REQUEST_URI'](省略导入),在 PHP 中:$_SERVER['REQUEST_URI']。
.htaccess 类似功能¶
.htaccess 类似功能
Apache .htaccess 替代方案
任意复杂的逻辑¶
如果 lighttpd 模块不原生支持特定的逻辑集,则还有另一个选项:lighttpd mod_magnet。
任意复杂的逻辑可以写入 Lua 脚本并通过 mod_magnet 运行。