深入解读Althttpd: 第一部分

Althttpd是一款轻量级Web服务器软件,自2004年起支撑sqlite.org网站,平均每天响应50万次请求,分发近50GB内容。其设计简约,易于配置和维护,通过命令行参数进行配置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Althttpd 是一款 Web Server, 和 nginx/apache相似, 相比之下, 该款更轻量化, 功能也较为简洁, sqlite.org 在用. 经朋友推荐学习, 不得不提另一款 Tinyhttpd, 更简洁的设计和模型, 只是拿来学习使用, 似乎并未用于实际业务. 由于实际文件只有三个, 我这里就做全量解析, Marddown 文件主要做翻译工作, Makefile 文件主要做命令解析(可能会在翻译那部分一起做), 源码文件当然挨个分析.

althttpd.md

Althttpd 是一个简单的 web 服务器, 自从2004年就在 sqlite.org 站点投入使用, 主要追求轻量化, 安全性和低资源使用.
截至2018年, 部署在每月40刀的 Linode VPS上 Althttpd 支撑的 sqlite.org 平均每天响应50w的请求(每秒大约5到6个), 分发将近50G内容每天(大约4.6兆每秒), 这台机器上的负载基本保持在0.1或0.2. 大约19%的请求是访问不同的源码仓库 [Fossil](https://fossil-scm.org/).

设计哲学

Althttpd 通常从 xinetdstunnel4 启动, 一个为服务每个连接的隔离进程, 一个将处理通过同一连接的一个或多个请求的独立 Althttpd 进程. 当连接关闭, Althttpd 进程就结束了.
Althttpd 也可以独立运行, 自身监听80端口为了即将达到的请求, 然后创建一个自己的子进程去处理每个已到达的连接, 当然每个处理的连接是在相互独立的进程. 唯一的区别就是每个处理连接的子进程是从 Althttpd 主进程启动的, 而不是 xinetdstunnel4 .
Althttpd 没有配置文件, 所有的配置都从命令参数中获取, 有利于保持简洁的配置和降低通过异常配置站点带来的弱安全性的担忧.
Althttpd 没有自身的 TLS 连接处理. 对于 HTTPS 连接, Althttpd 通过响应 stunnel4 去处理 TLS 协议, 解密和加密.
由于每个 Althttpd 进程只需要服务于一个独立的连接, 所以它也是个独立线程. 而且, 每个进程只存活于一个独立连接的生命周期中, 这意味着不需要担心过多的内存泄漏问题. 这些促进安全审核和分析的设计因素有利于保持 Althttpd 源码的简洁.

源码

有关 Althttpd 完整的源码都在一个没有任何非标准外部库依赖的独立文件, 文件名为 althttpd.c . 为了构建和安装 Althttpd , 运行 gcc -Os -o /usr/bin/althttpd althttpd.c . 源码有非常多的注释, 易于理解, 所以也容易做一些自定义特殊化需求的适配.

xinetd 配置

下面展示的就是 sqlite.org 中使用的支持 IPv4/IPv6 非加密请求的 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 将自身关于站点根目录层次的权限纳入控制, 删除之前监听读取任意内容的超级用户权限. 通过 -user 选项告诉 Althttpd 访问用户将变成 www-data .
-root 选项告诉 Althttpd 寻找文档结构的位置. 在 sqlite.org 这个例子中, 所有内容都是从 /home/www 提供的. 位于文档结构的顶端都是一些以 .website 结尾的目录, 每个这样的目录都是一个独立的站点. 这种目录是基于到达请求的域名和参数被选择的. 这儿有一部分 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

对于每个请求, 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 目录内, 文件是通过请求资源标识定位( URI: Uniform Resource Identifier )提供服务. 这些文件都被标记为通过 CGI 运行的可执行文件. 以 .scgi 结尾的不可执行文件在遇到 SCGI hostname port 形式的请求将提供一个 SCGI 请求给 hostname port . 所有其他不可执行文件都是原样分发的.
如果请求 URI 指定 *.website 内目录名称, Althttpd 将追加 /home, /index.html, 和 /index.cgi, 以这样的顺序, 查找匹配项. 如果请求 URI 的前缀与可执行文件名称配置, 那个文件将以 CGI 方式运行. 对于原样内容, 请求 URI 必须匹配正确的文件名.
对于原样内容分发, 将从编译到 Althttpd 的一个表中根据文件名扩展推断出 MIME 类型.

使用 stunnel4 配置 https

Althttpd 本身没有任何加密, 所以为了使用 Althttpd 的站点配置加密, 推荐使用 stunnel4 . 在 sqlite.org 站点, 在 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 知道如何设置
CGIhttps 环境变量. xinetdstunnel4 同时配置运行 Althttpd 也是可以的. 实际上, 这正是 sqlite.org 的运行方式, 通过 xinetd 访问 http://sqlite.org/ , 通过 stunnel4 访问 https://sqlite.org/ .

独立运行

在作者的工作台桌面, 他的 home 目录下有个名为 ~/www/default.website 包含了一些文件和 CGI 脚本的子目录, Althttpd 可通过以下命令提供该内容 althttpd -root ~/www -port 8080 . -port 8080 是配置 Althttpd 在独立运行模式中监听的端口为 8080 . 作者的 Althttpd 独立运行模式只用于测试. 由于 Althttpd 本身不支持 TLS 访问, 在正式环境中更推荐使用 stunnel4 .

安全功能

为了防止恶意访问, Althttpd 提供的文件命名有一些严格的限制. 在请求 URI 中, 所有的非 ASCII 字母数字的编码和 ,-./:~ 都会被转成 一个单字符 _ . 此外, 在请求 URI 中任意以 .- 开始的路径元素, Althttpd 总会触发 404 错误. 所以在文档结构中放一些以 .- 开始命名的辅助文件也是安全的.
一个异常: 尽管 Althttpd 对于路径元素中以 . 开始命名的请求总是 404, 但它是允许 /.well-known/ 开头的请求访问, 在 /.well-known/ 目录下的目录或文件是允许以 .- 开头(但是禁止 .. ). 这个异常主要是为了允许 LetsEncrypt 验证站点所有者关系.

基本认证

如果一个命名为 -auth 的文件出现在内容层次中, 那么所有同级和处于更低级的文件都需要 HTTP basic authentication 验证, 由 -auth 文件的内容定义. 这个 -auth 是面向行的纯文本的文件, 空行和以 # 开头的行都会被忽略, 其余行如下:

  • http-redirect
    http-redirect 行, 如果存在, 将会导致所有请求都被重定向成 https 请求. -auth 是顺序读取和执行的, 所以在这行之下的内容对于请求将永不可见或执行.
  • https-only
    https-only 行, 如果存在, 表示只允许 https 请求访问, 任一 http 请求都会触发 404 错误, 这行通常出现在 http-redirect 行之后.
  • realm
    一个为了建立 realm 基础认证表单的独立行, 浏览器通常将 realm 名称展示为一个询问名称和密码的对话框的名称.
  • user NAME LOGIN:PASSWORD
    这是批量行, 一行时每个有效的用户, LOGIN:PASSWORD 参数定义了用户必须输入才能访问站点的名称和密码, 密码是纯文本, HTTP Basic Authentication 也不是最安全的认证策略. 在成功登陆后, 名称会被保存在 REMOTE_USER 环境变量中, 所以它可以通过 CGI 脚本. NAMEPASSWORD 通常是一样的, 但最好设置成不同的.
  • anyone
    如果 anyone 一旦出现, 它就意味着任何请求都是被允许的, 即使没有提供用户和密码. 这个和 http-redirect 结合使用对于从 HTTP 重定向到不需要登陆标识的 HTTPS 请求是非常有用的.

认证实例

sqlite.org 站点在顶级目录中包含了一个 -auth 文件:

http-redirect
anyone

这个文件导致所有 HTTP 请求被定向到 https 请求, 不需要任何登陆.
fossil-scm.org 配置的 -auth 文件如下:

realm Access To All Fossil Repositories
http-redirect
 user drh drh:xxxxxxxxxxxxxxxx

当然, 这个密码不是一串 x 字符, 对于 -auth, 这种显示是很常见的. 访问控制对于独立用户授权是在 private 子目录下的内容, 这主要是提供用于 https 访问. 对于所有需要将密码放在请求头的基础认证, 强烈推荐设置 http-redirect , 通过 http 传输凭证是会被截取的.

日志文件

如果 -logfile 选项在 Althttpd 命令行中给出, 那么, 每个请求都会新增一个独立行到指定文件. 这个日志文件的内容是由逗号间隔的值或RFC4180标准指定的 CSV 格式.
在源码中有些解释每个字段在输出行意思的注释. 实际上, CSV 形式的日志文件很容易导入 sqlite 分析, 使用像下面这种脚本:

CREATE TABLE log(
 date TEXT,             /* Timestamp */
  ip TEXT,               /* Source IP address */
  url TEXT,              /* Request URI */
  ref TEXT,              /* Referer */
  code INT,              /* Result code.  ex: 200, 404 */
  nIn INT,               /* Bytes in request */
  nOut INT,              /* Bytes in reply */
  t1 INT, t2 INT,        /* Process time (user, system) milliseconds */
  t3 INT, t4 INT,        /* CGI script time (user, system) milliseconds */
  t5 INT,                /* Wall-clock time, milliseconds */
  nreq INT,              /* Sequence number of this request */
  agent TEXT,            /* User agent */
  user TEXT,             /* Remote user */
  n INT,                 /* Bytes of url that are in SCRIPT_NAME */
  lineno INT             /* Source code line that generated log entry */
);
.mode csv
.import httplog.csv log

-option 选项中配置的文件名可能包含一些被 strftime() 填充的时间字符. 所以, 为了创建每日日志文件, 你可能需要这样使用 -logfile /var/logs/althttpd/httplog-%Y%m%d.csv .

Makefile

有关 Makefile 的相关知识, 尚不太熟悉, 就不在这里做介绍, 直接看内容中的命令:

althttpd:	althttpd.c
	cc -Os -Wall -Wextra -o althttpd althttpd.c

clean:	
	rm -f althttpd
  • althttpd 创建可执行文件
    • -Os 去掉了那些会导致最终可执行程序增大的优化;
    • -Wall 显示所有警告信息;
    • -Wextra 显示附加警告信息;
    • -o 指定生成的输出文件.
  • clean 清除 althttpd 可执行文件(当前目录).

在这部分, 我们了解了怎么去使用, 下面, 将去了解它的具体实现.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值