草庐IT

Caddy-用Go写的新一代可扩展WebServer

east4ming 2023-03-28 原文

前几天用 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 编写.

有关Caddy-用Go写的新一代可扩展WebServer的更多相关文章

  1. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  2. c - mkmf 在编译 C 扩展时忽略子文件夹中的文件 - 2

    我想这样组织C源代码:+/||___+ext||||___+native_extension||||___+lib||||||___(Sourcefilesarekeptinhere-maycontainsub-folders)||||___native_extension.c||___native_extension.h||___extconf.rb||___+lib||||___(Rubysourcecode)||___Rakefile我无法使此设置与mkmf一起正常工作。native_extension/lib中的文件(包含在native_extension.c中)将被完全忽略。

  3. ruby-on-rails - 向 Rails 3 添加 Ruby 扩展方法的最佳实践? - 2

    我有一个要在我的Rails3项目中使用的数组扩展方法。它应该住在哪里?我有一个应用程序/类,我最初把它放在(array_extensions.rb)中,在我的config/application.rb中我加载路径:config.autoload_paths+=%W(#{Rails.root}/应用程序/类)。但是,当我转到railsconsole时,未加载扩展。是否有一个预定义的位置可以放置我的Rails3扩展方法?或者,一种预先定义的方式来添加它们?我知道Rails有自己的数组扩展方法。我应该将我的添加到active_support/core_ext/array/conversion

  4. ruby - 如何在 ruby​​ 中复制目录结构,不包括某些文件扩展名 - 2

    我想编写一个ruby​​脚本来递归复制目录结构,但排除某些文件类型。因此,给定以下目录结构:folder1folder2file1.txtfile2.txtfile3.csfile4.htmlfolder2folder3file4.dll我想复制这个结构,但不包含.txt和.cs文件。因此,生成的目录结构应如下所示:folder1folder2file4.htmlfolder2folder3file4.dll 最佳答案 您可以使用查找模块。这是一个代码片段:require"find"ignored_extensions=[".cs"

  5. ruby - 扩展类和实例 - 2

    这个问题有两个部分。在RubyProgrammingLanguage一书中,有一个使用模块扩展字符串对象和类的示例(第8.1.1节)。第一个问题。为什么如果您使用新方法扩展类,然后创建该类的对象/实例,则无法访问该方法?irb(main):001:0>moduleGreeter;defciao;"Ciao!";end;end=>nilirb(main):002:0>String.extend(Greeter)=>Stringirb(main):003:0>String.ciao=>"Ciao!"irb(main):004:0>x="foobar"=>"foobar"irb(main):

  6. ruby - 动态扩展现有方法或覆盖 ruby​​ 中的发送方法 - 2

    假设我们有A、B、C类。Adefself.inherited(sub)#metaprogramminggoeshere#takeclassthathasjustinheritedclassA#andforfooclassesinjectprepare_foo()as#firstlineofmethodthenrunrestofthecodeenddefprepare_foo#=>prepare_foo()neededhere#somecodeendendBprepare_foo()neededhere#somecodeendend如您所见,我正在尝试将foo_prepare()调用注入

  7. ruby-on-rails - Textmate 'Go to symbol' 相当于 Vim - 2

    在Railcasts上,我注意到一个非常有趣的功能“转到符号”窗口。它像Command-T一样工作,但显示当前文件中可用的类和方法。如何在vim中获取它? 最佳答案 尝试:helptags有各种程序和脚本可以生成标记文件。此外,标记文件格式非常简单,因此很容易将sed(1)或类似的脚本组合在一起,无论您使用何种语言,它们都可以生成标记文件。轻松获取标记文件(除了下载生成器之外)的关键在于格式化样式而不是实际解析语法。 关于ruby-on-rails-Textmate'Gotosymbol

  8. ruby-on-rails - 如何扩展 Ruby Test::Unit 断言以包含 assert_false? - 2

    显然在Test::Unit中没有assert_false。您将如何通过扩展断言并添加文件config/initializers/assertions_helper.rb来添加它?这是最好的方法吗?我不想修改test/unit/assertions.rb。顺便说一句,我不认为这是多余的。我使用的是assert_equalfalse,something_to_evaluate。这种方法的问题是很容易意外使用assertfalse,something_to_evaluate。这将始终失败,不会引发错误或警告,并且会在测试中引入错误。 最佳答案

  9. ruby-on-rails - 无法构建 gem native 扩展 (mkmf (LoadError)) - Ubuntu 12.04 - 2

    这个问题在这里已经有了答案:Unabletoinstallgem-Failedtobuildgemnativeextension-cannotloadsuchfile--mkmf(LoadError)(17个答案)关闭9年前。嘿,我正在尝试在一台新的ubuntu机器上安装rails。我安装了ruby​​和rvm,但出现“无法构建gemnative扩展”错误。这是什么意思?$sudogeminstallrails-v3.2.9(没有sudo表示我没有权限)然后它会输出很多“获取”命令,最终会出现这个错误:Buildingnativeextensions.Thiscouldtakeawhi

  10. ruby-on-rails - 使用模块扩展带有 "has_many"的插件中的模型 - 2

    我在引擎样式插件中有一些代码,其中包含一些模型。在我的应用程序中,我想扩展其中一个模型。通过在初始值设定项中包含一个模块,我已经设法将实例和类方法添加到相关模型中。但是我似乎无法添加关联、回调等。我收到“找不到方法”错误。/libs/qwerty/core.rbmoduleQwertymoduleCoremoduleExtensionsmoduleUser#InstanceMethodsGoHere#ClassMethodsmoduleClassMethodshas_many:hits,:uniq=>true#nomethodfoundbefore_validation_on_crea

随机推荐