Caddyfile概念

本文档将帮助你详细了解HTTP Caddyfile。

  1. 结构
  2. 地址
  3. 匹配器
  4. 占位符
  5. 片段
  6. 注释
  7. 环境变量
  8. 全局选项

结构

下面的图片可以直观地描述Caddyfile的结构:

Caddyfile的结构

关键点:

  • 可选的全局选项块可以放在文件的头部
  • 否则, Caddyfile的首行总是要提供服务的网站地址。
  • 所有指令和匹配器都必须放在站点块中。跨站点块没有全局范围或继承。
  • 如果只有一个站点块,则其花括号{ }是可选的。

一个Caddyfile至少包含一个或多个站点块,这些块总是以站点的一个或多个地址开始。出现在地址之前的任何指令都会使扰乱解析器。

打开和关闭一个是用花括号完成的:

  1. ... {
  2. ...
  3. }
  • 打开的花括号{必须位于行尾。
  • 大括号}必须独占一行。

当只有一个站点块时,花括号(和缩进)是可选的。这是为了方便快速定义单个站点,例如:

  1. localhost
  2. reverse_proxy /api/* localhost:9001
  3. file_server

相当于:

  1. localhost {
  2. reverse_proxy /api/* localhost:9001
  3. file_server
  4. }

当你只有一个站点块时;这是一个偏好问题。

要使用相同的Caddyfile配置多个站点,你必须在每个站点周围使用花括号来分隔它们的配置:

  1. example1.com {
  2. root * /www/example.com
  3. file_server
  4. }
  5. example2.com {
  6. reverse_proxy localhost:9000
  7. }

如果一个请求匹配多个站点块,则选择具有最具体匹配地址的站点块。请求不会级联到其他站点块。

指令

指令是自定义网站服务方式的关键字。例如,完整的文件服务器配置可能如下所示:

  1. localhost
  2. file_server

或反向代理:

  1. localhost
  2. reverse_proxy localhost:9000

在这些示例中,file_serverreverse_proxy是指令。指令是站点块中一行的第一个单词。

在第二个示例中,localhost:9000是一个参数,因为它出现在指令之后的同一行。

请注意,当调整 Caddyfile 时,指令会根据特定的默认指令顺序进行排序。

子指令可以出现在指令块中:

  1. localhost
  2. reverse_proxy localhost:9000 localhost:9001 {
  3. lb_policy first
  4. }

这里,lb_policyreverse_proxy的子指令(它用于设置后端之间使用的负载平衡策略)。

标记和引号

Caddyfile在被解析之前被词法解析成标记。空格在Caddyfile中很重要,因为标记就是由它进行分隔。

通常,指令需要一定数量的参数。如果单个参数有一个带有空格的值,它会被作为两个单独的标记进行词法分析:

  1. directive abc def

这可能会出现问题并返回错误或意外行为。

如果abc def应该是单个参数的值,则需要使用引号:

  1. directive "abc def"

如果你也需要在带引号的标记中使用引号,则可以转义引号:

  1. directive "\"abc def\""

在带引号的标记内,所有其他字符都按字面意思处理,包括空格、制表符和换行符。

你还可以使用反引号`来引用标记:

  1. directive `"foo bar"`

当标记包含引号文字时,反引号字符串很方便,例如JSON文本。

地址

地址总是出现在站点块的顶部,并且通常出现在Caddyfile中的第一行。

这些是有效地址的示例:

  • localhost
  • example.com
  • :443
  • http://example.com
  • localhost:8080
  • 127.0.0.1
  • [::1]:2015
  • example.com/foo/*
  • *.example.com
  • http://

从地址中,Caddy可以潜在地推断出你站点的方案、主机、端口和路径。

如果你指定主机名,则只会处理具有匹配Host标头的请求。换句话说,如果站点地址是localhost,那么Caddy将不会匹配到127.0.0.1的请求。

可以使用通配符(*),但仅代表主机名的一个标签。例如,*.example.com匹配foo.example.com,但不匹配foo.bar.example.com*匹配localhost,但不匹配example.com。要捕获所有主机,请省略地址的主机部分。

如果多个站点共享相同的定义,你可以将所有站点一起列出:

  1. localhost:8080, example.com, www.example.com

或者

  1. localhost:8080,
  2. example.com,
  3. www.example.com

请注意逗号如何表示地址的延续。

地址必须是唯一的;你不能多次指定同一个地址。

匹配器

默认情况下,注入HTTP处理程序的指令适用于所有请求(除非另有说明)。

请求匹配器可用于按给定标准对请求进行分类。这个概念源于底层的JSON结构,知道如何在Caddyfile中使用它们很重要。使用匹配器,你可以准确指定某个指令适用于哪些请求。

对于支持匹配器的指令,指令后的第一个参数是匹配器标记。这里有些例子:

  1. root * /var/www # matcher token: *
  2. root /index.html /var/www # matcher token: /index.html
  3. root @post /var/www # matcher token: @post

完全省略匹配器标记,则可以匹配所有的请求;例如,如果下一个参数看起来不像路径匹配器,则不需要给出*

阅读有关请求匹配器的页面,了解更多信息。

占位符

你可以在Caddyfile中使用任何Caddy占位符,但为方便起见,你还可以使用一些等效的速记符:

简写 替换
{dir} {http.request.uri.path.dir}
{file} {http.request.uri.path.file}
{header.*} {http.request.header.*}
{host} {http.request.host}
{labels.*} {http.request.host.labels.*}
{hostport} {http.request.hostport}
{port} {http.request.port}
{method} {http.request.method}
{path} {http.request.uri.path}
{path.*} {http.request.uri.path.*}
{query} {http.request.uri.query}
{query.*} {http.request.uri.query.*}
{re.*.*} {http.regexp.*.*}
{remote} {http.request.remote}
{remote_host} {http.request.remote.host}
{remote_port} {http.request.remote.port}
{scheme} {http.request.scheme}
{uri} {http.request.uri}
{tls_cipher} {http.request.tls.cipher_suite}
{tls_version} {http.request.tls.version}
{tls_client_fingerprint} {http.request.tls.client.fingerprint}
{tls_client_issuer} {http.request.tls.client.issuer}
{tls_client_serial} {http.request.tls.client.serial}
{tls_client_subject} {http.request.tls.client.subject}
{tls_client_certificate_pem} {http.request.tls.client.certificate_pem}
{tls_client_certificate_der_base64} {http.request.tls.client.certificate_der_base64}
{upstream_hostport} {http.reverse_proxy.upstream.hostport}

片段

你可以定义称为片段的特殊块,方法是给它们一个用括号括起来的名称:

  1. (redirect) {
  2. @http {
  3. protocol http
  4. }
  5. redir @http https://{host}{uri}
  6. }

然后你可以在任何你需要的地方重复使用它:

  1. import redirect

import 指令还可用于在其位置包含其他文件。作为一种特殊情况,它几乎可以出现在Caddyfile中的任何位置。

你可以将参数传递给导入的配置并像这样使用它们:

  1. (snippet) {
  2. respond "Yahaha! You found {args.0}!"
  3. }
  4. a.example.com {
  5. import snippet "Example A"
  6. }
  7. b.example.com {
  8. import snippet "Example B"
  9. }

注释

注释从行首的#开始并一直持续到行尾:

  1. # Comments can start a line
  2. directive # or go at the end

哈希字符#不能出现在标记的中间(即它必须以空格开头或出现在行首)。这允许在URI或其他值中使用它而不需要引号。

环境变量

如果你的配置依赖于环境变量,你可以在Caddyfile中使用它们:

  1. {$SITE_ADDRESS}

这种形式的环境变量在解析开始之前被替换,因此它们可以扩展为空值、部分标记、完整标记,甚至是多个标记和行。

当未找到环境变量时,可以指定默认值,方法是使用:变量名和默认值之间的分隔符:

  1. {$DOMAIN:localhost}

如果你想将环境变量的替换推迟到运行时,你可以使用标准{env.*}占位符

全局选项

Caddyfile可以选择以没有键的特殊块开始,称为全局选项块

  1. {
  2. ...
  3. }

如果存在,它必须是配置中的第一个块。

它用于设置全局适用的选项,或不适用于任何特定站点。在里面,只能设置全局选项;你不能在其中使用常规站点指令。

点击了解有关全局选项块的更多信息。