前几天用 Netmaker 的时候发现它用 Caddy 替换掉了 Nginx,用了后发现确实简单好用,就安利一下。

Caddy 是一个强大的、可扩展的平台,用 Go 编写,可以为你的站点、服务和应用程序提供服务。如果你是 Caddy 的新手,你服务网络的方式将会改变。

引言

大多数人使用 Caddy 作为网络服务器或代理,但在其核心,Caddy 是一个服务器的服务器(a server of servers)。通过必要的模块,它可以承担任何长时间运行的进程的角色!

配置是动态的和可通过 Caddy 的 API 导出 。虽然不需要配置文件,但是您仍然可以使用它们; 大多数人最喜欢的配置 Caddy 的方法是使用 Caddyfile。配置文档的格式通过配置适配器采用多种形式,但 Caddy 的本地配置语言是 JSON

Caddy 为所有主流平台编译,并且没有运行时依赖项。

新手指南

我们建议每个人不管经验如何都要看一下我们的入门指南。它将为你提供一个全面的视角来看待你的新网络服务器,这对你继续学习是无价的。本教程将探索使用 Caddy 的基础知识,并帮助您在更高的层次上熟悉它。

目的:

  • 运行守护进程
  • 试试 API
  • 给 Caddy 一个配置
  • 测试配置
  • 制作一个 Caddyfile
  • 使用配置适配器(config adapter)
  • 从一个初始配置开始
  • 比较 JSON 和 Caddyfile
  • 比较 API 和配置文件
  • 在后台运行
  • 零停机时间配置重载

