44 个稳定版本

3.3.8 2024年7月24日
3.3.6 2024年3月22日
3.3.3 2023年12月27日
3.3.1 2023年8月6日
1.2.1 2020年6月20日

#18网络编程

Download history 2/week @ 2024-04-29 10/week @ 2024-05-20 9/week @ 2024-05-27 32/week @ 2024-06-03 38/week @ 2024-06-10 13/week @ 2024-06-17 13/week @ 2024-06-24 39/week @ 2024-07-01 22/week @ 2024-07-08 11/week @ 2024-07-15 177/week @ 2024-07-22 180/week @ 2024-07-29 16/week @ 2024-08-05 22/week @ 2024-08-12

每月396次下载

MIT/Apache

68KB
917

Agate

Crates.io Test Status Dependency Status

静态文件的简单 Gemini 服务器

Agate 是一个用于 Gemini 网络协议的服务器,使用 Rust 编程语言构建。Agate 功能非常少,只能提供静态文件服务。它使用异步 I/O,即使在低端硬件上运行并处理大量并发请求时也非常高效。

了解更多

安装和设置

  1. 获取 agate 的二进制文件。您可以使用以下任何一种方式

预编译

下载并解压 预编译的二进制文件

NixOS/Nix

使用 nix 软件包管理器运行 nix-env -i agate

Guix 系统

部署 agate 到 GNU Guix 系统中,通过将 agate-service-type 添加到您的系统 服务

Arch Linux

安装 agate-binAUR 包以获取预编译的二进制文件。否则,安装 agateAUR 包以从源代码编译 agate。

Cargo

如果您已安装 Rust 工具链,则运行 cargo install agate 以从 crates.io 安装 agate。

源代码

下载源代码,然后在源代码库中运行 cargo build --release,然后找到二进制文件位于 target/release/agate


如果您的系统中存在,您可以使用 tools 目录中的安装脚本进行后续步骤。
如果没有,请考虑贡献一个,以便让技术不太熟练的用户更容易使用!


  1. 运行服务器。您可以使用以下参数来指定内容目录的位置、监听的 IP 地址和端口、请求 URL 中预期的域名以及要包含在 MIME 类型文本/gemini 文件中的默认语言代码:(将主机名 example.com 替换为您 Gemini 服务器的地址。)如果您尚未自己进行,Agate 首次运行时将为您生成私钥和证书,并使用指定的主机名。
agate --content path/to/content/ \
      --addr [::]:1965 \
      --addr 0.0.0.0:1965 \
      --hostname example.com \
      --lang en-US

所有命令行参数都是可选的。运行 agate --help 查看省略参数时使用的默认值。

当客户端请求 URL gemini://example.com/foo/bar 时,Agate 将响应位于 path/to/content/foo/bar 的文件。如果请求路径的任何部分以点开头,无论文件是否存在,Agate 都将响应状态码 52。此行为可以通过 --serve-secret 或在 .meta 配置文件中的特定文件条目来禁用(参见元预设)。如果该路径存在目录,Agate 将在该目录中查找名为 index.gmi 的文件。

配置

自动证书生成

如果使用了 --hostname 参数,Agate 将为指定的每个域名生成密钥和自签名证书。根据规范,Gemini 建议使用自签名证书,因为 Gemini 使用证书的 TOFU(首次使用信任)原则。因此,生成的证书也将具有较长的有效期 4096-01-01

有关密钥和证书的手动配置,请参阅下文的 证书部分

TLS 版本

Agate 默认支持 TLSv1.2 和 TLSv1.3。您可以使用标志 --only-tls13(或其简写 -3)禁用对 TLSv1.2 的支持。这 不推荐 使用,因为它可能会破坏与某些客户端的兼容性。Gemini 规范要求“目前”与 TLSv1.2 兼容,因为并非所有平台都对 TLSv1.3 有很好的支持(参见规范第 4.1 节)。

目录列出

您可以通过在该目录中放置名为 .directory-listing-ok 的文件来启用该目录的基本目录列出。这不会影响子目录。此文件必须是 UTF-8 编码的文本;它可以是空的。文件中的任何文本都将添加到目录列表的开头。目录列表将隐藏以点开头的文件和目录(例如,.directory-listing-ok 文件本身、.meta 配置文件或 .. 目录)。

