Web 服务器 Caddy 2
下载与安装
我们需要从Caddy 下载页面下载Caddy V2,并将下载的可执行文件放在我们系统的PATH
中。
可以在Caddy 下载页面获取不同系统或CPU架构的可执行文件。同Caddy v1时一样,此页面可以让我们自定义带有不同插件的Caddy V2。
A. Debian,Ubuntu,Raspbian
我们可以使用apt-get
命令来安装Caddy,然后下载caddy.service文件,使用systemd
来启动Caddy。
1 | sudo apt-get install -y debian-keyring debian-archive-keyring apt-transport-https |
也可以自Caddy 下载页面手动下载包含第三方插件的可执行文件,然后将它放在PATH
下(如/usr/local/bin/
),方便我们运行。
1 | # 下载带有webdav插件的Linux AMD64版本的Caddy |
B. Docker
1 | docker pull caddy |
运行Caddy服务
按照下面的步骤来安装caddy服务。
- 要求:
caddy
可执行文件已经下载完成systemctl --version
版本高于232sudo
权限
将我们下载的caddy可执行文件放在$PATH
下,并确认可以被执行。
1 | :~$ sudo mv caddy /usr/local/bin && sudo chmod +x /usr/local/bin/caddy |
创建名为caddy
的用户组
1 | :~$ sudo groupadd --system caddy |
创建名为caddy
的用户,并且带有一个可以写入的用户目录。
1 | sudo useradd --system \ |
注意: 如果使用了caddy的配置文件,必须确保此文件是可以被用户
caddy
可读的。
下一步,创建systemd
服务的配置文件。
Github-Caddy.service
1 | :~$ sudo cat > /lib/systemd/system/caddy.service << EOF |
最后,我们就可以使用下面的命令来运行caddy
了。
1 | :~$ sudo systemctl start caddy |
此时,Caddy的日志被重定向到了journalctl
中,使用下面命令来查看运行日志
1 | :~$ sudo journalctl -u caddy --no-pager | less |
Caddyfile例子
PHP
1 | # ----------全局配置--------------- |
php_fastcgi
此指令将指定的请求发送给 PHP FastCGI 服务,如php-fpm
。
1 | # 将所有PHP请求重定向至 127.0.0.1:9000 |
WebDav
1 | # -----------全局配置--------------- |
此功能需要第三方插件http.handlers.webdav
支持。且此插件只提供了webdav
最基本的读取功能,不支持写入。
1 | :~$ caddy list-modules | grep webdav |
Caddyfile 文档
Caddyfile是一种方便人类阅读的格式。因为它易写、易理解,所以多数人们都喜欢用它来配置Caddy。
概念
Caddy-Docs-Concepts
结构
Caddyfile 文件的结构如下图:
重点:
- **全局选项 (global options block)**必须在文件的最顶端即开头处,此为可选,即配置文件中可以没有它。
- 如果Caddyfile中不包含全局选项(Global options),那么它的第一行(非注释行)必须是网站地址,即网站的域名。
- 所有指令(directives)和匹配器(matchers)必须处于站点配置里,即
{ }
里。 - 如果Caddyfile中仅配置了一个网站,那么它的
{ }
是可以省略的。
全局选项(Global Options)
Caddy-Docs-Global Options
Caddyfile可让您指定全局应用的选项。 一些选项作为默认值,而其他选项则可以定义Caddyfile适配器的行为。
Caddyfile的最顶部可以是全局选项块。
1 | { |
http_port : 指定服务器的HTTP端口. 仅限内部使用,并不会改变客户端的HTTP端口。默认为80。https_port : 指定服务器的HTTPS端口。仅限服务器内部使用,并不会改变客户端的HTTPS端口。默认 为443。server : 自定义跨多个站点的HTTP服务端的设置,因为这个功能无法在站点块中正确配置。protocol allow_h2c : 启用H2C(“明文HTTP / 2”或“ H2 over TCP”)支持,如果客户端支持,它将通过TCP协议来传输明文HTTP/2。 此设置仅适用于未加密的HTTP协议。experimental_http3 : 启用HTTP/3实验性支持。 注意,HTTP/3 暂时并不是一个完整的规范,并且客户端的支持也非常有限。将来该选项会被舍弃。
请求匹配器(Request Matchers)
请求匹配器可按特定条件筛选(或分类)请求。
在Caddyfile中,紧随指令之后的匹配(matcher)标记可以限制该指令的范围。 匹配器标记可以是以下形式之一:
通配符(Wildcard matchers) :* 匹配所有请求(默认).路径(Path matchers) :/path 以/
开头来匹配请求的路径。名称(Named matchers) :@name 以@
开头来定义一个名称匹配器。
通配符(Wildcard matchers)
通配符*
来匹配所有请求,且仅当需要匹配标识时时才使用。
1 | # 将所有的请求根目录设置为 /var/www/mysite |
路径(Path matchers)
由于按路径匹配非常常见,因此可以内联单个路径匹配器,如下所示:
1 | redir /old.html /new.html |
路径匹配的标识必须以正斜杠/
开头。
默认情况下路径匹配是路径完全匹配;进行前缀匹配必须附加*
。注意,/foo*
将匹配/foo
和/foo/
以及/foobar
;实际上我们可能需要的是/foo/*
。
名称匹配(Named matchers)
定义具有唯一名称的匹配器可使您更灵活,允许您将任何可用的匹配器组合到一个集合中:
1 | # 定义多个匹配 |
例子:
1 | @websockets { |
此代理仅代理名为“Connection”的字段(值包含单词“Upgrade”)和名为“Upgrade”的字段(值为“websocket”)的请求。
与指令一样,
名称匹配器定义了一个匹配器集。
标准匹配器(Standard matchers)
- expression
- file
- header
- header_regexp
- host
- method
- not
- path
- path_regexp
- protocol
- query
- remote_ip
header
1 | header <field> [<value>] |
对请求里header
参数进行匹配。
<field>
需要检查的HTTP头部字段的名字。- 如果它的前缀为
!
,则表示HTTP头部不允许包含此字段。 <value>
为该字段需要匹配的值。- 如果它的前缀为
*
,则表示进行前缀模糊匹配。 - 如果它的后缀为
*
,则表示进行后缀模糊匹配。 - 如果被
*
包围,则表示进行字符串模糊匹配。 - 其它情况,则进行精准匹配。
header
下的字段之间进行**与(AND)**操作,多个header
之间进行或(or)
操作。
例1
对HTTP头部的Connection
与 server
字段进行匹配:
Connection
字段值需包含Upgrade
server
字段的值必须为Caddy
最后匹配结果进行与(and)
操作。
1 | @foo { |
例2
HTTP头部Foo
字段的值是否为bar
或baz
1 | @foo { |
例3
HTTP头部不能包含名为Foo
的字段。
1 | @not_foo { |
method
1 | method <verbs...> |
对HTTP的请求方式进行匹配,如POST
。可以同时匹配多个请求方式。
或(or)
操作。
1 | # 是否为 GET 请求 |
not
1 | # 单行 not 之间进行或操作 |
将匹配的结果进行非
操作。
例1
匹配不包含以/css/
或 /js/
开头的请求路径。
这里的
或
是path
匹配器里的,而非not
匹配器
1 | not path /css/* /js/* |
例2
对HTTP请求进行匹配:
- 不以
/api/
开头的路径,或 - 请求方式不为
POST
1 | not path /api/* |
例3
同时对HTTP请求的多个内容进行匹配:
- 请求路径不以
/api/
开头的,和 - 请求方法不为
POST
的
1 | not { |
path
1 | path <paths...> |
对HTTP请求的URI
进行匹配,一般进行精准匹配,使用*
时可以进行模糊匹配:
*
在后面,进行后缀模糊匹配,如/prefix/*
*
在前面,则进行前缀模糊匹配,如*.suffix
*
在两边,则进行子字符串精确匹配,如*/contains/*
*
在中间,则两边精确匹配中间模糊匹配,如/accounts/*/info
或(or)
操作。
指令
下面列表的指令为Caddy的自有指令,可以用在Caddyfile中。
指令 | 说明 |
---|---|
acme_server | 嵌入式ACME服务器 |
basicauth | HTTP基本身份验证 |
bind | 自定义服务器的套接字地址 |
encode | 编码(通常压缩)响应 |
file_server | 为磁盘上的文件提供显示服务 |
handle | 互斥的指令组 |
handle_errors | 定义处理错误的路由 |
handle_path | 类似于句柄(handle),但隐匿删除匹配路径的前缀 |
header | 移除或设置HTTP响应头 |
import | 加载外部文件或摘要 |
log | 启用访问/请求的日志记录 |
map | 将输入值映射到一个或多个输出上 |
metrics | 配置Prometheus指标的节点 |
php_fastcgi | 通过FastCGI为PHP站点提供服务 |
push | 利用HTTP/2推送协议向客户端进行推送 |
redir | 向客户端发送重定向指令 |
request_body | 对传入请求的主体进行操作 |
request_header | 对传入请求的头部进行操作 |
respond | 向客户端写入固定的响应 |
reverse_proxy | 一个强大且可扩展的反向代理 |
rewrite | 在服务器内部重写请求 |
root | 设置网站的根目录 |
route | 将一组指令封装为一条复合指令 |
templates | 把响应的内容模板化 |
tls | 自定义TLS设置 |
try_files | 在服务端将指定后缀的文件请求进行重写 |
uri | 对URI进行操作 |
指令执行优先级
HTTP处理链被许多指令操控着。这些指令执行的优先级非常重要,因此Caddy在其内部为这些指令定义了一套默认的优先级:
1 | map |
我们可以使用route
指令或在全局选项中使用order
来重新定义指令执行时的优先级。
log
允许和设置HTTP请求的访问日志。
log
指令在Caddyfile站点块里进行使用,而非其它地方。
1 | log { |
output
: 设置日志记录的位置。默认 : stderrstderr
: 控制台的标准错误通道(默认选项)。stdout
: 控制台的标准输出通道。discard
: 无日志输出。file
: 输出至指定的文本文件。为了防止硬盘空间耗尽默认对日志文件进行轮换。net
: 网络套接接口。format
: 对日志进行编码或格式化。默认 : 如果检测到stdout是终端则为console格式,否则为json格式。console
: 对每条日志按console格式进行编码以使其易于人类阅读,同时也保留下了某些结构。json
: 对每条日志按JSON结构进行格式化。single_field
: 仅在日志条目中写入单个字段。对于其中一个字段已经包含我们所需的信息时很有用。filter
: 定义一个日志编码格式,允许按字段进行过滤。delete
: 在对日志进行编码时删除指定字段。ip_mask
: 在字段中将IP地址模糊化处理。level
: 设置日志的等级。默认等级 :INFO
例子
1 | # 使用普通格式记录日志 |
Basicauth
basicauth, Enables HTTP Basic Authentication, which can be used to protect directories and files with a username and hashed password. Note that basic auth is not secure over plain HTTP.
Caddy configuration does not accept plaintext passwords; we MUST hash them before putting them into the configuration. The
1 | :~$ caddy hash-password |
Example:
1 | haven200.com { |
encode
Encodes responses using the configured encoding(s). A typical use for encoding is compression.
1 | haven200.com { |
file_server
A static file server. It works by appending the request’s URI path to the site’s root path. By default, it enforces canonical URIs; if necessary, requests to directories will be redirected to have a trailing forward slash, and requests to files will be redirected to strip the trailing slash.
Most often, the file_server directive is paired with the root directive to set file root for the whole site.
1 | file_server [<matcher>] [browse] { |
browse
enables file listings for requests to directories that do not have an index file.root
sets the path to the site root for just this file server instance, overriding any other.Default :{http.vars.root}
or the current working directory.Note: This subdirective only changes the root for this directive. For other directives (like try_files or templates) to know the same site root, use the root directive, not this subdirective.hide
is a list of files or folders to hide; if requested, the file server will pretend they do not exist. Accepts placeholders and glob patterns. Note that these are file system paths, NOT request paths.index
is a list of filenames to look for as index files.Default :index.html
index.txt
<template_file>
is an optional custom template file to use for directory listings.
Example One
The file_server directive is usually paired with the root directive to set the root path from which to serve files:
1 | haven200.com { |
Example Two
A static file server out of the /var/www
directory With file listings enabled, and hide all .git
folders and their contents
1 | haven200.com { |
header
Manipulates HTTP header fields on the response. It can set, add, and delete header values, or perform replacements using regular expressions.
By default, header operations are performed immediately unless any of the headers are being deleted, in which case the header operations are automatically deferred until the time they are being written to the client.
1 | header [<matcher>] [[+|-|?]<field> [<value>|<find>] [<replace>]] { |
<field>
is the name of the header field. By default, will overwrite any existing field of the same name. Prefix with+
to add the field instead of replace, or prefix with-
to remove the field.<value>
is the header field value, if adding or setting a field.<default_value>
is the header field value that will be set only if the header does not already exist.<find>
is the substring or regular expression to search for.<replace>
is the replacement value; required if performing a search-and-replace.defer
will force the header operations to be deferred until the response is written out to the client. This is automatically enabled if any of the header fields are being deleted.
Example
1 | # Set a custom header field on all requests |
root
Sets the root
path of the site, used by various matchers and directives that access the file system. If unset, the default site root is the current working directory.
Specifically, this directive sets the {http.vars.root}
placeholder.
This directive does not automatically enable serving static files, so it is often used in conjunction with the [file_server directive][toc_haven200_file_server] or the [php_fastcgi directive][toc_haven200_php_fastcgi].
1 | # Set the site root to /home/user/public_html for all requests |
php_fastcgi
An opinionated directive that proxies requests to a PHP FastCGI server such as php-fpm.
Caddy’s reverse_proxy is capable of serving any FastCGI application, but this directive is tailored specifically for PHP apps. This directive is actually just a convenient way to use a longer, more common configuration (below).
1 | php_fastcgi [<matcher>] <php-fpm_gateways...> { |
<php-fpm_gateways...>
are the addresses of the FastCGI servers.root
sets the root folder to the site.Default :root
directive.split
sets the substrings for splitting the URI into two parts. The first matching substring will be used to split the “path info” from the path. The first piece is suffixed with the matching substring and will be assumed as the actual resource (CGI script) name. The second piece will be set to PATH_INFO for the CGI script to use.Default :.php
env
sets an extra environment variable to the given value. Can be specified more than once for multiple environment variables.index
specifies the filename to treat as the directory index file. This affects the file matcher in the expanded form.Default :index.php
resolve_root_symlink
enables resolving the root directory to its actual value by evaluating a symbolic link, if one exists.dial_timeout
is how long to wait when connecting to the upstream socket. Accepts duration values.Default : no timeout.read_timeout
is how long to wait when reading from the FastCGI server. Accepts duration values.Default : no timeout.write_timeout
is how long to wait when sending to the FastCGI server. Accepts duration values.Default : no timeout.
Expanded form
The php_fastcgi
directive is the same as the following configuration:
1 | route { |
Most modern PHP apps work well with this preset. If yours does not, feel free to borrow from this and customize it as needed instead of using the php_fastcgi
shortcut.
Examples
1 | #Proxy all PHP requests to a FastCGI responder listening at 127.0.0.1:9000: |
rewrite
Rewrites the request internally. A rewrite changes some or all of the request URI.
The rewrite
directive implies the intent to accept the request, but with modifications. It is mutually exclusive to other rewrite directives in the same block, so it is safe to define rewrites that would otherwise cascade into each other;
Because rewrite essentially performs an internal redirect, the Caddyfile adapter will not fold any subsequent, adjacent handlers into the same route if their matchers happen to be exactly the same. This allows the matchers of the next handlers to be deferred until after the rewrite. In other words, a matcher that matches a request before the rewrite might not match the same request after the rewrite. If you want your rewrite to share a route with other handlers, use the route or handle directives.
1 | rewrite [<matcher>] <to> |
- is the URI to set on the request. Only designated parts will be replaced. The URI path is any substring that comes before
?
. If?
is omitted, then the whole token is considered to be the path.
Examples
1 | # Rewrite all requests to foo.html, leaving any query string unchanged: |
引用:
- caddy v1
- Caddy-website
- Caddy-docs