先决条件

  • 已安装 caddycurl(安装 Caddy 可以参考这里

要启动 Caddy 作为一个守护程序,使用 run 子命令:

caddy run

默认情况下,Caddy 的配置(“ config”)为空。我们可以使用另一个终端访问管理 API 来验证这一点:

curl localhost:2019/config/

{% note info %}
ℹ️ 信息

上面地址不是你的网站,localhost:2019 是用来控制 Caddy 的管理端点,并被默认限制为本机访问。

我们可以通过给它一个配置来使 Caddy 变得有用。这可以通过多种方式完成,但是我们将在下一节使用 curl/load 端点发出 POST 请求。

你的第一个配置

为了准备我们的请求,我们需要做一个配置。

将其保存到 JSON 文件中(例如 caddy.JSON) :

{
	"apps": {
		"http": {
			"servers": {
				"example": {
					"listen": [":2015"],
					"routes": [
						{
							"handle": [{
								"handler": "static_response",
								"body": "Hello, world!"
							}]
						}
					]
				}
			}
		}
	}
}

然后上传:

curl localhost:2019/load \
	-X POST \
	-H "Content-Type: application/json" \
	-d @caddy.json

我们可以通过如下命令验证 Caddy 将我们的新配置应用到另一个 GET 请求:

curl localhost:2019/config/

然后测试新的配置:

$curl localhost:2015
Hello, world!

如果你看到 Hello, world! 那恭喜了,成功了!确保配置按预期的方式工作总是一个好主意,尤其是在部署到生产环境之前。

你的第一个 Caddyfile

另一种配置 Caddy 的方法是 Caddyfile。上面我们在 JSON 编写的配置可以简单地表达为:

:2015

respond "Hello, world!"

将其保存到工作目录文件中名为 Caddyfile (无扩展名)的文件中。

如果 Caddy 已经在运行, (Ctrl + c)停止它,然后运行:

caddy adapt

或者你把 Caddyfile 存储在别的地方,或者给它取了别的名字:

caddy adapt --config /path/to/Caddyfile

您将看到 JSON 输出! 这里发生了什么?

我们只是使用配置适配器将 Caddyfile 转换为 Caddy 的原生 JSON 结构。

虽然我们可以获得这个输出并发出另一个 API 请求,但是我们可以跳过所有这些步骤,因为 caddy 命令可以为我们完成这些操作。如果工作目录中有一个叫 Caddyfile 的文件,并且没有指定其他配置,Caddy 会加载 Caddyfile,为我们改编,然后马上运行。

现在当前文件夹中有一个 Caddyfile,让我们再次运行 caddy:

caddy run

或者如果你的 Caddyfile 在其他地方:

caddy run --config /path/to/Caddyfile

(如果调用的是不以“ Caddyfile”开头的其他名称,则需要指定 --adapter caddyfile)

正如你所看到的,有几种方法可以让你使用初始配置启动 Caddy:

  • 在工作目录一个名为 Caddyfile 的文件
  • --config flag (可选项,带有--adapter flag)
  • --resume flag (如果先前加载了配置)

JSON vs. Caddyfile

现在您知道了,Caddyfile 刚刚为您转换为 JSON。

Caddyfile 看起来比 JSON 简单,但是你应该一直使用它吗?每种方法都有利有弊。答案取决于您的需求和用例。

JSON Caddyfile
完整的 Caddy 功能 最常见的 Caddy 功能部件
易于生成 易于手工制作
易于编程 难以自动化
非常有表现力 适度的表达
允许配置遍历 不能在 Caddyfile 间转换
部分配置更改 只能修改整个配置
可以导出 无法导出
与所有 API 端点兼容 与某些 API 端点兼容
自动生成的文档 文档是手写的
无处不在 小众
更有效率 更多的计算
有点无聊 挺有意思的
了解更多:JSON 结构 了解更多:Caddyfile 文档

您将需要决定哪一个最适合您的用例。

需要注意的是,JSON 和 Caddyfile (以及任何其他支持的配置适配器)都可以与 Caddy 的 API 一起使用。然而,如果您使用 JSON,您将获得 Caddy 的全部功能和 API 特性。如果使用配置适配器,使用 API 加载或更改配置的唯一方法是 /load 端点

API vs. 配置文件

{% note info %}
ℹ️ 信息

实际上,即使是配置文件也要经过 Caddy 的 API 端点,命令只是为您包装了这些 API 调用。

您还需要决定您的工作流是基于 API 的还是基于 CLI 的。(您可以在同一台服务器上同时使用 API 和配置文件,但我们不推荐这样做: 最好有一个真实的来源。)

API 配置文件
使用 HTTP 请求修改配置 使用 shell 命令修改配置
易于扩大规模 难以规模化
手工操作难度大 易于手工操作
真的很有趣 也很有趣
了解更多:API 教程 了解更多:Caddyfile 教程

{% note info %}
ℹ️ 信息

使用 API 手动管理服务器配置完全可以通过适当的工具实现,例如: 任何 REST 客户端应用程序

或配置文件工作流的选择与配置适配器的使用是正交的: 你可以使用 JSON,但存储在一个文件中,并使用命令行界面; 相反,你也可以使用 Caddyfile 与 API。

但是大多数人会使用 json + api 或 Caddyfile + CLI 组合。

如您所见,Caddy 非常适合于各种各样的用例和部署!

Start,stop,run

因为 Caddy 是一个服务器,所以它可以无限期地运行。这意味着在执行 caddy run 之后,终端不会解除阻塞,直到进程终止(通常使用 Ctrl + c)。

虽然 caddy run 是最常见的,通常是推荐的(特别是在进行系统服务时!),你也可以选择使用 caddy start 启动 Caddy,并让它在后台运行:

caddy start

这将允许您再次使用您的终端,这在一些交互式无头环境中非常方便。

然后你必须自己停止这个过程,因为 Ctrl + c 不会为你停止:

caddy stop

或者使用 API 的/stop 端点

重新加载配置

您的服务器可以执行零停机时间配置重载/更改。

加载或更改配置的所有 API 端点都是完美的,并且没有停机时间。

但是,在使用命令行时,可能很容易使用 Ctrl + c 来停止服务器,然后再重新启动服务器以获取新的配置。不要这样做: 停止和启动服务器与配置更改是正交的,并将导致停机。

相反,使用 caddy reload 命令来优雅地修改配置:

caddy reload

这实际上只是在引擎盖下使用了 API。它将加载并在必要时将配置文件调整为 JSON,然后在不停机的情况下优雅地替换活动配置。

如果加载新配置时出现任何错误,Caddy 将回滚到上次工作的配置。

{% note info %}
ℹ️ 信息

从技术上讲,新配置是在停止旧配置之前启动的,因此在很短的时间内,两个配置都在运行!如果新配置失败,它将中止一个错误,而旧配置则根本不会停止

Caddy 常用功能

  1. 静态文件访问
  2. 反向代理
  3. HTTPS

静态文件访问

命令行方式

在终端中,切换到站点的根目录并运行:

caddy file-server

如果你得到一个权限错误,这可能意味着你的操作系统不允许你绑定到低端口---- 所以改用高端口:

caddy file-server --listen :2015

然后在浏览器中打开 (或 localhost:2015)查看您的网站!

如果你没有索引文件,但是你想要显示一个文件列表,可以使用 --browse 选项:

caddy file-server --browse

您可以使用另一个文件夹作为站点根目录:

caddy file-server --root ~/mysite

Caddyfile 方式

在站点的根目录中,创建一个名为 Caddyfile 的文件,其中包含以下内容:

localhost

file_server

或:

localhost

file_server browse

localhost

root * /home/me/mysite
file_server

分别对应以上的几个命令。

反向代理

本教程假设您有一个运行在 127.0.0.1:9000 上的后端 HTTP 服务。

命令行方式

很直白,直接能看明白:

caddy reverse-proxy --to 127.0.0.1:9000

如果你没有权限绑定到低端口,你可以从高端口代理:

caddy reverse-proxy --from :2016 --to 127.0.0.1:9000

Caddyfile 方式

直接上配置:

localhost

reverse_proxy 127.0.0.1:9000

caddy run 运行即可

更改代理的地址很容易:

:2016

reverse_proxy 127.0.0.1:9000

更改 Caddyfile 时,请确保重新加载 Caddy (或停止并重新启动它)。

使用反向代理指令以做很多事情。

HTTPS

本指南将向您展示如何立即使用完全自管理的 HTTPS 启动和运行。

{% note info %}
ℹ️ 信息

在默认情况下,Caddy 对所有站点使用 HTTPS,只要在配置中提供了主机名。本教程假设您希望通过 HTTPS 获得一个公共受信任的站点(即不是“ localhost”) ,因此我们将使用一个公共域名和外部端口

先决条件:

  • 对 DNS 的基本了解
  • 注册的公共域名
  • 对端口80和443的外部访问
  • 已安装 caddycurl

在本教程中,将 example.com 替换为您的实际域名。

设置域名的 A/AAAA 记录指向服务器。您可以通过登录到您的 DNS 提供商和管理您的域名来做到这一点。

在继续之前,用权威 lookup 验证正确的记录。用你的域名替换 example.com,如果你使用的是 IPv6,把 type=A 替换为 type=AAAA:

curl "https://cloudflare-dns.com/dns-query?name=example.com&type=A" \
  -H "accept: application/dns-json"

{% note info %}
ℹ️ 提示

一切的前提是你是在 cloudflare 上买的这个域名。
如果不是的话,步骤会复杂一些。
参见这篇 域名在 DNSPod 上的证书申请方式

还要确保您的服务器在端口80和443上是可以从公共接口访问的。

{% note info %}
ℹ️ 提示

如果您在您的家庭或其他受限制的网络,您可能需要转发端口或调整防火墙设置

所有我们需要做的是开始用您的域名配置 Caddy。有几种方法可以做到这一点。

Caddyfile

这是获取 HTTPS 的最常用方法。

创建一个名为 Caddyfile (无扩展名)的文件,其中第一行是您的域名,例如:

example.com

respond "Hello, privacy!"

然后从同一个目录中运行:

caddy run

您将看到 Caddy 提供一个 TLS 证书,并通过 HTTPS 服务您的站点。这是可能的,因为你的网站在 Caddyfile 中的地址包含一个域名。

file-server 命令

caddy file-server --domain example.com

可以了。

reverse-proxy 命令

caddy reverse-proxy --from example.com --to localhost:9000

总结

Caddy 吸引我的地方:

  1. 自动申请续约证书
  2. 简单命令的 Caddyfile
  3. Go 编写,Caddy 为所有主流平台编译,并且没有运行时依赖项。

???

参考资料

三人行, 必有我师; 知识共享, 天下为公. 本文由东风微鸣技术博客 EWhisper.cn 编写.