名为 index.gmi 的文件将始终优先于目录列出。

元预设

您可以将名为 .meta 的文件放入任何内容目录中。该文件存储了Agate在提供这些文件时使用的相邻文件的一些元数据。该 .meta 文件必须使用UTF-8编码。您还可以使用 -C 标志(或长格式 --central-conf)启用中央配置文件。在这种情况下,Agate将始终在内容根目录中查找 .meta 配置文件,并忽略其他目录中的 .meta 文件。

.meta 文件具有以下格式(*1)

  • 空行将被忽略。
  • 同一行上的 # 之后的所有内容都是注释,将被忽略。
  • 所有其他行必须具有以下形式:<路径>:<元数据>,即以文件路径开头,后面跟一个冒号,然后是元数据。

<path> 是大小写敏感的文件路径,可能在磁盘上存在或不存在。如果指向目录,则会被忽略。如果不使用中央配置文件模式,使用当前目录中不是文件的路径是未定义的行为(例如 ../index.gmi 将是未定义的行为)。您可以在现有路径中使用Unix样式的模式。例如 content/* 将匹配 content 中的任何文件,而 content/** 还将匹配 content 的子目录中的任何文件。然而,由于它们的特殊意义,默认情况下,*** 模式不会匹配以点开头的文件或目录。可以通过 --serve-secret 禁用此行为,或者通过例如 content/.*content/**/.* 分别显式匹配以点开头的文件。有关您可以使用模式的更多信息,请参阅 glob::Pattern 的文档。规则可以覆盖其他规则,因此如果一个文件被多个规则匹配,则最后一条规则生效。

<metadata> 可以采用以下四种可能的形式

  1. 空的
    Agate不会发送默认语言参数,即使它在命令行中指定了。
  2. 以分号和MIME参数开始
    如果找到文件,Agate将把指定的字符串附加到MIME类型上。
  3. 以Gemini状态码(即1-6之间的数字后面跟另一个数字)和一个空格开始
    无论文件是否存在,Agate都会发送元数据。文件不会被发送或访问。
  4. 一个MIME类型,可能包括参数
    如果找到文件,Agate将使用此MIME类型而不是它猜测的类型。即使它在命令行中指定了,也不会使用默认语言参数。

如果一行违反了格式或看起来像案例 3,但又是不正确的,可能会被忽略。你应该检查你的日志。请知道,当访问相应目录的文件时,首先读取这个配置文件。所以启动后没有日志消息并不意味着 .meta 文件是好的。

这样的配置文件可能看起来像这样

# This line will be ignored.
**/*.de.gmi: ;lang=de
nl/**/*.gmi: ;lang=nl
index.gmi: ;lang=en-GB
LICENSE: text/plain;charset=UTF-8
gone.gmi: 52 This file is no longer here, sorry.

如果这是内容根目录中的 .meta 文件,并且使用了 -C 标志,这将导致以下响应头

  • //index.gmi -> 20 text/gemini;lang=en-GB
  • /LICENSE -> 20 text/plain;charset=UTF-8
  • /gone.gmi -> 52 This file is no longer here, sorry.
  • 任何以 .de.gmi 结尾的非隐藏文件(包括在非隐藏子目录中)-> 20 text/gemini;lang=de
  • 任何在 nl 目录中的非隐藏文件,以 .gmi 结尾(包括在非隐藏子目录中)-> 20 text/gemini;lang=nl

(*1) 从理论上讲,语法类似于典型的 INI 类文件,并允许使用具有 [section](默认部分设置为解析器中的 mime)的节(由于所有其他部分都被忽略,这并没有什么区别)。这也意味着理论上也可以使用 = 而不是 :。有关更多信息,请访问 configparser 的文档

日志详细程度

Agate 使用 env_logger crate,并允许您通过设置 RUST_LOG 环境变量来设置日志详细程度。要关闭所有日志,请使用 RUST_LOG=off。有关更多信息,请参阅 env_logger 的文档

虚拟主机

Agate 具有基本的虚拟主机支持。如果您指定了多个 --hostname,Agate 将在内容根目录中的相应主机名目录中查找。例如,如果其中一个主机名是 example.com,并且内容根目录设置为默认的 ./content,并且请求 gemini://example.com/file.gmi,那么 Agate 将查找 ./content/example.com/file.gmi。只有当指定了多个 --hostname 时,此行为才会启用。Agate 还支持不同主机名的不同证书,请参阅下面的证书部分。

