文档
一个 项目

常见的 Caddyfile 模式

本页演示了一些针对常见用例的完整且最小化的 Caddyfile 配置示例。这些可作为你自己 Caddyfile 文档的起点。

这些并不是可直接套用的解决方案;你需要自定义域名、端口/套接字、目录路径等。它们旨在说明一些最常见的配置模式。

静态文件服务器

example.com {
	root * /var/www
	file_server
}

像往常一样,第一行是站点地址。root 指令 指定站点根目录的路径(* 表示匹配所有请求,以便与 路径匹配器 区分)—如果站点不在当前工作目录,请更改为你的站点路径。最后,我们启用 静态文件服务器

反向代理

代理所有请求:

example.com {
	reverse_proxy localhost:5000
}

仅代理路径以 /api/ 开头的请求,其他所有请求提供静态文件:

example.com {
	root * /var/www
	reverse_proxy /api/* localhost:5000
	file_server
}

这使用了 请求匹配器 来仅匹配以 /api/ 开头的请求并将其代理到后端。所有其他请求将从站点的 root 使用 静态文件服务器 提供。这也依赖于 reverse_proxy指令顺序 中位于 file_server 之上。

更多 reverse_proxy 示例见此处

PHP

PHP-FPM

如果运行着 PHP FastCGI 服务,对于大多数现代 PHP 应用,类似下面的配置即可:

example.com {
	root * /srv/public
	encode
	php_fastcgi localhost:9000
	file_server
}

相应地定制站点根目录;此示例假设你的 PHP 应用的 webroot 在 public 目录中——磁盘上存在的文件请求将由 file_server 提供,其他请求将路由到 index.php 由 PHP 应用处理。

有时你也可以使用 unix 套接字连接到 PHP-FPM:

php_fastcgi unix//run/php/php8.2-fpm.sock

php_fastcgi 指令 实际上只是 若干配置项的快捷方式

FrankenPHP

另外,你也可以使用 FrankenPHP,它是一个将 PHP 直接通过 CGO(Go 到 C 绑定)调用的 Caddy 发行版。相比 PHP-FPM,这种方式的速度可达约 4 倍,若能使用 worker 模式甚至更好。

{
    frankenphp
    order php_server before file_server
}

example.com {
	root * /srv/public
    encode zstd br gzip
    php_server
}

重定向 www. 子域

要通过 HTTP 重定向来添加 www. 子域:

example.com {
	redir https://www.{host}{uri}
}

www.example.com {
}

移除 它:

www.example.com {
	redir https://example.com{uri}
}

example.com {
}

要一次性为多个域名移除它;此处使用了 {labels.*} 占位符,它们是主机名的各部分,从右侧开始以 0 为索引(例如 0=com1=example-one2=www):

www.example-one.com, www.example-two.com {
	redir https://{labels.1}.{labels.0}{uri}
}

example-one.com, example-two.com {
}

尾部斜杠

你通常不需要自行配置;file_server 指令 会根据请求的资源是目录还是文件,通过 HTTP 重定向自动为请求添加或移除尾部斜杠。

然而,如果你需要,你仍然可以在配置中强制尾部斜杠。有两种方式:内部强制或外部强制。

内部强制

这使用 rewrite 指令。Caddy 将在内部重写 URI 来添加或移除尾部斜杠:

example.com {
	rewrite /add     /add/
	rewrite /remove/ /remove
}

使用 rewrite 时,有无尾部斜杠的请求将被视为相同。

外部强制

这使用 redir 指令。Caddy 会要求浏览器更改 URI 来添加或移除尾部斜杠:

example.com {
	redir /add     /add/
	redir /remove/ /remove
}

使用重定向时,客户端必须重新发起请求,从而强制资源只有一个可接受的 URI。

通配符证书

如果你需要使用相同的通配符证书为多个子域提供服务,最好的方式是像下面这样使用 handle 指令host 匹配器 的 Caddyfile:

*.example.com {
	tls {
		dns <provider_name> [<params...>]
	}

	@foo host foo.example.com
	handle @foo {
		respond "Foo!"
	}

	@bar host bar.example.com
	handle @bar {
		respond "Bar!"
	}

	# Fallback for otherwise unhandled domains
	handle {
		abort
	}
}

你必须启用 ACME DNS 挑战,以让 Caddy 自动管理通配符证书。

单页应用(SPA)

当网页自己处理路由时,服务器可能会收到大量在服务端并不存在的页面请求,但只要返回单一的索引文件,客户端就能进行渲染。像这样的 Web 应用称为 SPA(单页应用)。

主要思路是让服务器“尝试文件”以判断请求的文件是否在服务端存在,如果不存在,则回退到一个索引文件,由客户端进行路由(通常使用客户端 JavaScript)。

典型的 SPA 配置通常如下所示:

example.com {
	root * /srv
	encode
	try_files {path} /index.html
	file_server
}

如果你的 SPA 与 API 或其他仅在服务端提供的端点耦合,你会想用 handle 块将它们单独处理:

example.com {
	encode

	handle /api/* {
		reverse_proxy backend:8000
	}

	handle {
		root * /srv
		try_files {path} /index.html
		file_server
	}
}

如果你的 index.html 引用了带哈希的 JS/CSS 资产文件名,你可能想为其添加 Cache-Control 头,指示客户端不要缓存(以便资产变化时,浏览器能获取到新的文件)。由于 try_files 重写用于从任何未匹配到磁盘上其它文件的路径提供你的 index.html,你可以用一个 route 包裹 try_files,这样 header 处理器会在重写之后运行(否则由于 指令顺序 它通常会在之前运行):

route {
	try_files {path} /index.html
	header /index.html Cache-Control "public, max-age=0, must-revalidate"
}

Caddy 代理到另一个 Caddy

如果你有一个公开可访问的 Caddy 实例(称为“前端”),以及另一个位于私有网络的 Caddy 实例(称为“后端”)用于提供实际应用,你可以使用 reverse_proxy 指令 将请求传递过去。

前端实例:

foo.example.com, bar.example.com {
	reverse_proxy 10.0.0.1:80
}

后端实例:

{
	servers {
		trusted_proxies static private_ranges
	}
}

http://foo.example.com {
	reverse_proxy foo-app:8080
}

http://bar.example.com {
	reverse_proxy bar-app:9000
}
  • 该示例为两个不同的域名提供服务,均将流量代理到同一后端 Caddy 实例的端口 80。你的后端实例以不同方式为这两个域名提供服务,因此它用两个独立的站点块进行配置。

  • 在后端,使用了 http:// 来在端口 80 上接受 HTTP。前端实例终止 TLS,前端与后端之间的流量在私有网络上,因此无需再次加密。

  • 如果需要,你可以在后端使用不同的端口(如 8080);只需在后端配置中为每个站点地址追加 :8080,或者将 http_port 全局选项 设置为 8080

  • 在后端,使用了 trusted_proxies 全局选项 来告诉 Caddy 信任前端实例作为代理。这可确保保留真实的客户端 IP。

  • 进一步地,你可以有多个后端实例并在它们之间进行 负载均衡。你还可以在前端实例使用 acme_server 配置 mTLS(双向 TLS),使其充当后端实例的 CA(当前端和后端之间的流量跨越不受信任的网络时这很有用)。