https://sqlite.org/althttpd/dir?ci=tip (推荐)
https://github.com/jesrui/althttpd/tree/master (旧版本)
https://sqlite.org/althttpd/file?name=althttpd.md&ci=tip
轻量级 web 服务器,设计宗旨是追求简洁、安全和低资源占用。
设计理念
Althttpd通常是通过xinetd、systemd或类似的工具启动的。针对每个传入的连接启动一个单独的进程,该进程完全专注于为该连接提供服务。单个althttpd进程将处理同一连接上的一个或多个HTTP请求。当连接关闭时,althttpd进程退出。
Althttpd还可以独立运行。Althttpd本身监听端口80以接收传入的HTTP请求(或端口443以接收传入的HTTPS请求),然后复制自身以处理每个传入的连接。每个连接仍然使用单独的进程处理。唯一的区别是连接处理程序进程现在是由主althttpd实例启动的,而不是由xinetd或systemd启动。
Althttpd没有配置文件。所有配置都使用一些命令行参数处理。这有助于保持配置的简单性,并减轻了通过错误配置的Web服务器引入安全漏洞的担忧。
由于每个althttpd进程只需为单个连接提供服务,althttpd是单线程的。此外,每个进程的生命周期仅为单个连接的持续时间,这意味着althttpd不需要过多担心内存泄漏。这些设计因素有助于保持althttpd源代码的简洁性,便于进行安全审计和分析。
用于服务TLS连接有两个选项:
TLS:传输层安全性协议(TLS),是一种网络协议,用于保护在两个通信应用程序之间传输的数据的安全性和隐私性。TLS的前身是安全套接层协议(SSL)。TLS和SSL之间存在一些技术差异,但它们的基本目标相同。
TLS的主要功能包括:数据加密、身份验证、数据完整性。
HTTPS(超文本传输安全协议)是在HTTP协议上使用TLS的变体,用于加密和保护Web页面的数据传输。
althttpd的完整源代码包含在一个单独的C代码文件中,没有依赖于标准C库之外的任何内容,只有在选择ENABLE_TLS选项时才需要OpenSSL。源代码文件命名为"althttpd.c"。要构建和安装althttpd,请运行以下命令:
gcc -Os -o /usr/bin/althttpd althttpd.c
-Os 用于指定编译器优化代码大小而非执行速度。
althttpd的源代码有详细的注释,并且易于访问。对于特殊需求,定制化应该相对容易。
要使用libssl构建带有内置TLS支持的althttpd:
gcc -Os -o /usr/bin/althttpd -fPIC -DENABLE_TLS althttpd.c -lssl -lcrypto
SQLite网站使用静态构建,因此在服务器上不需要安装OpenSSL。
以下是sqlite.org上/etc/xinetd.d/http文件的完整内容,配置althttpd以在IPv4和IPv6上提供未加密的HTTP请求。您可以将其用作创建自己安装的模板。
如果您更愿意使用systemd,有一个附近的单独教程介绍如何执行该操作。但是,即使只是为了更好地了解althttpd的期望,您仍然可以查看此处的说明。
service http
{
port = 80
flags = IPv4
socket_type = stream
wait = no
user = root
server = /usr/bin/althttpd
server_args = -logfile /logs/http.log -root /home/www -user www-data
bind = 45.33.6.223
}
service http
{
port = 80
flags = REUSE IPv6
bind = 2600:3c00::f03c:91ff:fe96:b959
socket_type = stream
wait = no
user = root
server = /usr/bin/althttpd
server_args = -logfile /logs/http.log -root /home/www -user www-data
}
关键观察点在于端口80上的每个传入TCP/IP连接都会启动一个/usr/bin/althttpd的副本,并带有一些额外的参数,这些参数等于web服务器的配置。
请注意,althttpd作为超级用户运行。这不是必需的,但如果这样做,然后althttpd将自身移动到Web文档层次结构的根(例如,示例中的/home/www)的chroot监狱中,然后在读取任何内容之前放弃所有超级用户权限。-user选项告诉althttpd在进入chroot监狱后变为用户www-data。
-root选项(始终应为绝对路径)告诉althttpd在哪里找到文档层次结构。在sqlite.org的情况下,所有内容都是从/home/www提供的。在此文档层次结构的顶级是一堆以".website"结尾的目录。每个这样的目录都是一个单独的网站。目录的选择基于传入HTTP请求的Host参数。sqlite.org的目录部分列表如下:
3dcanvas_tcl_lang_org.website
3dcanvas_tcl_tk.website
androwish_org.website
canvas3d_tcl_lang_org.website
canvas3d_tcl_tk.website
cvstrac_org.website
default.website
fossil_scm_com.website
fossil_scm_hwaci_com.website
fossil_scm_org.website
system_data_sqlite_org.website
wapp_tcl_lang_org.website
wapp_tcl_tk.website
www2_alt_mail_net.website
www_androwish_org.website
www_cvstrac_org.website
www_fossil_scm_com.website
www_fossil_scm_org.website
www_sqlite_org.website
对于每个传入的HTTP请求,althttpd获取请求头中Host参数的文本,将其转换为小写,并将所有ASCII字母数字之外的字符更改为"_"。结果确定用于内容的子目录。如果没有匹配项,则将使用"default.website"目录作为回退。
例如,如果Host参数是"www.SQLite.org",则将其名称转换为"www_sqlite_org.website",并且这是用于提供内容的目录。如果Host参数是"fossil-scm.org",则使用"fossil_scm_org.website"目录。通常,两个或更多名称指向同一个网站。例如,fossil-scm.org、www.fossil-scm.org、fossil-scm.com和www.fossil-scm.com都是同一个网站。在这种情况下,通常只有一个目录是真正的目录,其他目录是符号链接。
在仅托管单个网站的最小安装中,只需有一个名为"default.website"的子目录即可。
在*.website目录内,要提供的文件由HTTP请求URI选择。标记为可执行的文件将作为CGI运行。以".scgi"结尾并且内容形式为"SCGI hostname port"的非可执行文件将SCGI请求中继到hostname:port。所有其他非可执行文件都按原样提供。
如果请求URI指定了*.website内部的目录名称,则althttpd会附加"/home"、“/index.html"和”/index.cgi",按顺序查找匹配项。
如果URI的前缀与可执行文件的名称相匹配,那么该文件将作为CGI运行。对于按原样传递的内容,MIME类型是通过使用编译到althttpd中的表从文件扩展名推断出来的。
从版本2.0(2022-01-16)开始,althttpd可以选择支持TLS加密连接。使用Xinetd设置HTTPS网站与HTTP网站非常相似。xinetd的适当配置是/etc/xinetd.d目录中名为"https"的单个文件,内容如下:
service https
{
port = 443
flags = IPv4
socket_type = stream
wait = no
user = root
server = /usr/bin/althttpd
server_args = -logfile /logs/http.log -root /home/www -user www-data -cert /etc/letsencrypt/live/sqlite.org/fullchain.pem -pkey /etc/letsencrypt/live/sqlite.org/privkey.pem
bind = 45.33.6.223
}
service https
{
port = 443
flags = REUSE IPv6
bind = 2600:3c00::f03c:91ff:fe96:b959
socket_type = stream
wait = no
user = root
server = /usr/bin/althttpd
server_args = -logfile /logs/http.log -root /home/www -user www-data -cert /etc/letsencrypt/live/sqlite.org/fullchain.pem -pkey /etc/letsencrypt/live/sqlite.org/privkey.pem
}
当然,您需要调整路径名和IP地址,使其适合您的特定安装。
这个https配置文件与之前的http配置文件相同,只有一些变化:
将服务名称从 “http” 更改为 “https”
将端口号从80更改为443
添加-cert和-pkey选项给althttpd,以便它知道在哪里找到适当的证书和私钥。
创建新的https配置文件后,只需重新启动xinetd(通常使用命令 “/etc/init.d/xinetd restart”),您的现有网站将立即具有HTTPS版本。
早期版本的althttpd不支持加密。在althttpd上加密网站的推荐方式是使用stunnel4。这些建议现在已经改变。我们现在建议您将althttpd更新到2.0版本或更高版本,并使用前一节中描述的xinetd技术。此部分保留供历史参考。
在sqlite.org网站上,/etc/stunnel/stunnel.conf文件的相关行是:
cert = /etc/letsencrypt/live/sqlite.org/fullchain.pem
key = /etc/letsencrypt/live/sqlite.org/privkey.pem
[https]
accept = :::443
TIMEOUTclose = 0
exec = /usr/bin/althttpd
execargs = /usr/bin/althttpd -logfile /logs/http.log -root /home/www -user www-data -https 1
这个设置与xinetd设置非常相似。一个关键的区别是使用"-https 1"选项告诉althttpd连接是加密的。这很重要,这样althttpd将知道为CGI程序设置HTTPS环境变量。
配置xinetd和stunnel4同时运行althttpd是可以的。事实上,这是SQLite.org网站的运行方式。对http://sqlite.org/的请求经过xinetd,对https://sqlite.org/的请求经过stunnel4。
在作者的桌面工作站上,他的主目录下有一个子目录名为~/www/default.website。该子目录包含一组文件和CGI脚本。可以通过运行以下命令让althttpd在那里提供内容:
althttpd -root ~/www -port 8080
"-port 8080"选项告诉althttpd在独立模式下运行,监听端口8080。
althttpd的作者只在测试时使用独立模式。对于基于SSL的生产用途,建议使用内置的TLS支持或stunnel4。
如果althttpd使用TLS支持构建,则可以使用以下选项告诉它以HTTPS模式运行:
althttpd -root ~/www --port 8043 --cert unsafe-builtin
此选项使用编译的自签名SSL证书,极不安全,仅用于测试目的。使用–cert选项指定自己的PEM格式SSL证书。–cert的参数可以是SSL私钥(通常命名为"privkey.pem")和证书链(通常命名为"fullchain.pem")的串联。或者,–cert可以指向只有fullchain.pem文件,而独立的–pkey选项可以指向privkey.pem文件。
使用自己的证书:
althttpd -root ~/www --port 8043 --cert fullchain.pem --pkey privkey.pem
请注意,证书在althttpd降低根权限之前就会被读取,因此证书可能存在于althttpd进程将在其下运行的非根用户无法访问的地方。
如果您在一个目录中有构成网站的各种HTML、JavaScript、CSS和其他资源文件,并且希望轻松测试这些文件,您可以输入以下命令:
althttpd --page index.html
在上述命令中,"index.html"是初始HTML页面的名称。此命令以独立模式启动althttpd,侦听它可以找到的第一个可用端口,并绑定到回环IP地址(127.0.0.1)。它还会自动在您的Web浏览器中打开一个新标签页,并指向"index.html"页面。
如果您在远程系统上开发网站,可以使用以下方式启动:
althttpd --popup
“–popup"选项与”–page"类似,但不限制IP地址为回环地址,并且不尝试启动新的Web浏览器标签页。
为了防范恶意行为,althttpd对将提供的文件名称施加了一些限制。在请求URI中,除了字母数字和", -./:~“之外的所有字符都会转换为单个”_“。此外,如果请求URI的任何路径元素以”.“或”-“开头,althttpd都会始终返回404 Not Found错误。因此,只要文件名以”.“或”-"开头,就可以将辅助文件(例如由CGI使用的数据库或其他内容)放在文档层次结构中。
当althttpd返回404时,它会尝试确定请求是否恶意,如果它认为是,则可以选择临时阻止客户端的IP。
一个例外:尽管althttpd通常对任何以".“开头的路径元素的请求返回404 Not Found,但它允许以”/.well-known/“开头的URI请求。”/.well-known/“下面的文件或目录名称允许以”.“或”-“开头(但不允许以”…"开头)。此例外是为了允许LetsEncrypt验证对网站的拥有权。
如果在内容层次结构的任何位置都存在名为"-auth"的文件,那么所有同级文件和所有低级目录中的文件都需要HTTP基本身份验证,其定义由"-auth"文件的内容确定。“-auth"文件是纯文本和面向行的。空行和以”#"开头的行将被忽略。其他行的含义如下:
http-redirect
如果存在http-redirect行,则会导致所有HTTP请求重定向为HTTPS请求。"-auth"文件按顺序读取和处理,因此在"http-redirect"行下面的行对于http请求永远不会被看到或处理。
https-only
如果存在https-only行,则表示仅允许HTTPS请求。任何HTTP请求都会导致404 Not Found错误。https-only行通常出现在http-redirect行之后。
realm NAME
此形式的单行建立基本身份验证的 “realm”。Web浏览器通常将realm名称显示为要求用户名和密码的对话框的标题。
user NAME LOGIN:PASSWORD
有多个用户行,每个有效用户对应一行。LOGIN:PASSWORD参数定义用户必须键入的用户名和密码以访问网站。密码是明文的 - HTTP基本身份验证不是最安全的身份验证机制。成功登录后,NAME被存储在REMOTE_USER环境变量中,以便可以被CGI脚本访问。NAME和LOGIN通常相同,但也可以不同。
anyone
如果遇到"anyone"行,表示允许任何请求,即使没有提供用户名和密码。这行与"http-redirect"组合使用,可以使所有普通HTTP请求在不要求登录凭据的情况下重定向到HTTPS。
http://www.sqlite.org/ 网站在顶级目录下包含一个"-auth"文件,内容如下:
http-redirect
anyone
这个"-auth"文件导致所有HTTP请求都被重定向到HTTPS,而无需进一步的登录。(试试:访问 http://sqlite.org/ 并验证是否被重定向到 https://sqlite.org/。)
在 https://fossil-scm.org/private/ 存在一个"-auth"文件,内容如下:
realm Access To All Fossil Repositories
http-redirect
user drh drh:xxxxxxxxxxxxxxxx
当然,密码不是一行 “x” 字符。这演示了"-auth"文件的典型用法。对于单个用户,只要用户通过HTTPS而不是HTTP进入,就授予对"private"子目录中内容的访问权限。强烈建议对所有基本身份验证使用 “http-redirect” 行,因为密码包含在请求头中,如果通过HTTP发送请求,可能会被坏人截取和窃取。
如果在althttpd命令行上给出了"-logfile"选项,那么对于每个HTTP请求,都会向指定的文件追加一行。日志文件采用RFC4180规定的逗号分隔值(CSV)格式。在源代码中有一条注释解释输出行中每个字段的含义。
日志文件是CSV格式的,因此可以使用类似下面的脚本将其轻松导入到SQLite中进行分析:
CREATE TABLE log(
date TEXT, /* 时间戳 */
ip TEXT, /* 源IP地址 */
url TEXT, /* 请求URI */
ref TEXT, /* 引用者 */
code INT, /* 结果代码,例如:200,404 */
nIn INT, /* 请求中的字节数 */
nOut INT, /* 回复中的字节数 */
t1 INT, t2 INT, /* 处理时间(用户、系统)毫秒 */
t3 INT, t4 INT, /* CGI脚本时间(用户、系统)毫秒 */
t5 INT, /* 墙钟时间,毫秒 */
nreq INT, /* 此请求的序列号 */
agent TEXT, /* 用户代理 */
user TEXT, /* 远程用户 */
n INT, /* 在SCRIPT_NAME中的URL字节数 */
lineno INT /* 生成日志条目的源代码行 */
);
.mode csv
.import httplog.csv log
在"-logfile"选项上的文件名可能包含strftime()扩展的基于时间的字符。因此,要使每天使用一个新的日志文件,可以使用类似以下的内容:
-logfile /var/logs/althttpd/httplog-%Y%m%d.csv
如果在althttpd中包含了–ipshun DIRECTORY选项,DIRECTORY是从chroot jail内部访问的绝对路径(以"/"开头),并且客户端的IP地址作为该目录中的一个文件出现,那么althttpd可能返回503 Service Unavailable而不是处理请求。
如果文件大小为零字节,则始终返回503。因此,您可以"touch"一个文件,其名称是IP地址,永久封禁该客户端。
如果文件大小为N字节,则如果文件的修改时间在300*N秒之前,则在N秒内返回503。换句话说,每字节文件封禁客户端五分钟。
如果althttpd收到一个将导致404 Not Found的请求,并且在检查REQUEST_URI时该请求看起来很可疑,那么会自动创建封禁文件。例如,任何包含/…/的请求都被视为黑客企图。还检查其他常见的漏洞探测。可能会根据经验增加漏洞探测列表。
封禁文件在5分钟/字节后自动取消链接。
封禁文件最初大小为1字节。但如果封禁到期,然后在5分钟每字节的块文件大小之前到达新请求,则文件将增加一个字节,并且修改时间将被重置。
5分钟的封禁时间可以在构建时通过传递 -DBANISH_TIME=N 进行配置,其中 N 是默认为 300 的秒数。
Althttpd对服务器端内容压缩有基本支持,通常将文件的传输成本减少一半以上。与将压缩库添加到althttpd不同,它依赖于网站开发人员提供压缩和未压缩形式的内容。
在提供文件时,如果客户端支持gzip压缩,并且找到了同名文件加上 .gz 扩展名,就会向客户端提供已gzip压缩的文件,并附带响应头表示已经gzip压缩。对于用户来说,原始请求的文件似乎是压缩的。但实际上,在幕后,提供的是不同的文件。
请注意,此功能仅适用于静态文件,而不适用于CGI。
https://sqlite.org/althttpd/file?name=static-build.md&ci=tip
本文档描述了如何在Linux(或类似的类Unix操作系统)上构建一个完全自包含的、静态链接的 “althttpd” 二进制文件。
编译静态的OpenSSL库。
./config no-ssl3 no-weak-ssl-ciphers no-shared no-threads --openssldir=/usr/lib/ssl
CFLAGS=-Os make -e
编译althttpd。
gcc -I./openssl/include -Os -Wall -Wextra -DENABLE_TLS \
-o althttpd althttpd.c -L./openssl -lssl -lcrypto -ldl
以上就是所有需要做的。编译后,只需将生成的二进制文件移动到服务器的 /usr/bin 目录即可。
https://sqlite.org/althttpd/file?name=linode-systemd.md&ci=tip
使用Althttpd、Linode和Systemd设置网站
以下是我最近(2024年1月16日)在廉价的Linode VPS上使用Alhttpd、Let’s Encrypt和systemd设置网站的笔记。
如果对本文档有建议或错误报告,请在论坛上发表留言。
在Linode上创建帐户并启动新的VPS。您可以以每月5美元的价格获得它们。在这个示例中,我使用了一个每月12美元的Linode,这可能有点过剩。我可能会在某个时候降级到每月5美元的计划。
我选择了Ubuntu 23.10作为操作系统,因为那是当时最新的Ubuntu版本。使用您更熟悉的其他Linux发行版。
我构建的系统使用了我已经拥有的域名的子域,因此我不必购买新的域名。如果不是这种情况,请立即购买域名。如何执行此操作的详细信息超出了本文档的范围,但网络上有许多好的教程。
将您的域名指向Linode名称服务器。根据您要执行的操作,进行所需的任何DNS条目。Linode提供了一个出色且易于使用的界面。
以root身份登录到您的VPS。我需要升级和安装新软件,如下所示:
apt update
apt upgrade
apt install letsencrypt
应该已经有一个名为 “www-data” 的用户。(检查 /etc/passwd 文件。)这是我用于Web服务的用户。
我还手动编辑了 /etc/passwd 文件,将用户 www-data 的默认shell从 /usr/bin/nologin 更改为 /bin/bash。这个更改允许我运行 “su www-data” 命令以成为 www-data 用户,同时操作属于该用户的文件。但这一步是完全可选的。
为该用户在 /home/www 创建一个主目录。创建一个名为 /home/www/default.website 的子目录。将子目录的所有者更改为 www-data。命令序列如下:
mkdir -p /home/www/default.website
chown www-data /home/www/default.website
创建一个名为 /home/www/default.website/index.html 的文件,该文件由 www-data 用户可读,并放入一些HTML内容作为占位符。也许像这样:
<h1>Hello, Worldh1>
<p>If you can see this, that means the web server is running.p>
添加任何您想要的其他内容。但是,请注意,具有执行权限位的文件将被视为CGI运行。因此,请确保 *.website 文件夹中的任何文件或子文件夹中的文件都不可执行,除非您确实打算将它们作为CGI运行。
我在我的桌面Linux机器上构建了一个静态链接的althttpd二进制文件(使用这些说明),并使用scp将静态二进制文件传输到VPS。在 /usr/bin/ 安装静态二进制文件。
首先,您需要启动简单的HTTP(未加密)服务,因为这是从Let’s Encrypt获取证书的先决条件。创建一个文件 /etc/systemd/system/http.socket,内容如下:
[Unit]
Description=HTTP socket
[Socket]
Accept=yes
ListenStream=80
NoDelay=true
[Install]
WantedBy=sockets.target
然后创建另一个文件,命名为 /etc/systemd/system/[email protected],内容如下:
[Unit]
Description=HTTP socket server
After=network-online.target
[Service]
WorkingDirectory=/home/www
ExecStart=/usr/bin/althttpd -root /home/www -
user www-data
StandardInput=socket
[Install]
WantedBy=multi-user.target
文件名中的 “@” 不是拼写错误。由于某种原因,systemd似乎需要它。我不知道细节。
最后,使用以下命令启动新服务:
systemctl daemon-reload
systemctl enable http.socket
systemctl start http.socket
此时,您应该能够将Web浏览器指向VPS的端口80,并看到在步骤4.0末尾安装的占位HTML。您还可以使用以下命令检查服务的状态或关闭服务:
systemctl status http.socket
systemctl stop http.socket
为了使用HTTPS,您需要一个证书。使用类似以下的命令获取证书:
letsencrypt certonly --webroot -w /home/www/default.website -d your-domain.org
当然,将您的实际域名替换为 “your-domain.org”。如果您希望Web服务器为多个域提供服务,可以使用多个 “-d” 选项。有关详细信息,请参阅letsencrypt文档。
我相信此命令设置了域将自动更新证书。您不应该再次运行此命令。如果以后发现我错了,我将回来更正这段文字。
您的证书将在以下文件中找到:
/etc/letsencrypt/live/your-domain.org/fullchain.pem
/etc/letsencrypt/live/your-domain.org/privkey.pem
确保 “privkey.pem” 文件保持安全。这是您的私钥。这是Web服务器用于向陌生人验证您服务器身份的内容。
现在您有了证书,您可以创建额外的systemd配置条目,以在端口443上接收TLS HTTPS请求。首先创建一个名为 /etc/systemd/system/https.socket 的文件,内容如下:
[Unit]
Description=HTTPS socket
[Socket]
Accept=yes
ListenStream=443
NoDelay=true
[Install]
WantedBy=sockets.target
然后创建另一个文件,命名为 /etc/systemd/system/[email protected],内容如下:
[Unit]
Description=HTTPS socket server
After=network-online.target
[Service]
WorkingDirectory=/home/www
ExecStart=/usr/bin/althttpd -root /home/www -user www-data -cert /etc/letsencrypt/live/your-domain.org/fullchain.pem -pkey /etc/letsencrypt/live/your-domain.org/privkey.pem
StandardInput=socket
[Install]
WantedBy=multi-user.target
这两个文件与步骤6.0中为HTTP服务创建的文件非常相似。关键区别:
创建这两个文件后,运行:
systemctl daemon-reload
systemctl enable https.socket
systemctl start https.socket
执行完这些步骤后,您应该能够使用TLS加密的连接浏览您的网站。
如果要记录Web流量(建议),请创建一个名为 /home/www/log 的新目录,并将所有者更改为 www-data。然后编辑步骤6.0和8.0中创建的 *.service 文件,将 “–log /log/http.log” 一词添加到 “ExecStart=…” 行中。
请注意,文件名为 “/log/http.log”,而不是 “/home/www/log/http.log”。这是因为althttpd在执行任何其他操作之前会对 /home/www 目录进行chroot。这是一个安全功能,可防止CGI脚本中的错误危害您的系统。由于chroot,从althttpd的角度来看, “/home/www/log/http.log” 文件实际上将被称为 “/log/http.log”。
在进行这些更改后,运行:
systemctl restart http.socket
systemctl restart https.socket
现在,您可以尝试其他配置更改。添加像 “–ipshun /ipshun” 这样的选项是推荐的,以帮助消除恶意爬虫。您还可以在 “/home/www” 下添加特定域的新 “*.website” 文件夹。有关指导和建议,请参阅其他althttpd文档。本教程应足以帮助您入门。