这篇文章上次修改于 2364 天前,可能其部分内容已经发生变化,如有疑问可询问作者。 作为新兴 Web 服务器,基于 Go 编写的 Caddy 提供了很多简单易用的功能而没有历史的包袱,其默认支持 HTTP/2、HTTPS、QUIC,对于 IPV6、WebSockets 都有很好的支持。并且其丰富的插件系统提供了文件管理、文件上传、git仓库、DNS代理等实用插件。 #安装使用 [官方下载界](https://caddyserver.com/download "官方下载界")面选择你需要的插件功能定制个性化二进制文件,下载完毕之后即可以使用caddy命令直接运行。其默认监听 2015 端口,在浏览器中打开 http://localhost:2015 即可以查看其运行情况。我们也可以通过-conf参数指定配置文件: ``` caddy -conf="/path/to/Caddyfile" ``` 简单记录下 Caddyfile 的配置语法,Caddy 的一大特性在于其使用所谓指令(Directives)来描述功能进行配置,相较于 Nginx 或者 Apache 其配置会简化很多。如果我们希望复用某个配置文件,可以使用import指令: ``` import config/common.conf ``` 或者多个文件 ``` import ../vhosts/* ``` #基础配置 Caddyfile是用UTF-8编码的纯Unicode文本,以空格或者花括号为占位符,以换行符为指令结束符,包含空格的标签定义必须以双引号保护。 语法格式为 ``` lables(list) definition(block) ``` ``` label1 { directive1 arg1 directive2 arg2 { subdir1 arg3 arg4 subdir2 # nested blocks not supported } directive3 } ``` - **其中lable 为标识符,必须全局唯一**,一般以主机名开头,也可以包含路径。definitions为Directives配置块,**不支持嵌套**。一个包含多个lables的Caddyfile必须包含花括号中的每个定义。开花括号必须在标签行的末尾,而结束的花括号必须是其行上的唯一标记。所有directives 必须在站点 definition内. - **import**指令是一个特殊的例子,因为它可以出现在定义块之外。这样做的结果是,没有任何标签可以考虑“导入”的价值。 一个简单的单站点配置类似如下: ``` localhost gzip browse websocket /echo cat ext .html log /var/log/access.log proxy /api 127.0.0.1:7005 header /api Access-Control-Allow-Origin * ``` 多个站点(虚拟机模式)配置如下 ``` mysite.com/mydir { root /www/mysite.com } *.mysite.com,sub.sub.mysite.com { root /www/sub.mysite.com gzip log ../access.log } localhost:2020, https://site.com, http://mysite.com { ... } ``` 环境变量在caddy中是内置支持的,使用shell中环境变量写法 ``` label_{$ENV_VAR_1} directive {%ENV_VAR_2%} ``` 如: ``` localhost:{$PORT} root {%SITE_ROOT%} ``` #配置语法: ##站点地址(url) caddy使用url作为lable标签,完整语法:**scheme://host:port/path** - 通配符*可用于主机名。 通配符必须取代整个域名标签:* .example.com有效,但foo * .example.com不是。 主机名可能有多个通配符标签,但它们必须是左对齐。 (请注意,要使用SSL时,只允许包含一个通配符标签)定义为*的网站仅匹配单标签名称,如“localhost”而不是“example.com”。 要匹配所有主机,请将主机名保留为空。 - 当 Caddy 检测到站点名符合下列条件时会自动使用 Let's Encrypt 脚本来为站点添加 HTTPS 支持,并且自动监听 80 与 443 端口: - 主机名不可为空并且没有 localhost 与 IP 地址 - 端口号未明确指定为 80 - Scheme 未明确指定为 http - TLS 未被关闭 - 未指明证书 关于SSL请查阅[官网手册](https://caddyserver.com/docs/automatic-https "官网手册")。 ``` :2015 # Host: (any), Port: 2015 localhost # Host: localhost; Port: 2015 localhost:8080 # Host: localhost; Port: 8080 example.com # Host: example.com; Ports: 80->443 http://example.com # Host: example.com; Port: 80 https://example.com # Host: example.com; Ports: 80->443 http://example.com:1234 # Host: example.com; Port: 1234 https://example.com:80 # Error! HTTPS on port 80 * # Hosts: *; Port: 2015 *.example.com # Hosts: *.example.com; Port: 443 *.*.example.com # Hosts: *.*.example.com; Port: 2015 example.com/foo/ # Host: example.com; Ports: 80, 443; Path: /foo/ /foo/ # Host: (any), Port: 2015, Path: /foo/ ``` ##路径匹配 某些指令接受指定要匹配的基本路径的参数。 基本路径是前缀。 如果URL以基本路径开始,它将会匹配。 例如,/ foo的基本路径会将请求匹配到/ foo,/ foo.html,/ foobar和/foo/bar.html。 如果你想限制一个基本路径只匹配一个特定的目录,那么用/ foo /等正斜杠结尾作为后缀,这将不匹配/ foobar。 ##指令块 - 大多数指令调用一个中间件层。 中间件是处理HTTP请求的应用程序中的一个小层,它可以很好地完成一件事。 中间件作为插件在启动时被链接在一起(如果你愿意的话,可以手动编译)。 只有从Caddyfile调用的中间件处理程序才会被链接,因此小型Caddyfiles非常快速高效。 - 参数的语法因指令而异。 有些需要,有些则不需要。 请查阅每条指令的文档以获取详细用法。 - 对于注册为插件的指令,文档页面将显示以服务器类型为前缀的指令名称,例如如“http.realip”或“dns.dnssec”。 在Caddyfile中使用它们时,请删除前缀(“http。”)。 前缀只是为了确保唯一的命名,但不在Caddyfile中使用。 ##占位符,内置变量 某些指令允许您在Caddyfile中使用占位符来为每个请求填写不同的值。 例如,值{path}将被请求URL的路径部分替换。 这些也被称为可替换值,一般的,占位符仅支持支持它们的指令。 [检查指令的文档以查看是否支持占位符。](https://caddyserver.com/docs/placeholders "检查指令的文档以查看是否支持占位符。") ##常见指令 ###bind [绑定到特定地址](https://caddyserver.com/docs/bind "绑定到特定地址") ``` bind host #only host or ip without port ``` ###browse[ 目录列表](https://caddyserver.com/docs/browse " 目录列表") ``` browse [path [tplfile]] #path is the base path to match. Any directories in this base path become browsable. #tplfile is the location of a template file to use. ``` 模板语法请参考[Caddy's template actions ](https://caddyserver.com/docs/template-actions "Caddy's template actions ") ###timeouts [超时设置](https://caddyserver.com/docs/timeouts "超时设置") ``` #set val for all timeouts timeouts val #You can also configure each timeout individually: timeouts { read val header val write val idle val } ``` 例如: ``` timeouts { read 30s write 20s } ``` ###errors [错误定义](https://caddyserver.com/docs/errors "错误定义") ``` errors [logfile] { code file rotate_size mb rotate_age days rotate_keep count rotate_compress } ``` ###status [状态码](https://caddyserver.com/docs/status "状态码") ``` status code path status code { path } ``` 如: ``` #To hide the existence of a secret folder: status 404 /secrets #To hide the existence of multiple folders: status 404 { /hidden /secrets } ``` ###expvar [统计信息](https://caddyserver.com/docs/expvar "统计信息") expvar以JSON格式显示有关运行时或当前进程状态的变量。 默认路径是/ debug / vars。 默认情况下,它会报告内存统计信息,用于运行Caddy的命令以及goroutine的数量。 > 尽管在实时网站上使用它通常是安全的,但请注意不要泄露任何敏感内容 ``` expvar [path] #expvar /stats ``` ###extensions [扩展名](https://caddyserver.com/docs/ext "扩展名") extensions ...是一个以空格分隔的扩展名(包括点)来尝试的列表。 将按列出的顺序尝试扩展。 至少需要一个扩展名参数。 假设你有一个名为/contact.html的文件。 您可以通过让Caddy尝试使用.html文件来联系该文件。 按顺序尝试.html,.htm和.php: ``` ext .html .htm .php ``` ###fastcgi [fastcgi代理](https://caddyserver.com/docs/fastcgi "fastcgi代理") fastcgi代理请求到FastCGI服务器。 尽管此指令最常用的用途是为PHP站点提供服务,但它默认为通用FastCGI代理。 该指令可能会在不同的请求路径中使用多次。 ``` fastcgi path endpoint [preset] { root directory ext extension split splitval index indexfile env key value except ignored_paths... upstream endpoint connect_timeout duration read_timeout duration send_timeout duration } ``` 例如: ``` #Proxy all requests to a FastCGI responder listening at 127.0.0.1:9000: fastcgi / 127.0.0.1:9000 #Forward all requests in /blog to a PHP site (like WordPress) being served with php-fpm: fastcgi /blog/ 127.0.0.1:9000 php #With custom FastCGI configuration: fastcgi / 127.0.0.1:9001 { split .html } #With PHP preset, but overriding the ext property: fastcgi / 127.0.0.1:9001 php { ext .html } #With PHP preset, but the FastCGI server is running in a container based on an official Docker image (with container port 9000 published to 127.0.0.1:9001): fastcgi / 127.0.0.1:9001 php { root /var/www/html } ``` ###gzip [gzip压缩](https://caddyserver.com/docs/gzip "gzip压缩") ``` gzip { ext extensions... not paths level compression_level min_length min_bytes } ``` 例如: ``` gzip { level 1 not /images /videos } ``` ###header [请求头](https://caddyserver.com/docs/header "请求头") ``` header path name value header path { name value } ``` 如: ``` header / X-Custom-Header "My value" #Strip the "Hidden" field from header: header / -Hidden #Multiple custom headers for a specific path, while removing the Server field: header /api { Access-Control-Allow-Origin * Access-Control-Allow-Methods "GET, POST, OPTIONS" -Server } #Add some security headers to all pages: header / { # Enable HTTP Strict Transport Security (HSTS) to force clients to always # connect via HTTPS (do not use if only testing) Strict-Transport-Security "max-age=31536000;" # Enable cross-site filter (XSS) and tell browser to block detected attacks X-XSS-Protection "1; mode=block" # Prevent some browsers from MIME-sniffing a response away from the declared Content-Type X-Content-Type-Options "nosniff" # Disallow the site to be rendered within a frame (clickjacking protection) X-Frame-Options "DENY" } ``` ###proxy [反向代理和负载均衡](https://caddyserver.com/docs/proxy "反向代理和负载均衡") proxy支持多个后端以及自定义header。 负载平衡功能包括多个策略,运行状况检查和故障转移。 Caddy也可以代理WebSocket连接。 可用于日志格式的占位符:{upstream} - 请求代理到的上游主机的名称。 ``` proxy from to proxy from to... { policy name [value] fail_timeout duration max_fails integer max_conns integer try_duration duration try_interval duration health_check path health_check_port port health_check_interval interval_duration health_check_timeout timeout_duration header_upstream name value header_downstream name value keepalive number timeout duration without prefix except ignored_paths... upstream to insecure_skip_verify preset } ``` 例如: ``` #Proxy all requests within /api to a backend system: proxy /api localhost:9005 #Load-balance all requests between three backends (using random policy): proxy / web1.local:80 web2.local:90 web3.local:100 #Same as above, with header affinity: proxy / web1.local:80 web2.local:90 web3.local:100 { policy header X-My-Header } #Round-robin style: proxy / web1.local:80 web2.local:90 web3.local:100 { policy round_robin } #With health checks and proxy headers to pass hostname, IP, and scheme upstream: proxy / web1.local:80 web2.local:90 web3.local:100 { policy round_robin health_check /health transparent } #Proxy WebSocket connections: proxy /stream localhost:8080 { websocket } #Proxy everything except requests to /static or /robots.txt: proxy / backend:1234 { except /static /robots.txt } #Proxy to a backend with HTTPS on the standard HTTPS port: proxy / https://backend ``` ###redir [重定向](https://caddyserver.com/docs/redir "重定向") redir将向客户端发送HTTP重定向状态码。 也可以使条件重定向。 ``` redir from to [code] #To create a permanent, "catch-all" redirect, omit the from value: redir to redir [code] { from to [code] } #A group of redirects can also be conditional: redir [code] { if a cond b if_op [and|or] ... } ``` 例如: ``` #When a request comes in for /resources/images/photo.jpg, redirect to /resources/images/drawing.jpg with HTTP 307 (Temporary Redirect) status code: redir /resources/images/photo.jpg /resources/images/drawing.jpg 307 #Redirect all requests to https://newsite.com while preserving the request URI: redir https://newsite.com{uri} #Defining multiple redirections that share a 307 status code, except the last one: redir 307 { /foo /info/foo /todo /notes /api-dev /api meta } #Redirect only if the forwarded protocol is HTTP: redir 301 { if {>X-Forwarded-Proto} is http / https://{host}{uri} } ``` ###rewrite [url重写](https://caddyserver.com/docs/rewrite "重定向") 重写执行内部URL重写。 这允许客户端请求一个资源,但实际上不需要HTTP重定向就可以被服务。 重写对客户是不可见的。 有简单的重写(快速)和复杂的重写(较慢),但它们足够强大以适应大多数动态后端应用程序。 ``` rewrite [not] from to... rewrite [basepath] { regexp pattern ext extensions... if a cond b if_op [and|or] to destinations... } ``` 如: ``` #Rewrite everything to /index.php. (rewrite / /index.php will only match /) rewrite .* /index.php #When requests come in for /mobile, actually serve /mobile/index. rewrite /mobile /mobile/index #If the file is not favicon.ico and it is not a valid file or directory, serve the maintenance page if present, or finally, rewrite to index.php. rewrite { if {file} not favicon.ico to {path} {path}/ /maintenance.html /index.php } #If user agent includes "mobile" and path is not a valid file/directory, rewrite to the mobile index page. rewrite { if {>User-agent} has mobile to {path} {path}/ /mobile/index.php } #Rewrite /app to /index with a query string. {1} is the matched group (.*). rewrite /app { r (.*) to /index?path={1} } #Rewrite requests for /app/example to /index.php?category=example. rewrite /app { r ^/(\w+)/?$ to /index?category={1} } ``` ###internal [http.internal](https://caddyserver.com/docs/internal "http.internal") 保护指定目录中的所有资源。 直接请求受保护目录中的资源的浏览器(或任何客户端)将返回404。 ``` internal path ``` ###limits [请求限制](https://caddyserver.com/docs/limits "请求限制") 限制对接受的HTTP请求设置限制。 请求标题和正文大小可能受到限制。 请求标头大小可以限制在某些字节数。 由于Go库的工作方式,一个限制适用于同一个监听器上的所有站点(如果有多个配置,则选择最小限制)。 请求身材尺寸也可能受到限制。 当从请求主体读取的字节数超过限制时,读取将终止,并且将向客户端发送错误。 (从技术上讲,它依赖于每个读取请求体的中间件来正确处理错误,但标准的Caddy指令应该用HTTP 413进行响应。)默认情况下,没有大小限制。 大小值必须是正整数,并且除非给出单位,否则将其解释为字节。 有效示例:3500(3,500字节),500kb(500千字节),10mb(10兆字节),1gb(1千兆字节)。 ``` limits { header size body [path] size } ``` ``` limits { header 100KB body /upload 100MB body /profile 25KB body /api 10KB } ``` ###log [日志](https://caddyserver.com/docs/log "日志") ``` log file log path file [format] log path file [format] { rotate_size mb rotate_age days rotate_keep count rotate_compress ipmask ipv4_mask [ipv6_mask] except paths... } ``` ``` #log to access.log log #log to stdout with default format log stdout #Custom log format: log / stdout "{proto} Request: {method} {path}" #Predefined format: log / stdout "{combined}" #With rotation: log requests.log { rotate_size 50 # Rotate after 50 MB rotate_age 90 # Keep rotated files for 90 days rotate_keep 20 # Keep at most 20 log files rotate_compress # Compress rotated log files in gzip format } ``` ###http.mime [自定义Content-Type](https://caddyserver.com/docs/mime "自定义Content-Type") 通常情况下,内容类型会通过嗅探内容自动检测类型, 如果您遇到错误Content-Type的响应,或者提供的内容不是静态文件,则可以使用此中间件来设置正确的Content-Type。 ``` mime ext type mime { ext type } ``` 例如: ``` mime .mp4 video/mp4 mime { .swf application/x-shockwave-flash .pdf application/pdf .exe application/octet-stream } ``` ###request_id [请求id](https://caddyserver.com/docs/request_id "请求id") request_id生成UUID.可通过{request_id}占位符引用,用于许多其他指令,包括标头和日志。使用request_id时,{request_id}占位符将具有值; 否则它将是空的。request_id通常用于灰度部署场景。 ``` request_id [header_field] ``` 如: ``` request_id #Set the request ID in a response header: header / Caddy-Request-Id {request_id} #Read the request ID from a request header called X-Request-ID, if present: request_id X-Request-ID ``` ###tls [SSL指令](https://caddyserver.com/docs/tls "SSL指令") 由于HTTPS自动启用,因此该指令用于覆盖默认设置。 Caddy支持SNI (Server Name Indication),因此您可以从机器上的同一端口为多个HTTPS站点提供服务。 另外,Caddy为所有合格证书实施OCSP装订。 Caddy还会定期自动更新所有TLS会话密钥。 ``` #Disables TLS for the site. Not recommended unless you have a good reason. With TLS off, automatic HTTPS is also disabled, so the default port (2015) will not be changed. tls off #email is the email address to use with which to generate a certificate with a trusted CA. By providing an email here you will not be prompted when you run Caddy. tls email #To use Caddy with your own certificate and key: tls cert key #Or to have Caddy generate and use an untrusted, self-signed certificate in memory that lasts 7 days (enough for local development): tls self_signed #Advanced users may open a settings block for more control, optionally specifying their own certificate and key: tls [cert key] { ca uri protocols min max ciphers ciphers... curves curves... clients [request|require|verify_if_given] clientcas... load dir max_certs limit ask url key_type type dns provider alpn protos... must_staple wildcard } ``` #[docker 插件](https://github.com/lucaslorentz/caddy-docker-proxy/blob/master/README.md "docker 插件") 连接到Docker Swarm集群,并基于Docker Services元数据动态生成Caddyfile。通常用作docker cluster的ingress控制器,[更多详细用法请参考官网](https://github.com/lucaslorentz/caddy-docker-proxy/blob/master/README.md "更多详细用法请参考官网")。 #caddy插件 caddy有许多插件,诸如dns,jwt,cors等。[如何编写和使用 插件请参考官方文档](https://caddyserver.com/docs "如何编写和使用 插件请参考官方文档") #quic支持 [Caddy 从0.9开始实验支持QUIC](https://github.com/mholt/caddy/wiki/QUIC "Caddy 从0.9开始实验支持QUIC"), 要尝试它,请使用-quic标志运行: ``` $ caddy -quic ``` #参考: - https://caddyserver.com/docs/ - https://github.com/caddyserver/examples - https://github.com/mholt/caddy/wiki/Troubleshooting-PHP-FPM-and-FastCGI
没有评论