如果您想要为多个域名提供相同的内容,您可以通过不指定 --hostname 来禁用主机名检查。在这种情况下,Agate 将忽略请求的主机名,除了检查是否存在之外。

当指定了一个或多个 --hostname 时,Agate 将检查请求 URL 中的主机名和端口是否与指定的主机名和监听端口匹配。如果 Agate 在另一个端口后的代理后面,并且收到一个指定代理端口的 URL 请求,则该端口可能不匹配 Agate 的任何监听端口,请求将被拒绝:可以使用 --skip-port-check 来禁用端口检查。

证书

Agate 支持 --certs 选项使用多个证书。因此,Agate 总是要求客户端使用 SNI,这应该不是问题,因为 Gemini 规范也要求使用 SNI。

默认情况下,证书存储在 .certificates 目录中。这是一个隐藏目录,目的是为了防止粗心大意的人将内容根目录设置为当前目录,这也可能包含证书目录。在这种情况下,证书和私钥仍然会被隐藏。证书仅在 Agate 启动时加载,并在运行时不会重新加载。证书目录可以直接包含一个密钥和证书对,如果没有其他匹配的密钥,则使用默认对。证书目录还可以包含特定域的子目录,例如 example.orgportal.example.org 的文件夹。请注意,子域(如 portal.example.org)的子文件夹不应在其他子文件夹内部,而应直接在证书目录中。Agate 将选择最接近名称的证书/密钥对。例如,以下目录结构:

.certificates
|-- cert.der     (1)
|-- key.der      (1)
|-- example.org
|   |-- cert.der (2)
|   `-- key.der  (2)
`-- portal.example.org
    |-- cert.der (3)
    `-- key.der  (3)

这会被理解为以下内容:

  • 证书/密钥对(1)将用于整个域名树(以下有例外)。
  • 证书/密钥对(2)将用于 example.org 的整个域名树,包括子域如 secret.example.org。它覆盖了此子树的密钥对(1)(以下有例外)。
  • 证书/密钥对(3)将用于 portal.example.org 的整个域名树,包括子域如 test.portal.example.org。它覆盖了此子树的密钥对(1)和(2)。

使用仅命名 . 的目录会导致未定义的行为,因为这将与顶级证书/密钥对(如上例中的密钥对(1))具有相同的意义。

证书/密钥对的文件必须命名为 cert.derkey.der。证书必须是一个包含域名名称的主题备用名称的 X.509 证书,格式为 DER 文件。私钥必须以 DER 格式存在,并且必须是 RSA、ECDSA 或 Ed25519 密钥。

日志记录

所有通过 TCP 套接字发出的请求都将使用此格式进行记录

<local ip>:<local port> <remote ip or dash> "<request>" <response status> "<response meta>"[ error:<error>]

所有通过 Unix 套接字发出的请求都将使用此格式进行记录

unix:[<unix socket name>] - "<request>" <response status> "<response meta>"[ error:<error>]

方括号表示可选部分。

只有发生错误时,“错误:”部分才会被记录。这仅应用于信息目的,因为状态码应提供发生错误的信息。如果错误是由于连接未建立(例如由于TLS错误)造成的,则可以使用下面列出的特殊状态码。

默认情况下,Agate不会记录远程IP地址,因为这可能是一个问题,因为IP地址在欧盟的GDPR中被视为私人数据。要启用IP地址的记录,可以使用--log-ip选项。请注意,在这种情况下,一些错误条件可能会强制Agate记录破折号而不是IP地址。Unix套接字连接的连接也无法记录IP地址。

除了这些之外,还可能根据选择的日志级别在日志中发生一些行。例如,初始的“正在监听...”行或关于列出特定目录的信息。

Agate在记录错误时使用一些不是有效Gemini状态码的状态码

  • 00 - 建立TLS连接时出错
  • 01 - 获取对等方的IP地址时出错

安全考虑

如果您想在多用户系统上运行agate,您应该知道所有证书和密钥数据都会被加载到内存中,并存储在那里,直到服务器停止。由于内存在使用后也没有被明确覆盖或清零,因此敏感数据可能在服务器终止后仍然留在内存中。

依赖项

~13–22MB
~424K SLoC