+
+ handle_response [] {
+
+ }
+}
+```
+
+- **@name** is the name of a [response matcher](/docs/caddyfile/response-matchers). As long as each response matcher has a unique name, multiple matchers can be defined. A response can be matched on the status code and presence or value of a response header.
+
+- **replace_status** simply changes the status code of response when matched by the given matcher.
+
+- **handle_response** defines the route to execute when matched by the given matcher (or, if a matcher is omitted, all responses). The first matching block will be applied. Inside a `handle_response` block, any other [directives](/docs/caddyfile/directives) can be used.
+
+Within `handle_response` routes, the following placeholders are available to pull information from the original response:
+
+- `{resp.status_code}` The status code of the original response.
+
+- `{resp.header.*}` The headers from the original response.
+
+
+## Examples
+
+When using [FrankenPHP](https://frankenphp.dev/)'s `php_server`, you can use `intercept` to implement `X-Accel-Redirect` support, serving static files as requested by the PHP app:
+
+```caddy
+localhost {
+ root * /srv
+
+ intercept {
+ @accel header X-Accel-Redirect *
+ handle_response @accel {
+ root * /path/to/private/files
+ rewrite {resp.header.X-Accel-Redirect}
+ method GET
+ file_server
+ }
+ }
+
+ php_server
+}
+```
diff --git a/src/docs/markdown/caddyfile/directives/log.md b/src/docs/markdown/caddyfile/directives/log.md
index 59e89de..234f65a 100644
--- a/src/docs/markdown/caddyfile/directives/log.md
+++ b/src/docs/markdown/caddyfile/directives/log.md
@@ -59,7 +59,7 @@ To add custom fields to the log entries, use the [`log_append` directive](log_ap
- [append](#append)
- [Examples](#examples)
-Since Caddy v2.5, by default, headers with potentially sensitive information (`Cookie`, `Set-Cookie`, `Authorization` and `Proxy-Authorization`) will be logged with empty values. This behaviour can be disabled with the [`log_credentials`](/docs/caddyfile/options#log-credentials) global server option.
+By default, headers with potentially sensitive information (`Cookie`, `Set-Cookie`, `Authorization` and `Proxy-Authorization`) will be logged as `REDACTED` in access logs. This behaviour can be disabled with the [`log_credentials`](/docs/caddyfile/options#log-credentials) global server option.
## Syntax
@@ -67,29 +67,34 @@ Since Caddy v2.5, by default, headers with potentially sensitive information (`C
```caddy-d
log [] {
hostnames
+ no_hostname
output ...
format ...
level
}
```
-- **logger_name** is an optional override of the logger name for this site.
+- **logger_name** is an optional override of the logger name for this site.
By default, a logger name is generated automatically, e.g. `log0`, `log1`, and so on depending on the order of the sites in the Caddyfile. This is only useful if you wish to reliably refer to the output of this logger from another logger defined in global options. See [an example](#multiple-outputs) below.
-- **hostnames** is an optional override of the hostnames that this logger applies to.
+- **hostnames** is an optional override of the hostnames that this logger applies to.
By default, the logger applies to the hostnames of the site block it appears in, i.e. the site addresses. This is useful if you wish to define different loggers per subdomain in a [wildcard site block](/docs/caddyfile/patterns#wildcard-certificates). See [an example](#wildcard-logs) below.
-- **output** configures where to write the logs. See [`output` modules](#output-modules) below.
+- **no_hostname** prevents the logger from being associated with any of the site block's hostnames. By default, the logger is associated with the [site address](/docs/caddyfile/concepts#addresses) that the `log` directive appears in.
+
+ This is useful when you want to log requests to different files based on some condition, such as the request path or method, using the [`log_name` directive](/docs/caddyfile/directives/log_name).
+
+- **output** configures where to write the logs. See [`output` modules](#output-modules) below.
Default: `stderr`.
-- **format** describes how to encode, or format, the logs. See [`format` modules](#format-modules) below.
+- **format** describes how to encode, or format, the logs. See [`format` modules](#format-modules) below.
Default: `console` if `stderr` is detected to be a terminal, `json` otherwise.
-- **level** is the minimum entry level to log. Default: `INFO`.
+- **level** is the minimum entry level to log. Default: `INFO`.
Note that access logs currently only emit `INFO` and `ERROR` level logs.
@@ -150,9 +155,7 @@ output file {
- **<filename>** is the path to the log file.
-- **mode** is the file mode octal value as specified with the unix `chmod` command. For example `0600` would set the mode to `rw-,---,---`, while `0640` would set the mode to `rw-,r--,---`.
-
- Default: `0600`
+- **mode** is the Unix file mode/permissions to use for the log file. The mode consists of between 1 and 4 octal digits (same as the numeric format accepted by the Unix [chmod
](https://en.wikipedia.org/wiki/Chmod) command, except that an all-zero mode is interpreted as the default mode `600`). For example: `0600` would set the mode to `rw-,---,---` (read/write access to the log file's owner, and no access to anyone else); `0640` would set the mode to `rw-,r--,---` (read/write access to file's owner, only read access to the group); `644` sets the mode to `rw-,r--,r--` provides read/write access to the log file's owner, but only read access to the group owner and other users.
- **roll_disabled** disables log rolling. This can lead to disk space depletion, so only use this if your log files are maintained some other way.
@@ -174,7 +177,6 @@ output file {
- **roll_keep_for** is how long to keep rolled files as a [duration string](/docs/conventions#durations). The current implementation supports day resolution; fractional values are rounded up to the next whole day. For example, `36h` (1.5 days) is rounded up to `48h` (2 days). Default: `2160h` (90 days)
-
#### net
A network socket. If the socket goes down, it will dump logs to stderr while it attempts to reconnect.
@@ -263,8 +265,9 @@ format {
Default: `seconds`.
May be one of:
- - `seconds` Floating-point number of seconds elapsed.
- - `nano` Integer number of nanoseconds elapsed.
+ - `s`, `second` or `seconds` Floating-point number of seconds elapsed.
+ - `ms`, `milli` or `millis` Floating-point number of milliseconds elapsed.
+ - `ns`, `nano` or `nanos` Integer number of nanoseconds elapsed.
- `string` Using Go's built-in string format, for example `1m32.05s` or `6.31ms`.
- **level_format** The format for levels.
diff --git a/src/docs/markdown/caddyfile/directives/log_append.md b/src/docs/markdown/caddyfile/directives/log_append.md
index a996894..d7a3738 100644
--- a/src/docs/markdown/caddyfile/directives/log_append.md
+++ b/src/docs/markdown/caddyfile/directives/log_append.md
@@ -37,3 +37,21 @@ example.com {
}
}
```
+
+Display in the logs, which reverse proxy upstream was effectively used (either `node1`, `node2` or `node3`) and
+the time spent proxying to the upstream in milliseconds as well as how long it took the proxy upstream to write the response header:
+
+```caddy
+example.com {
+ log
+
+ handle {
+ reverse_proxy node1:80 node2:80 node3:80 {
+ lb_policy random_choose 2
+ }
+ log_append upstream_host {rp.upstream.host}
+ log_append upstream_duration_ms {rp.upstream.duration_ms}
+ log_append upstream_latency_ms {rp.upstream.latency_ms}
+ }
+}
+```
diff --git a/src/docs/markdown/caddyfile/directives/log_name.md b/src/docs/markdown/caddyfile/directives/log_name.md
new file mode 100644
index 0000000..c1dce38
--- /dev/null
+++ b/src/docs/markdown/caddyfile/directives/log_name.md
@@ -0,0 +1,49 @@
+---
+title: log_name (Caddyfile directive)
+---
+
+# log_name
+
+Overrides the logger name to use for a request when writing access logs with the [`log` directive](log).
+
+This directive is useful when you want to log requests to different files based on some condition, such as the request path or method.
+
+More than one logger name can be specified, such that the request's log gets pushed to more than one matching logger.
+
+This is often paired with the `log` directive's [`no_hostname`](log#no_hostname) option, which prevents the logger from being associated with any of the site block's hostnames, so that only requests that set `log_name` will push logs to that logger.
+
+
+## Syntax
+
+```caddy-d
+log_name []
+```
+
+
+## Examples
+
+You may want to log requests to different files, for example you might want to log health checks to a separate file from the main access logs.
+
+Using `no_hostname` in a `log` prevents the logger from being associated with any of the site block's hostnames (i.e. `localhost` here), so that only requests that have `log_name` set to that logger's name will receive logs.
+
+```caddy
+localhost {
+ log {
+ output file ./caddy.access.log
+ }
+
+ log health_check_log {
+ output file ./caddy.access.health.log
+ no_hostname
+ }
+
+ handle /healthz* {
+ log_name health_check_log
+ respond "Healthy"
+ }
+
+ handle {
+ respond "Hello World"
+ }
+}
+```
diff --git a/src/docs/markdown/caddyfile/directives/php_fastcgi.md b/src/docs/markdown/caddyfile/directives/php_fastcgi.md
index 42897e1..2946c34 100644
--- a/src/docs/markdown/caddyfile/directives/php_fastcgi.md
+++ b/src/docs/markdown/caddyfile/directives/php_fastcgi.md
@@ -78,15 +78,18 @@ The `php_fastcgi` directive (without subdirectives) is the same as the following
```caddy-d
route {
# Add trailing slash for directory requests
+ # This redirection is automatically disabled if "{http.request.uri.path}/index.php"
+ # doesn't appear in the try_files list
@canonicalPath {
file {path}/index.php
not path */
}
redir @canonicalPath {http.request.orig_uri.path}/ 308
- # If the requested file does not exist, try index files
+ # If the requested file does not exist, try index files and assume index.php always exists
@indexFiles file {
try_files {path} {path}/index.php index.php
+ try_policy first_exist_fallback
split_path .php
}
rewrite @indexFiles {file_match.relative}
@@ -105,7 +108,9 @@ route {
- The first section deals with canonicalizing the request path. The goal is to ensure that requests that target a directory on disk actually have the trailing slash `/` added to the request path, so that only a single URL is valid for requests to that directory.
- This is performed by using a request matcher that matches only requests that _don't_ end in a slash, and which map to a directory on disk which contains an `index.php` file, and if it matches, performs a HTTP 308 redirect with the trailing slash appended. So for example, it would redirect a request with path `/foo` to `/foo/` (appending a `/`, to canonicalize the path to the directory), if `/foo/index.php` exists on disk.
+ This canonicalization occurs only if the `try_files` subdirective contains `{path}/index.php` (the default).
+
+ This is performed by using a request matcher that matches only requests that _don't_ end in a slash, and which map to a directory on disk which contains an `index.php` file, and if it matches, performs an HTTP 308 redirect with the trailing slash appended. So for example, it would redirect a request with path `/foo` to `/foo/` (appending a `/`, to canonicalize the path to the directory), if `/foo/index.php` exists on disk.
- The next section deals with performing path rewrites based on whether a matching file exists on disk. This also has the side-effect of remembering the part of the path after `.php` (if the request path had `.php` in it). This is important for Caddy to correctly set the FastCGI environment variables.
@@ -113,7 +118,7 @@ route {
- Second, it checks if `{path}/index.php` is a file that exists on disk. If so, it rewrites to that path. For requests to a directory like `/foo/` it'll then look for `/foo//index.php` (which gets normalized to `/foo/index.php`), and rewrite the request to that path if it exists. This behaviour is sometimes useful if you're running another PHP app in a subdirectory of your webroot.
- - Lastly, it'll rewrite to `index.php` if that file exists (it almost always should for modern PHP apps). This allows your PHP app to handle any request for paths that _don't_ map to files on disk, by using the `index.php` script as its entrypoint.
+ - Lastly, it'll always rewrite to `index.php` (it almost always exists for modern PHP apps). This allows your PHP app to handle any request for paths that _don't_ map to files on disk, by using the `index.php` script as its entrypoint.
- And finally, the last section is what actually proxies the request to your PHP FastCGI (or PHP-FPM) service to actually run your PHP code. The request matcher will only match requests which end in `.php`, so, any file that _isn't_ a PHP script and that _does_ exist on disk, will _not_ be handled by this directive, and will fall through.
diff --git a/src/docs/markdown/caddyfile/directives/push.md b/src/docs/markdown/caddyfile/directives/push.md
index 9a8b9df..358b2b2 100644
--- a/src/docs/markdown/caddyfile/directives/push.md
+++ b/src/docs/markdown/caddyfile/directives/push.md
@@ -40,7 +40,7 @@ push [] [] {
}
```
-- **<resource>** is the target URI path to push. If used within the block, may optionally be preceeded by the method (GET or POST; GET is default).
+- **<resource>** is the target URI path to push. If used within the block, may optionally be preceded by the method (GET or POST; GET is default).
- **<headers>** manipulates the headers of the push request using the same syntax as the [`header` directive](/docs/caddyfile/directives/header). Some headers are carried over by default and do not need to be explicitly configured (see above).
diff --git a/src/docs/markdown/caddyfile/directives/request_body.md b/src/docs/markdown/caddyfile/directives/request_body.md
index 3dfbf3e..e25cd26 100644
--- a/src/docs/markdown/caddyfile/directives/request_body.md
+++ b/src/docs/markdown/caddyfile/directives/request_body.md
@@ -6,17 +6,19 @@ title: request_body (Caddyfile directive)
Manipulates or sets restrictions on the bodies of incoming requests.
-
## Syntax
```caddy-d
request_body [] {
max_size
+ set
}
```
- **max_size** is the maximum size in bytes allowed for the request body. It accepts all size values supported by [go-humanize](https://pkg.go.dev/github.com/dustin/go-humanize#pkg-constants). Reads of more bytes will return an error with HTTP status `413`.
+⚠️ Experimental | v2.10.0+
+- **set** allows setting the request body to specific content. The content can include placeholders to dynamically insert data.
## Examples
@@ -30,3 +32,21 @@ example.com {
reverse_proxy localhost:8080
}
```
+
+Set the request body with a JSON structure containing a SQL query:
+
+```caddy
+example.com {
+ handle /jazz {
+ request_body {
+ set `\{"statementText":"SELECT name, genre, debut_year FROM artists WHERE genre = 'Jazz'"}`
+ }
+
+ reverse_proxy localhost:8080 {
+ header_up Content-Type application/json
+ method POST
+ rewrite * /execute-sql
+ }
+ }
+}
+```
diff --git a/src/docs/markdown/caddyfile/directives/reverse_proxy.md b/src/docs/markdown/caddyfile/directives/reverse_proxy.md
index 1fdc564..9d96b2b 100644
--- a/src/docs/markdown/caddyfile/directives/reverse_proxy.md
+++ b/src/docs/markdown/caddyfile/directives/reverse_proxy.md
@@ -11,13 +11,18 @@ window.$(function() {
let text = item.innerText.replace(//g,'>');
let url = '#' + item.innerText.replace(/_/g, "-");
window.$(item).addClass('nd').removeClass('k')
- window.$(item).html(`${text}`);
+ window.$(item).html(`${text}`);
});
// Fix matcher placeholder
- window.$('pre.chroma .k:contains("handle_response")').first().nextAll().slice(0, 3)
+ window.$('pre.chroma .nd:contains("@name")').first()
+ .html('@name')
+ window.$('pre.chroma .k:contains("replace_status")').first().next().slice(0, 3)
.wrapAll('').parent()
- .html('[<matcher>]')
+ .html('[<matcher>]')
+ window.$('pre.chroma .k:contains("handle_response")').first().next().slice(0, 3)
+ .wrapAll('').parent()
+ .html('[<matcher>]')
// We'll add links to all the subdirectives if a matching anchor tag is found on the page.
addLinksToSubdirectives();
@@ -66,12 +71,18 @@ reverse_proxy [] [] {
lb_retry_match
# active health checking
- health_uri
- health_port
- health_interval
- health_timeout
- health_status
- health_body
+ health_uri
+ health_upstream
+ health_port
+ health_interval
+ health_passes
+ health_fails
+ health_timeout
+ health_method
+ health_status
+ health_request_body
+ health_body
+ health_follow_redirects
health_headers {
[]
}
@@ -125,19 +136,20 @@ reverse_proxy [] [] {
-### Upstreams
+## Upstreams
- **<upstreams...>** is a list of upstreams (backends) to which to proxy.
- **to** is an alternate way to specify the list of upstreams, one (or more) per line.
- **dynamic** configures a _dynamic upstreams_ module. This allows getting the list of upstreams dynamically for every request. See [dynamic upstreams](#dynamic-upstreams) below for a description of standard dynamic upstream modules. Dynamic upstreams are retrieved at every proxy loop iteration (i.e. potentially multiple times per request if load balancing retries are enabled) and will be preferred over static upstreams. If an error occurs, the proxy will fall back to using any statically-configured upstreams.
-#### Upstream addresses
+### Upstream addresses
Static upstream addresses can take the form of a URL that contains only scheme and host/port, or a conventional [Caddy network address](/docs/conventions#network-addresses). Valid examples:
- `localhost:4000`
- `127.0.0.1:4000`
+- `[::1]:4000`
- `http://localhost:4000`
- `https://example.com`
- `h2c://127.0.0.1`
@@ -145,6 +157,7 @@ Static upstream addresses can take the form of a URL that contains only scheme a
- `unix//var/php.sock`
- `unix+h2c//var/grpc.sock`
- `localhost:8001-8006`
+- `[fe80::ea9f:80ff:fe46:cbfd%eth0]:443`
By default, connections are made to the upstream over plaintext HTTP. When using the URL form, a scheme can be used to set some [`transport`](#transports) defaults as a shorthand.
- Using `https://` as the scheme will use the [`http` transport](#the-http-transport) with [`tls`](#tls) enabled.
@@ -157,6 +170,8 @@ By default, connections are made to the upstream over plaintext HTTP. When using
Schemes cannot be mixed, since they modify the common transport configuration (a TLS-enabled transport cannot carry both HTTPS and plaintext HTTP). Any explicit transport configuration will not be overwritten, and omitting schemes or using other ports will not assume a particular transport.
+When using IPv6 with a zone (e.g. link-local addresses with a specific network interface), a scheme **cannot** be used as a shortcut because the `%` will result in a URL-parse error; configure the transport explicitly instead.
+
When using the [network address](/docs/conventions#network-addresses) form, the network type is specified as a prefix to the upstream address. This cannot be combined with a URL scheme. As a special case, `unix+h2c/` is supported as a shortcut for the `unix/` network plus the same effects as the `h2c://` scheme. Port ranges are supported as a shortcut, which expands to multiple upstreams with the same host.
Upstream addresses **cannot** contain paths or query strings, as that would imply simultaneous rewriting the request while proxying, which behavior is not defined or supported. You may use the [`rewrite`](/docs/caddyfile/directives/rewrite) directive should you need this.
@@ -164,12 +179,12 @@ Upstream addresses **cannot** contain paths or query strings, as that would impl
If the address is not a URL (i.e. does not have a scheme), then [placeholders](/docs/caddyfile/concepts#placeholders) can be used, but this makes the upstream _dynamically static_, meaning that potentially many different backends act as a single, static upstream in terms of health checks and load balancing. We recommend using a [dynamic upstreams](#dynamic-upstreams) module instead, if possible. When using placeholders, a port **must** be included (either by the placeholder replacement, or as a static suffix to the address).
-#### Dynamic upstreams
+### Dynamic upstreams
Caddy's reverse proxy comes standard with some dynamic upstream modules. Note that using dynamic upstreams has implications for load balancing and health checks, depending on specific policy configuration: active health checks do not run for dynamic upstreams; and load balancing and passive health checks are best served if the list of upstreams is relatively stable and consistent (especially with round-robin). Ideally, dynamic upstream modules only return healthy, usable backends.
-##### SRV
+#### SRV
Retrieves upstreams from SRV DNS records.
@@ -196,7 +211,7 @@ Retrieves upstreams from SRV DNS records.
-##### A/AAAA
+#### A/AAAA
Retrieves upstreams from A/AAAA DNS records.
@@ -221,7 +236,7 @@ Retrieves upstreams from A/AAAA DNS records.
- **versions** is the list of IP versions to resolve for. Default: `ipv4 ipv6` which correspond to both A and AAAA records respectively.
-##### Multi
+#### Multi
Append the results of multiple dynamic upstream modules. Useful if you want redundant sources of upstreams, for example: a primary cluster of SRVs backed up by a secondary cluster of SRVs.
@@ -236,7 +251,7 @@ Append the results of multiple dynamic upstream modules. Useful if you want redu
-### Load balancing
+## Load balancing
Load balancing is typically used to split traffic between multiple upstreams. By enabling retries, it can also be used with one or more upstreams, to hold requests until a healthy upstream can be selected (e.g. to wait and mitigate errors while rebooting or redeploying an upstream).
@@ -263,7 +278,7 @@ This is enabled by default, with the `random` policy. Retries are disabled by de
- `round_robin` iterates each upstream in turn
- - `weighted_round_robin ` iterates each upstream in turn, respecting the weights provided. The amount of weight arguments should match the amount of upstreams configured. Weights should be non-zero positive integers. For example with two upstreams and weights `5 1`, the first upstream would be selected 5 times in a row before the second upstream is selected once, then the cycle repeats.
+ - `weighted_round_robin ` iterates each upstream in turn, respecting the weights provided. The amount of weight arguments should match the amount of upstreams configured. Weights should be non-negative integers. For example with two upstreams and weights `5 1`, the first upstream would be selected 5 times in a row before the second upstream is selected once, then the cycle repeats. If zero is used as a weight, this will disable selecting the upstream for new requests.
- `least_conn` choose upstream with fewest number of current requests; if more than one host has the least number of requests, then one of those hosts is chosen at random
@@ -298,41 +313,53 @@ This is enabled by default, with the `random` policy. Retries are disabled by de
- **lb_try_duration** is a [duration value](/docs/conventions#durations) that defines how long to try selecting available backends for each request if the next available host is down. By default, retries are disabled (zero duration).
- Clients will wait for up to this long while the load balancer tries to find an available upstream host. A reasonable starting point might be `5s` since the HTTP transport's default dial timeout is `3s`, so that should allow for at least one retry if the first selected upstream cannot be reached; but feel free to experiment to find the right balance for your usecase.
+ Clients will wait for up to this long while the load balancer tries to find an available upstream host. A reasonable starting point might be `5s` since the HTTP transport's default dial timeout is `3s`, so that should allow for at least one retry if the first selected upstream cannot be reached; but feel free to experiment to find the right balance for your use case.
- **lb_try_interval** is a [duration value](/docs/conventions#durations) that defines how long to wait between selecting the next host from the pool. Default is `250ms`. Only relevant when a request to an upstream host fails. Be aware that setting this to `0` with a non-zero `lb_try_duration` can cause the CPU to spin if all backends are down and latency is very low.
-- **lb_retry_match** restricts with which requests retries are allowed. A request must match this condition in order to be retried if the connection to the upstream succeded but the subsequent round-trip failed. If the connection to the upstream failed, a retry is always allowed. By default, only `GET` requests are retried.
+- **lb_retry_match** restricts with which requests retries are allowed. A request must match this condition in order to be retried if the connection to the upstream succeeded but the subsequent round-trip failed. If the connection to the upstream failed, a retry is always allowed. By default, only `GET` requests are retried.
The syntax for this option is the same as for [named request matchers](/docs/caddyfile/matchers#named-matchers), but without the `@name`. If you only need a single matcher, you may configure it on the same line. For multiple matchers, a block is necessary.
-#### Active health checks
+### Active health checks
Active health checks perform health checking in the background on a timer. To enable this, `health_uri` or `health_port` are required.
- **health_uri** is the URI path (and optional query) for active health checks.
-- **health_port** is the port to use for active health checks, if different from the upstream's port.
+- **health_upstream** is the ip:port to use for active health checks, if different from the upstream. This should be used in tandem with `health_header` and `{http.reverse_proxy.active.target_upstream}`.
+
+- **health_port** is the port to use for active health checks, if different from the upstream's port. Ignored if `health_upstream` is used.
- **health_interval** is a [duration value](/docs/conventions#durations) that defines how often to perform active health checks. Default: `30s`.
+- **health_passes** is the number of consecutive health checks required before marking the backend as healthy again. Default: `1`.
+
+- **health_fails** is the number of consecutive health checks required before marking the backend as unhealthy. Default: `1`.
+
- **health_timeout** is a [duration value](/docs/conventions#durations) that defines how long to wait for a reply before marking the backend as down. Default: `5s`.
+- **health_method** is the HTTP method to use for the active health check. Default: `GET`.
+
- **health_status** is the HTTP status code to expect from a healthy backend. Can be a 3-digit status code, or a status code class ending in `xx`. For example: `200` (which is the default), or `2xx`.
+- **health_request_body** is a string representing the request body to send with the active health check.
+
- **health_body** is a substring or regular expression to match on the response body of an active health check. If the backend does not return a matching body, it will be marked as down.
+- **health_follow_redirects** will cause the health check to follow redirects provided by upstream. By default, a redirect response would cause the health check to count as a fail.
+
- **health_headers** allows specifying headers to set on the active health check requests. This is useful if you need to change the `Host` header, or if you need to provide some authentication to your backend as part of your health checks.
-#### Passive health checks
+### Passive health checks
Passive health checks happen inline with actual proxied requests. To enable this, `fail_duration` is required.
-- **fail_duration** is a [duration value](/docs/conventions#durations) that defines how long to remember a failed request. A duration > `0` enables passive health checking; the default is `0` (off). A reasonable starting point might be `30s` to balance error rates with responsiveness when bringing an unhealthy upstream back online; but feel free to experiment to find the right balance for your usecase.
+- **fail_duration** is a [duration value](/docs/conventions#durations) that defines how long to remember a failed request. A duration > `0` enables passive health checking; the default is `0` (off). A reasonable starting point might be `30s` to balance error rates with responsiveness when bringing an unhealthy upstream back online; but feel free to experiment to find the right balance for your use case.
- **max_fails** is the maximum number of failed requests within `fail_duration` that are needed before considering a backend to be down; must be >= `1`; default is `1`.
@@ -345,7 +372,7 @@ Passive health checks happen inline with actual proxied requests. To enable this
This should be a reasonably large number; configuring this means that the proxy will have a limit of `unhealthy_request_count × upstreams_count` total simultaneous requests, and any requests after that point will result in an error due to no upstreams being available.
-### Events
+## Events
When an upstream transitions from being healthy to unhealthy or vice-versa, [an event](/docs/caddyfile/options#event-options) is emitted. These events can be used to trigger other actions, such as sending a notification or logging a message. The events are as follows:
@@ -356,7 +383,7 @@ In both cases, the `host` is included as metadata in the event to identify the u
-### Streaming
+## Streaming
By default, the proxy partially buffers the response for wire efficiency.
@@ -383,7 +410,7 @@ By default, WebSocket connections are forcibly closed (with a Close control mess
-### Headers
+## Headers
The proxy can **manipulate headers** between itself and the backend:
@@ -431,9 +458,9 @@ header_up Some-Header "^prefix-([A-Za-z0-9]*)$" "replaced-$1-suffix"
The regular expression language used is RE2, included in Go. See the [RE2 syntax reference](https://github.com/google/re2/wiki/Syntax) and the [Go regexp syntax overview](https://pkg.go.dev/regexp/syntax). The replacement string is [expanded](https://pkg.go.dev/regexp#Regexp.Expand), allowing use of captured values, for example `$1` being the first capture group.
-#### Defaults
+### Defaults
-By default, Caddy passes thru incoming headers—including `Host`—to the backend without modifications, with three exceptions:
+By default, Caddy passes through incoming headers—including `Host`—to the backend without modifications, with three exceptions:
- It sets or augments the [`X-Forwarded-For`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) header field.
- It sets the [`X-Forwarded-Proto`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto) header field.
@@ -454,7 +481,7 @@ If you're using Cloudflare in front of Caddy, be aware that you may be vulnerabl
Additionally, when using the [`http` transport](#the-http-transport), the `Accept-Encoding: gzip` header will be set, if it is missing in the request from the client. This allows the upstream to serve compressed content if it can. This behavior can be disabled with [`compression off`](#compression) on the transport.
-#### HTTPS
+### HTTPS
Since (most) headers retain their original value when being proxied, it is often necessary to override the `Host` header with the configured upstream address when proxying to HTTPS, such that the `Host` header matches the TLS ServerName value:
@@ -466,9 +493,11 @@ reverse_proxy https://example.com {
The `X-Forwarded-Host` header is still passed [by default](#defaults), so the upstream may still use that if it needs to know the original `Host` header value.
+The same applies when terminating TLS in caddy and proxying via HTTP, whether to a port or a unix socket. Indeed, caddy itself must receive the correct Host, when it is the target of `reverse_proxy`. In the unix socket case, the `upstream_hostport` will be the socket path, and the Host must be set explicitly.
-### Rewrites
+
+## Rewrites
By default, Caddy performs the upstream request with the same HTTP method and URI as the incoming request, unless a rewrite was performed in the middleware chain before it reaches `reverse_proxy`.
@@ -486,14 +515,14 @@ For example, the request could be sent to an authentication gateway to decide wh
-### Transports
+## Transports
Caddy's proxy **transport** is pluggable:
- **transport** defines how to communicate with the backend. Default is `http`.
-#### The `http` transport
+### The `http` transport
```caddy-d
transport http {
@@ -522,6 +551,7 @@ transport http {
versions
compression off
max_conns_per_host
+ forward_proxy_url
}
```
@@ -580,15 +610,26 @@ transport http {
- **keepalive_idle_conns_per_host** if non-zero, controls the maximum idle (keep-alive) connections to keep per-host. Default: `32`.
-- **versions** allows customizing which versions of HTTP to support. As a special case, "h2c" is a valid value which will enable cleartext HTTP/2 connections to the upstream (however, this is a non-standard feature that does not use Go's default HTTP transport, so it is exclusive of other features; subject to change or removal). Default: `1.1 2`, or if scheme is `h2c://`, `h2c 2`
+- **versions** allows customizing which versions of HTTP to support.
+
+ Valid options are: `1.1`, `2`, `h2c`, `3`.
+
+ Default: `1.1 2`, or if the [upstream's scheme](#upstream-addresses) is `h2c://`, then the default is `h2c 2`.
+
+ `h2c` enables cleartext HTTP/2 connections to the upstream. This is a non-standard feature that does not use Go's default HTTP transport, so it is exclusive of other features.
+
+ `3` enables HTTP/3 connections to the upstream. ⚠️ This is an experimental feature and is subject to change.
- **compression** can be used to disable compression to the backend by setting it to `off`.
- **max_conns_per_host** optionally limits the total number of connections per host, including connections in the dialing, active, and idle states. Default: No limit.
+- **forward_proxy_url** specifies the URL of a server that the HTTP transport will use to proxy requests to the upstream server. By default, Caddy respects proxy configured via environment variables as per the [Go stdlib](https://pkg.go.dev/golang.org/x/net/http/httpproxy#FromEnvironment) like `HTTP_PROXY`. When a value is provided for this parameter, requests will flow through the reverse proxy in the following order:
+ - Client (users) 🡒 `reverse_proxy` 🡒 `forward_proxy_url` 🡒 upstream
-#### The `fastcgi` transport
+
+### The `fastcgi` transport
```caddy-d
transport fastcgi {
@@ -627,46 +668,33 @@ If you're trying to serve a modern PHP application, you may be looking for the [
-### Intercepting responses
+## Intercepting responses
-The reverse proxy can be configured to intercept responses from the backend. To facilitate this, response matchers can be defined (similar to the syntax for request matchers) and the first matching `handle_response` route will be invoked.
+The reverse proxy can be configured to intercept responses from the backend. To facilitate this, [response matchers](/docs/caddyfile/response-matchers) can be defined (similar to the syntax for request matchers) and the first matching `handle_response` route will be invoked.
When a response handler is invoked, the response from the backend is not written to the client, and the configured `handle_response` route will be executed instead, and it is up to that route to write a response. If the route does _not_ write a response, then request handling will continue with any handlers that are [ordered after](/docs/caddyfile/directives#directive-order) this `reverse_proxy`.
-- **@name** is the name of a [response matcher](#response-matcher). As long as each response matcher has a unique name, multiple matchers can be defined. A response can be matched on the status code and presence or value of a response header.
+- **@name** is the name of a [response matcher](/docs/caddyfile/response-matchers). As long as each response matcher has a unique name, multiple matchers can be defined. A response can be matched on the status code and presence or value of a response header.
+
- **replace_status** simply changes the status code of response when matched by the given matcher.
+
- **handle_response** defines the route to execute when matched by the given matcher (or, if a matcher is omitted, all responses). The first matching block will be applied. Inside a `handle_response` block, any other [directives](/docs/caddyfile/directives) can be used.
Additionally, inside `handle_response`, two special handler directives may be used:
- **copy_response** copies the response body received from the backend back to the client. Optionally allows changing the status code of the response while doing so. This directive is [ordered before `respond`](/docs/caddyfile/directives#directive-order).
+
- **copy_response_headers** copies the response headers from the backend to the client, optionally including _OR_ excluding a list of headers fields (cannot specify both `include` and `exclude`). This directive is [ordered after `header`](/docs/caddyfile/directives#directive-order).
Three placeholders will be made available within the `handle_response` routes:
- `{rp.status_code}` The status code from the backend's response.
+
- `{rp.status_text}` The status text from the backend's response.
+
- `{rp.header.*}` The headers from the backend's response.
-
-#### Response matcher
-
-**Response matchers** can be used to filter (or classify) responses by specific criteria.
-
-##### status
-
-```caddy-d
-status
-```
-
-By HTTP status code.
-
-- **<code...>** is a list of HTTP status codes. Special cases are strings like `2xx` and `3xx`, which match against all status codes in the range of `200`-`299` and `300`-`399`, respectively.
-
-##### header
-
-See the [`header`](/docs/caddyfile/matchers#header) request matcher for the supported syntax.
-
+While the reverse proxy response handler can copy the new response received from the proxy back to the client, it cannot pass on that new response to a subsequent reverse proxy. Every use of `reverse_proxy` receives the body from the original request (or as modified with a different module).
@@ -752,13 +780,13 @@ example.com {
```
-Instead you may establish trust with the upstream by explicitly [trusting the upstream's certificate](#tls_trusted_ca_certs), and (optionally) setting TLS-SNI to match the hostname in the upstream's certificate:
+Instead you may establish trust with the upstream by explicitly [trusting the upstream's certificate](#tls_trust_pool), and (optionally) setting TLS-SNI to match the hostname in the upstream's certificate:
```caddy
example.com {
reverse_proxy 10.0.0.1:443 {
transport http {
- tls_trusted_ca_certs /path/to/cert.pem
+ tls_trust_pool file /path/to/cert.pem
tls_server_name app.example.com
}
}
@@ -845,3 +873,16 @@ example.com {
```
+Using [active health checks](#active-health-checks) and `health_upstream` can be helpful when creating an intermediate service to do a more thorough health check. `{http.reverse_proxy.active.target_upstream}` can then be used as a header to provide the original upstream to the health check service.
+
+```caddy
+example.com {
+ reverse_proxy node1:80 node2:80 node3:80 {
+ health_uri /health
+ health_upstream 127.0.0.1:53336
+ health_headers {
+ Full-Upstream {http.reverse_proxy.active.target_upstream}
+ }
+ }
+}
+```
diff --git a/src/docs/markdown/caddyfile/directives/templates.md b/src/docs/markdown/caddyfile/directives/templates.md
index c640829..c0f60fe 100644
--- a/src/docs/markdown/caddyfile/directives/templates.md
+++ b/src/docs/markdown/caddyfile/directives/templates.md
@@ -54,6 +54,6 @@ To serve a simple static response using a template, make sure to set `Content-Ty
example.com {
header Content-Type text/plain
templates
- respond "Current year is: {{printf "{{"}}now | date "2006"{{printf "}}"}}"
+ respond `Current year is: {{printf "{{"}}now | date "2006"{{printf "}}"}}`
}
```
diff --git a/src/docs/markdown/caddyfile/directives/tls.md b/src/docs/markdown/caddyfile/directives/tls.md
index c1c122d..a64dab3 100644
--- a/src/docs/markdown/caddyfile/directives/tls.md
+++ b/src/docs/markdown/caddyfile/directives/tls.md
@@ -24,7 +24,7 @@ Compatibility note: Due to its sensitive nature as a security protocol, delibera
tls [internal|] | [ ] {
protocols []
ciphers
- curves
+ curves
alpn
load
ca
@@ -42,8 +42,6 @@ tls [internal|] | [ ] {
client_auth {
mode [request|require|verify_if_given|require_and_verify]
trust_pool
- trusted_leaf_cert
- trusted_leaf_cert_file
verifier
}
issuer []
@@ -84,7 +82,8 @@ Keep in mind that Let's Encrypt may send you emails about your certificate neari
- `TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA`
- `TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA`
-- **curves** specifies the list of EC curves to support. It is recommended to not change these. Supported values are:
+- **curves** specifies the list of EC groups to support. It is recommended to not change the defaults. Supported values are:
+ - `x25519mlkem768` (PQC)
- `x25519`
- `secp256r1`
- `secp384r1`
@@ -140,16 +139,12 @@ Keep in mind that Let's Encrypt may send you emails about your certificate neari
| verify_if_given | Ask clients for a certificate; allow even if there isn't one, but verify it if there is |
| require_and_verify | Require clients to present a valid certificate that is verified |
- Default: `require_and_verify` if any `trusted_ca_cert` or `trusted_leaf_cert` are provided; otherwise, `require`.
+ Default: `require_and_verify` if `trust_pool` module is provided; otherwise, `require`.
- **trust_pool** configures the source of certificate authorities (CA) providing certificates against which to validate client certificates.
The certificate authority used providing the pool of trusted certificates and the configuration within the segment depends on the configured source of trust pool module. The standard modules available in Caddy are [listed below](#trust-pool-providers). The full list of modules, including 3rd-party, is listed in the [`trust_pool` JSON documentation](/docs/json/apps/http/servers/tls_connection_policies/client_authentication/#trust_pool).
- - **trusted_leaf_cert** is a base64 DER-encoded client leaf certificate to accept.
-
- - **trusted_leaf_cert_file** is a path to a PEM CA certificate file against which to validate client certificates.
-
Multiple `trusted_*` directives may be used to specify multiple CA or leaf certificates. Client certificates which are not listed as one of the leaf certificates or signed by any of the specified CAs will be rejected according to the **mode**.
- **verifier** enables the use of a custom client certificate verifier module. These can perform custom client authentication checks, such as ensuring the certificate is not revoked.
@@ -291,7 +286,7 @@ Obtains certificates using the ACME protocol. Note that `acme` is a default issu
alt_tlsalpn_port
eab
trusted_roots
- dns []
+ dns [ []]
propagation_timeout
propagation_delay
dns_ttl
@@ -328,7 +323,7 @@ Obtains certificates using the ACME protocol. Note that `acme` is a default issu
- **trusted_roots** is one or more root certificates (as PEM filenames) to trust when connecting to the ACME CA server.
-- **dns** configures the DNS challenge.
+- **dns** configures the DNS challenge. A provider must be configured here, unless the [`dns` global option](/docs/caddyfile/options#dns) specifies a globally-applicable DNS provider module.
- **propagation_timeout** is a [duration value](/docs/conventions#durations) that sets the maximum time to wait for the DNS TXT records to appear when using the DNS challenge. Set to `-1` to disable propagation checks. Default 2 minutes.
@@ -362,19 +357,32 @@ Obtains certificates using the ACME protocol. Note that `acme` is a default issu
#### zerossl
-Obtains certificates using the ACME protocol, specifically with ZeroSSL. Note that `zerossl` is a default issuer, so configuring it explicitly is usually unnecessary.
+Obtains certificates using [ZeroSSL's proprietary certificate issuance API](https://zerossl.com/documentation/api/). An API key is required and payment may also be required depending on your plan. Note that this issue is distinct from [ZeroSSL's ACME endpoint](https://zerossl.com/documentation/acme/). To use ZeroSSL's ACME endpoint, use the `acme` issuer described above configured with ZeroSSL's ACME directory endpoint.
```caddy-d
-... zerossl [] {
- ...
+... zerossl {
+ validity_days
+ alt_http_port
+ dns ...
+ propagation_delay
+ propagation_timeout
+ resolvers
+ dns_ttl
}
```
-The syntax for `zerossl` is exactly the same as for [`acme`](#acme), except that its name is `zerossl` and it can optionally take your ZeroSSL API key.
+- **validity_days** defines the certificate lifetime. Only certain values are accepted; see [ZeroSSL's docs](https://zerossl.com/documentation/api/create-certificate/) for details.
+
+- **alt_http_port** is the port to use for completing ZeroSSL's HTTP validation, if not port 80.
+- **dns** enables CNAME validation method using the named DNS provider with the given configuration for automatic record provisioning. The DNS provider plugin must be installed from the [`caddy-dns`
](https://github.com/caddy-dns) repositories. Each provider plugin may have their own syntax following their name; refer to their docs for details. Maintaining support for each DNS provider is a community effort.
+- **propagation_delay** is how long to wait before checking for CNAME record propagation.
+- **propagation_timeout** is how long to wait for CNAME record propagation before giving up.
+- **resolvers** defines custom DNS resolvers to use when checking for CNAME record propagation.
+- **dns_ttl** configures the TTL for CNAME records created as part of the validation process.
-Its functionality is also the same, except that it will use ZeroSSL's directory by default and it can automatically negotiate EAB credentials (whereas with the `acme` issuer, you have to manually provide EAB credentials and set the directory endpoint).
-When explicitly configuring `zerossl`, configuring an `email` is required so that your certificates can appear in your ZeroSSL dashboard.
#### internal
@@ -394,7 +402,7 @@ Obtains certificates from an internal certificate authority.
Caddy will attempt to install the root CA certificate to the system trust store, but this may fail when Caddy is running as an unprivileged user, or when running in a Docker container. In that case, the root CA certificate will need to be manually installed, either by using the [`caddy trust`](/docs/command-line#caddy-trust) command, or by [copying out of the container](/docs/running#usage).
-- **lifetime** is a [duration value](/docs/conventions#durations) that sets the validity period for interally issued leaf certificates. Default: `12h`. It is NOT recommended to change this, unless absolutely necessary. It must be shorter than the intermediate's lifetime.
+- **lifetime** is a [duration value](/docs/conventions#durations) that sets the validity period for internally issued leaf certificates. Default: `12h`. It is NOT recommended to change this, unless absolutely necessary. It must be shorter than the intermediate's lifetime.
- **sign_with_root** forces the root to be the issuer instead of the intermediate. This is NOT recommended and should only be used when devices/clients do not properly validate certificate chains (very uncommon).
@@ -501,15 +509,13 @@ https:// {
}
```
-Enable TLS Client Authentication and require clients to present a valid certificate that is verified against all the provided CA's via `trusted_ca_cert_file`
+Enable TLS Client Authentication and require clients to present a valid certificate that is verified against all the provided CA's via the [`trust_pool`](#trust_pool) `file` provider:
```caddy
example.com {
tls {
client_auth {
- mode require_and_verify
- trusted_ca_cert_file ../caddy.ca.cer
- trusted_ca_cert_file ../root.ca.cer
+ trust_pool file ../caddy.ca.cer ../root.ca.cer
}
}
}
diff --git a/src/docs/markdown/caddyfile/directives/tracing.md b/src/docs/markdown/caddyfile/directives/tracing.md
index 881f279..c7b6a2f 100644
--- a/src/docs/markdown/caddyfile/directives/tracing.md
+++ b/src/docs/markdown/caddyfile/directives/tracing.md
@@ -10,7 +10,9 @@ When enabled, it will propagate an existing trace context or initialize a new on
It uses [gRPC](https://github.com/grpc/) as an exporter protocol and W3C [tracecontext](https://www.w3.org/TR/trace-context/) and [baggage](https://www.w3.org/TR/baggage/) as propagators.
-The trace ID is added to [access logs](/docs/caddyfile/directives/log) as the standard `traceID` field.
+The trace ID and span ID are added to [access logs](/docs/caddyfile/directives/log) as the standard `traceID` and `spanID` fields. Additionally, the `{http.vars.trace_id}` and `{http.vars.span_id}` placeholders are available; for example, you can use them in a [`request_header`](request_header) to pass the IDs to your app.
+
+
## Syntax
@@ -24,6 +26,8 @@ tracing {
[Placeholders](/docs/caddyfile/concepts#placeholders) may be used in span names; keep in mind that tracing happens as early as possible, so only request placeholders may be used, and not response placeholders.
+
+
## Configuration
### Environment variables
@@ -41,6 +45,8 @@ export OTEL_EXPORTER_OTLP_HEADERS="myAuthHeader=myToken,anotherHeader=value"
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://my-otlp-endpoint:55680
```
+
+
## Examples
Here is a **Caddyfile** example:
@@ -51,6 +57,7 @@ example.com {
tracing {
span api
}
+ request_header X-Trace-Id {http.vars.trace_id}
reverse_proxy localhost:8081
}
diff --git a/src/docs/markdown/caddyfile/directives/try_files.md b/src/docs/markdown/caddyfile/directives/try_files.md
index 5512622..39df0f8 100644
--- a/src/docs/markdown/caddyfile/directives/try_files.md
+++ b/src/docs/markdown/caddyfile/directives/try_files.md
@@ -11,7 +11,7 @@ Rewrites the request URI path to the first of the listed files which exists in t
```caddy-d
try_files {
- policy first_exist|smallest_size|largest_size|most_recently_modified
+ policy first_exist|first_exist_fallback|smallest_size|largest_size|most_recently_modified
}
```
diff --git a/src/docs/markdown/caddyfile/directives/uri.md b/src/docs/markdown/caddyfile/directives/uri.md
index 5acb2c7..7287f27 100644
--- a/src/docs/markdown/caddyfile/directives/uri.md
+++ b/src/docs/markdown/caddyfile/directives/uri.md
@@ -18,23 +18,56 @@ uri [] strip_prefix
uri [] strip_suffix
uri [] replace []
uri [] path_regexp
+uri [] query [-|+] []
+uri [] query {
+ [] []
+ ...
+}
```
-- The first (non-matcher) argument specifies the operation:
+The first (non-matcher) argument specifies the operation:
- - **strip_prefix** strips the prefix from the path.
+- **strip_prefix** strips the prefix from the path.
- - **strip_suffix** strips the suffix from the path.
+- **strip_suffix** strips the suffix from the path.
- - **replace** performs a substring replacement across the whole URI.
+- **replace** performs a substring replacement across the whole URI.
- - **path_regexp** performs a regular expression replacement on the path portion of the URI.
+ - **<target>** is the prefix, suffix, or search string/regular expression. If a prefix, the leading forward slash may be omitted, since paths always start with a forward slash.
-- **<target>** is the prefix, suffix, or search string/regular expression. If a prefix, the leading forward slash may be omitted, since paths always start with a forward slash.
+ - **<replacement>** is the replacement string. Supports using capture groups with `$name` or `${name}` syntax, or with a number for the index, such as `$1`. See the [Go documentation](https://golang.org/pkg/regexp/#Regexp.Expand) for details. If the replacement value is `""`, then the matching text is removed from the value.
-- **<replacement>** is the replacement string (only valid with `replace` and `path_regexp`). Supports using capture groups with `$name` or `${name}` syntax, or with a number for the index, such as `$1`. See the [Go documentation](https://golang.org/pkg/regexp/#Regexp.Expand) for details.
+ - **<limit>** is an optional limit to the maximum number of replacements.
-- **<limit>** is an optional limit to the maximum number of replacements (only valid with `replace`).
+- **path_regexp** performs a regular expression replacement on the path portion of the URI.
+
+ - **<target>** is the prefix, suffix, or search string/regular expression. If a prefix, the leading forward slash may be omitted, since paths always start with a forward slash.
+
+ - **<replacement>** is the replacement string. Supports using capture groups with `$name` or `${name}` syntax, or with a number for the index, such as `$1`. See the [Go documentation](https://golang.org/pkg/regexp/#Regexp.Expand) for details. If the replacement value is `""`, then the matching text is removed from the value.
+
+- **query** performs manipulations on the URI query, with the mode depending on the prefix to the parameter name or the count of arguments. A block can be used to specify multiple operations at once, grouped and performed in this order: rename 🡒 set 🡒 append 🡒 replace 🡒 delete.
+
+ - With no prefix, the parameter is set with the given value in the query.
+
+ For example, `uri query foo bar` will set the value of the `foo` param to `bar`.
+
+ - Prefix with `-` to remove the parameter from the query.
+
+ For example, `uri query -foo` will delete the `foo` parameter from the query.
+
+ - Prefix with `+` to append a parameter to the query, with the given value. This will _not_ overwrite an existing parameter with the same name (omit the `+` to overwrite).
+
+ For example, `uri query +foo bar` will append `foo=bar` to the query.
+
+ - A param with `>` as an infix will rename the parameter to the value after the `>`.
+
+ For example, `uri query foo>bar` will rename the `foo` parameter to `bar`.
+
+ - With three arguments, query value regular expression replacement is performed, where the first arg is the query param name, the second is the search value, and the third is the replacement. The first arg (param name) may be `*` to perform the replacement on all query params.
+
+ Supports using capture groups with `$name` or `${name}` syntax, or with a number for the index, such as `$1`. See the [Go documentation](https://golang.org/pkg/regexp/#Regexp.Expand) for details. If the replacement value is `""`, then the matching text is removed from the value.
+
+ For example, `uri query foo ^(ba)r $1z` would replace the value of the `foo` param, where the value began with `bar` resulting in the value becoming `baz`.
URI mutations occur on the normalized or unescaped form of the URI. However, escape sequences can be used in the prefix or suffix patterns to match only those literal escapes at those positions in the request path. For example, `uri strip_prefix /a/b` will rewrite both `/a/b/c` and `/a%2Fb/c` to `/c`; and `uri strip_prefix /a%2Fb` will rewrite `/a%2Fb/c` to `/c`, but won't match `/a/b/c`.
@@ -74,3 +107,44 @@ Collapse all repeated slashes in the request path (but not the request query) to
```caddy-d
uri path_regexp /{2,} /
```
+
+Set the value of the `foo` query parameter to `bar`:
+
+```caddy-d
+uri query foo bar
+```
+
+Remove the `foo` parameter from the query:
+
+```caddy-d
+uri query -foo
+```
+
+Rename the `foo` query parameter to `bar`:
+
+```caddy-d
+uri query foo>bar
+```
+
+Append the `bar` parameter to the query:
+
+```caddy-d
+uri query +foo bar
+```
+
+Replace the value of the `foo` query parameter where the value begins with `bar` with `baz`:
+
+```caddy-d
+uri query foo ^(ba)r $1z
+```
+
+Perform multiple query operations at once:
+
+```caddy-d
+uri query {
+ +foo bar
+ -baz
+ qux test
+ renamethis>renamed
+}
+```
diff --git a/src/docs/markdown/caddyfile/directives/vars.md b/src/docs/markdown/caddyfile/directives/vars.md
index 2497c2c..e002138 100644
--- a/src/docs/markdown/caddyfile/directives/vars.md
+++ b/src/docs/markdown/caddyfile/directives/vars.md
@@ -6,9 +6,11 @@ title: vars (Caddyfile directive)
Sets one or more variables to a particular value, to be used later in the request handling chain.
-The primary way to access variables is with placeholders, which have the form `{vars.variable_name}`, or with the [`vars`](/docs/caddyfile/matchers#vars) and [`vars_regexp`](/docs/caddyfile/matchers#vars_regexp) request matchers. You may use variables with the [`templates`](templates) directive using the `placeholder` function, for example: `{{placeholder "http.vars.variable_name"}}`
+The primary way to access variables is with placeholders, which have the form `{vars.variable_name}`, or with the [`vars`](/docs/caddyfile/matchers#vars) and [`vars_regexp`](/docs/caddyfile/matchers#vars_regexp) request matchers.
-As a special case, it's possible to override the variable named `http.auth.user.id`, which is stored in the replacer, to update the `user_id` field in access logs.
+You may use variables with the [`templates`](templates) directive using the `placeholder` function, for example: `{{ "{{placeholder \"http.vars.variable_name\"}}" }}`
+
+As a special case, it's possible to override the variable named `http.auth.user.id`, which is stored in the replacer, to update the `user_id` field in [access logs](log).
## Syntax
@@ -24,7 +26,7 @@ vars [] [ ] {
- **<value>** is the value of the variable.
- The value will be type converted if possible; `true` and `false` will be converted to boolean types, and numeric values will be converted to integer or float accordingly. To avoid this conversion, you may wrap the output with [quotes](/docs/caddyfile/concepts#tokens-and-quotes) and they will stay strings.
+ The value will be type converted if possible; `true` and `false` will be converted to boolean types, and numeric values will be converted to integer or float accordingly. To avoid this conversion and keep them as strings, you may wrap them with [quotes](/docs/caddyfile/concepts#tokens-and-quotes).
## Examples
diff --git a/src/docs/markdown/caddyfile/matchers.md b/src/docs/markdown/caddyfile/matchers.md
index 344822e..53e62b4 100644
--- a/src/docs/markdown/caddyfile/matchers.md
+++ b/src/docs/markdown/caddyfile/matchers.md
@@ -146,7 +146,7 @@ Then you can use the matcher like so, by specifying it as the first argument to
directive @name
```
-For example, this proxies websocket requests to `localhost:6001`, and other requests to `localhost:8080`. It matches requests that have a header field named `Connection` _containing_ `Upgrade`, **and** another field named `Upgrade` with exactly `websocket`:
+For example, this proxies HTTP/1.1 websocket requests to `localhost:6001`, and other requests to `localhost:8080`. It matches requests that have a header field named `Connection` _containing_ `Upgrade`, **and** another field named `Upgrade` with exactly `websocket`:
```caddy
example.com {
@@ -300,7 +300,7 @@ respond @api "Hello, API!"
file {
root
try_files
- try_policy first_exist|smallest_size|largest_size|most_recently_modified
+ try_policy first_exist|first_exist_fallback|smallest_size|largest_size|most_recently_modified
split_path
}
file
@@ -308,7 +308,7 @@ file
expression `file({
'root': '',
'try_files': [''],
- 'try_policy': 'first_exist|smallest_size|largest_size|most_recently_modified',
+ 'try_policy': 'first_exist|first_exist_fallback|smallest_size|largest_size|most_recently_modified',
'split_path': ['']
})`
expression file('')
@@ -330,6 +330,8 @@ By files.
- `first_exist` checks for file existence. The first file that exists is selected.
+ - `first_exist_fallback` is similar to `first_exist`, but assumes that the last element in the list always exists to prevent a disk access.
+
- `smallest_size` chooses the file with the smallest size.
- `largest_size` chooses the file with the largest size.
@@ -397,7 +399,7 @@ Some more examples using [CEL expressions](#expression). Keep in mind that place
### header
```caddy-d
-header []
+header [ ...]
expression header({'': ''})
```
@@ -406,7 +408,7 @@ By request header fields.
- `` is the name of the HTTP header field to check.
- If prefixed with `!`, the field must not exist to match (omit value arg).
-- `` is the value the field must have to match.
+- `` is the value the field must have to match. One or more may be specified.
- If prefixed with `*`, it performs a fast suffix match (appears at the end).
- If suffixed with `*`, it performs a fast prefix match (appears at the start).
- If enclosed by `*`, it performs a fast substring match (appears anywhere).
@@ -439,10 +441,10 @@ Match requests that do not have the `Foo` header field at all:
@not_foo header !Foo
```
-Using an [CEL expression](#expression), match WebSocket requests by checking for the `Connection` header containing `Upgrade` and the `Upgrade` header equalling `websocket`:
+Using an [CEL expression](#expression), match WebSocket requests by checking for the `Connection` header containing `Upgrade` and the `Upgrade` header equalling `websocket` (HTTP/2 has the `:protocol` header for this):
```caddy-d
-@websockets `header({'Connection':'*Upgrade*','Upgrade':'websocket'})`
+@websockets `header({'Connection':'*Upgrade*','Upgrade':'websocket'}) || header({':protocol': 'websocket'})`
```
@@ -460,7 +462,7 @@ Like [`header`](#header), but supports regular expressions.
The regular expression language used is RE2, included in Go. See the [RE2 syntax reference](https://github.com/google/re2/wiki/Syntax) and the [Go regexp syntax overview](https://pkg.go.dev/regexp/syntax).
-As of v2.8.0, if `name` is _not_ provided, the name will be taken from the named matcher's name. For example a named matcher `@foo` will cause this matcher to be named `foo`. The main advantage of specifying a name is if more than one regexp matcher is used in the same named matcher.
+As of v2.8.0, if `name` is _not_ provided, the name will be taken from the named matcher's name. For example a named matcher `@foo` will cause this matcher to be named `foo`. The main advantage of specifying a name is if more than one regexp matcher (e.g. `header_regexp` and [`path_regexp`](#path-regexp), or multiple different header fields) is used in the same named matcher.
Capture groups can be accessed via [placeholder](/docs/caddyfile/concepts#placeholders) in directives after matching:
- `{re..}` where:
@@ -471,7 +473,7 @@ Capture groups can be accessed via [placeholder](/docs/caddyfile/concepts#placeh
Capture group `0` is the full regexp match, `1` is the first capture group, `2` is the second capture group, and so on. So `{re.foo.1}` or `{re.1}` will both hold the value of the first capture group.
-Only one regular expression is supported per header field. Multiple different fields will be AND'ed.
+Only one regular expression is supported per header field, since regexp patterns cannot be merged; if you need more, consider using an [`expression` matcher](#expression). Matches against multiple different header fields will be AND'ed.
#### Example:
@@ -705,7 +707,7 @@ Like [`path`](#path), but supports regular expressions. Runs against the URI-dec
The regular expression language used is RE2, included in Go. See the [RE2 syntax reference](https://github.com/google/re2/wiki/Syntax) and the [Go regexp syntax overview](https://pkg.go.dev/regexp/syntax).
-As of v2.8.0, if `name` is _not_ provided, the name will be taken from the named matcher's name. For example a named matcher `@foo` will cause this matcher to be named `foo`. The main advantage of specifying a name is if more than one regexp matcher is used in the same named matcher.
+As of v2.8.0, if `name` is _not_ provided, the name will be taken from the named matcher's name. For example a named matcher `@foo` will cause this matcher to be named `foo`. The main advantage of specifying a name is if more than one regexp matcher (e.g. `path_regexp` and [`header_regexp`](#header-regexp)) is used in the same named matcher.
Capture groups can be accessed via [placeholder](/docs/caddyfile/concepts#placeholders) in directives after matching:
- `{re..}` where:
@@ -716,7 +718,7 @@ Capture groups can be accessed via [placeholder](/docs/caddyfile/concepts#placeh
Capture group `0` is the full regexp match, `1` is the first capture group, `2` is the second capture group, and so on. So `{re.foo.1}` or `{re.1}` will both hold the value of the first capture group.
-There can only be one `path_regexp` pattern per named matcher.
+There can only be one `path_regexp` pattern per named matcher, since this matcher cannot be merged with itself; if you need more, consider using an [`expression` matcher](#expression).
#### Example:
@@ -774,12 +776,13 @@ With a [CEL expression](#expression):
```caddy-d
query =...
+query ""
expression query({'': ''})
expression query({'': ['']})
```
-By query string parameters. Should be a sequence of `key=value` pairs. Keys are matched exactly (case-sensitively) but also support `*` to match any value. Values can use placeholders.
+By query string parameters. Should be a sequence of `key=value` pairs, or an empty string "". Keys are matched exactly (case-sensitively) but also support `*` to match any value. Values can use placeholders. Empty string matches http requests with no query parameters.
There can be multiple `query` matchers per named matcher, and pairs with the same keys will be OR'ed together. Different keys will be AND'ed together. So, all keys in the matcher must have at least one matching value.
@@ -874,6 +877,12 @@ Match an output of the [`map` directive](/docs/caddyfile/directives/map) named `
vars {magic_number} 3 5
```
+Match an arbitrary placeholder's value, i.e. the authenticated user's ID, either `Bob` or `Alice`:
+
+```caddy-d
+vars {http.auth.user.id} Bob Alice
+```
+
---
@@ -887,7 +896,7 @@ Like [`vars`](#vars), but supports regular expressions.
The regular expression language used is RE2, included in Go. See the [RE2 syntax reference](https://github.com/google/re2/wiki/Syntax) and the [Go regexp syntax overview](https://pkg.go.dev/regexp/syntax).
-As of v2.8.0, if `name` is _not_ provided, the name will be taken from the named matcher's name. For example a named matcher `@foo` will cause this matcher to be named `foo`. The main advantage of specifying a name is if more than one regexp matcher is used in the same named matcher.
+As of v2.8.0, if `name` is _not_ provided, the name will be taken from the named matcher's name. For example a named matcher `@foo` will cause this matcher to be named `foo`. The main advantage of specifying a name is if more than one regexp matcher (e.g. `vars_regexp` and [`header_regexp`](#header-regexp)) is used in the same named matcher.
Capture groups can be accessed via [placeholder](/docs/caddyfile/concepts#placeholders) in directives after matching:
- `{re..}` where:
@@ -898,7 +907,7 @@ Capture groups can be accessed via [placeholder](/docs/caddyfile/concepts#placeh
Capture group `0` is the full regexp match, `1` is the first capture group, `2` is the second capture group, and so on. So `{re.foo.1}` or `{re.1}` will both hold the value of the first capture group.
-There can only be one `vars_regexp` matcher per named matcher.
+Only one regular expression is supported per variable name, since regexp patterns cannot be merged; if you need more, consider using an [`expression` matcher](#expression). Matches against multiple different variables will be AND'ed.
#### Example:
diff --git a/src/docs/markdown/caddyfile/options.md b/src/docs/markdown/caddyfile/options.md
index cf58874..d208eba 100644
--- a/src/docs/markdown/caddyfile/options.md
+++ b/src/docs/markdown/caddyfile/options.md
@@ -76,6 +76,9 @@ Possible options are (click on each option to jump to its documentation):
}
grace_period
shutdown_delay
+ metrics {
+ per_host
+ }
# TLS Options
auto_https off|disable_redirects|ignore_loaded_certs|disable_certs
@@ -91,14 +94,18 @@ Possible options are (click on each option to jump to its documentation):
mac_key
}
acme_dns ...
+ dns ...
+ ech {
+ dns ...
+ }
on_demand_tls {
- ask
- interval
- burst
+ ask
+ permission
}
key_type ed25519|p256|p384|rsa2048|rsa4096
cert_issuer ...
renew_interval
+ cert_lifetime
ocsp_interval
ocsp_stapling off
preferred_chains [smallest] {
@@ -121,7 +128,7 @@ Possible options are (click on each option to jump to its documentation):
keepalive_interval
trusted_proxies ...
client_ip_headers
- metrics
+ trace
max_header_size
enable_full_duplex
log_credentials
@@ -328,7 +335,7 @@ The name can be passed to indicate a specific logger for which to customize the
Multiple loggers with different names can be configured by using the `log` multiple times.
-The differs from the [`log` directive](/docs/caddyfile/directives/log), which only configures HTTP request logging (also known as access logs). The `log` global option shares its configuration structure with the directive (except for `include` and `exclude`), and complete documentation can be found on the directive's page.
+This differs from the [`log` directive](/docs/caddyfile/directives/log), which only configures HTTP request logging (also known as access logs). The `log` global option shares its configuration structure with the directive (except for `include` and `exclude`), and complete documentation can be found on the directive's page.
- **output** configures where to write the logs.
@@ -548,6 +555,49 @@ The tokens following the name of the provider set up the provider the same as if
```
+##### `dns`
+Configures a default DNS provider to use when none other is specified locally in a relevant context. For example, if the ACME DNS challenge is enabled but does not have a DNS provider configured, this global default will be used. It is also applied for publishing Encrypted ClientHello (ECH) configs.
+
+Your Caddy binary must be compiled with the specified DNS provider module for this to work.
+
+Example, using credentials from an environment variable:
+
+```caddy
+{
+ dns cloudflare {env.CLOUDFLARE_API_TOKEN}
+}
+```
+
+(Requires Caddy 2.10 beta 1 or newer.)
+
+
+##### `ech`
+Enables Encrypted ClientHello (ECH) by using the specified public domain name(s) as the plaintext server name (SNI) in TLS handshakes. Given the right conditions, ECH can help protect the domain names of your sites on the wire during connections. Caddy will generate and publish one ECH config for each public name specified. Publication is how compatible clients (such as properly-configured modern browsers) know to use ECH to access your sites.
+
+In order to work properly, the ECH config(s) must be published in a way that clients expect. Most browsers (with DNS-over-HTTPS or DNS-over-TLS enabled) expect ECH configs to be published to HTTPS-type DNS records. Caddy does this kind of publication automatically, but you have to specify a DNS provider either with the `dns` sub-option, or globally with the [`dns` global option](#dns), and your Caddy binary must be built with the specified DNS provider module. (Custom builds are available on our [download page](/download).)
+
+**Privacy notices:**
+
+- It is generally advisable to **maximize the size of your [_anonymity set_](https://www.ietf.org/archive/id/draft-ietf-tls-esni-23.html#name-introduction)**. As such, we typically recommend that most users configure _only one_ public domain name to protect all your sites.
+- **Your server should be authoritative for the public domain name(s) you specify** (i.e. they should point to your server) because Caddy will obtain a certificate for them. These certificates are vital to help spec-conforming clients connect reliably and safely with ECH in some cases. They are only used to faciliate a proper ECH handshake, not used for application data (your sites -- unless you define a site that is the same as your public domain name).
+- Every circumstance may be different. We recommend consulting experts to **review your threat model** if the stakes are high, as ECH is not a one-size-fits-all solution.
+
+Example using credentials from an environment variable for publication to nameservers parked at Cloudflare:
+
+```caddy
+{
+ dns cloudflare {env.CLOUDFLARE_API_TOKEN}
+ ech ech.example.net
+}
+```
+
+This should cause compatible clients to load all your sites with `ech.example.net`, rather than the individual site names exposed in plaintext.
+
+Successful publication requires that your site's domains are parked at the configured DNS provider and the records can be modified with the given credentials / provider configuration.
+
+(Requires Caddy 2.10 beta 1 or newer.)
+
+
##### `on_demand_tls`
Configures [On-Demand TLS](/docs/automatic-https#on-demand-tls) where it is enabled, but does not enable it (to enable it, use the [`on_demand` subdirective of the `tls` directive](/docs/caddyfile/directives/tls#syntax)). Required for use in production environments, to prevent abuse.
@@ -563,7 +613,9 @@ The ask endpoint should return _as fast as possible_, in a few milliseconds, ide
-- **interval** and **burst** allows `` certificate operations within `` interval. These are deprecated and will be removed in a future version, due to not working as intended.
+- **permission** allows custom modules to be used to determine whether a certificate should be issued for a particular name. The module must implement the [`caddytls.OnDemandPermission` interface](https://pkg.go.dev/github.com/caddyserver/caddy/v2/modules/caddytls#OnDemandPermission). An `http` permission module is included, which is what the `ask` option uses, and remains as a shortcut for backwards compatibility.
+
+- ⚠️ **interval** and **burst** rate limiting options were available, but are NOT recommended. Remove them from your config if you still have them.
```caddy
{
@@ -623,6 +675,22 @@ Default: `10m`
```
+##### `cert_lifetime`
+The validity period to ask the CA to issue a certificate for.
+
+This value is used to compute the `notAfter` field of the ACME order; therefore the system must have a reasonably synchronized clock. NOTE: Not all CAs support this. Check with your CA's ACME documentation to see if this is allowed and what values may be used.
+
+Default: `0` (CA chooses lifetime, usually 90 days)
+
+⚠️ This is an experimental feature. Subject to change or removal.
+
+```caddy
+{
+ cert_lifetime 30d
+}
+```
+
+
##### `ocsp_interval`
How often to check if [OCSP staples
](https://en.wikipedia.org/wiki/OCSP_stapling) need updating.
@@ -768,9 +836,13 @@ http:// {
Allows configuring [listener wrappers](/docs/json/apps/http/servers/listener_wrappers/), which can modify the behaviour of the socket listener. They are applied in the given order.
-There is a special no-op [`tls`](/docs/json/apps/http/servers/listener_wrappers/tls/) listener wrapper provided as a standard module which marks where TLS should be handled in the chain of listener wrappers. It should only be used if another listener wrapper must be placed in front of the TLS handshake. This _does not_ enable TLS for a server; e.g. if this is used on your `:80` HTTP server, it will still act as a no-op.
+###### `tls`
-The included [`http_redirect`](/docs/json/apps/http/servers/listener_wrappers/http_redirect/) listener wrapper can look at the first few bytes of an incoming request to determine if it's likely HTTP (instead of TLS), and trigger an HTTP-to-HTTPS redirect on the same port but using the `https://` scheme. This is most useful when serving HTTPS on a non-standard port (other than `443`), since browsers will try HTTP unless the scheme is specified. Don't use this on an HTTP server. It must be placed _before_ the `tls` listener wrapper. For example:
+The `tls` listener wrapper is a no-op listener wrapper that marks where the TLS listener should be in a chain of listener wrappers. It should only be used if another listener wrapper must be placed in front of the TLS handshake.
+
+###### `http_redirect`
+
+The [`http_redirect`](/docs/json/apps/http/servers/listener_wrappers/http_redirect/) provides HTTP->HTTPS redirects for connections that come on the TLS port as an HTTP request, by detecting using the first few bytes that it's not a TLS handshake, but instead an HTTP request. This is most useful when serving HTTPS on a non-standard port (other than `443`), since browsers will try HTTP unless the scheme is specified. It must be placed _before_ the `tls` listener wrapper. Here's an example:
```caddy
{
@@ -783,7 +855,34 @@ The included [`http_redirect`](/docs/json/apps/http/servers/listener_wrappers/ht
}
```
-Also included is the [`proxy_protocol`](/docs/json/apps/http/servers/listener_wrappers/proxy_protocol/) listener wrapper (prior to v2.7.0 it was only available via a plugin), which enables [PROXY protocol](https://github.com/haproxy/haproxy/blob/master/doc/proxy-protocol.txt) parsing (popularized by HAProxy). This must be used _before_ the `tls` listener wrapper since it parses plaintext data at the start of the connection:
+###### `proxy_protocol`
+
+The [`proxy_protocol`](/docs/json/apps/http/servers/listener_wrappers/proxy_protocol/) listener wrapper (prior to v2.7.0 it was only available via a plugin) enables [PROXY protocol](https://github.com/haproxy/haproxy/blob/master/doc/proxy-protocol.txt) parsing (popularized by HAProxy). This must be used _before_ the `tls` listener wrapper since it parses plaintext data at the start of the connection:
+
+```caddy-d
+proxy_protocol {
+ timeout
+ allow
+ deny
+ fallback_policy
+}
+```
+
+- **timeout** specifies the maximum duration to wait for the PROXY header. Defaults to `5s`.
+
+- **allow** is a list of CIDR ranges of trusted sources to receive PROXY headers. Unix sockets are trusted by default and not part of this option.
+
+- **deny** is a list of CIDR ranges of trusted sources to reject PROXY headers from.
+
+- **fallback_policy** is the action to take if the PROXY header comes from an address that not in either list of allow/deny. The default fallback policy is `ignore`. Accepted values of `fallback_policy` are:
+ - `ignore`: address from PROXY header, but accept connection
+ - `use`: address from PROXY header
+ - `reject`: connection when PROXY header is sent
+ - `require`: connection to send PROXY header, reject if not present
+ - `skip`: accepts a connection without requiring the PROXY header.
+
+
+For example, for an HTTPS server (needing the `tls` listener wrapper) that accepts PROXY headers from a specific range of IP addresses, and rejects PROXY headers from a different range, with a timeout of 2 seconds:
```caddy
{
@@ -792,6 +891,8 @@ Also included is the [`proxy_protocol`](/docs/json/apps/http/servers/listener_wr
proxy_protocol {
timeout 2s
allow 192.168.86.1/24 192.168.86.1/24
+ deny 10.0.0.0/8
+ fallback_policy reject
}
tls
}
@@ -911,10 +1012,34 @@ Pairing with [`trusted_proxies`](#trusted-proxies), allows configuring which hea
Enables Prometheus metrics collection; necessary before scraping metrics. Note that metrics reduce performance on really busy servers. (Our community is working on improving this. Please get involved!)
+```caddy
+{
+ metrics
+}
+```
+
+You can add the `per_host` option to label metrics with the host name of the metric.
+
+```caddy
+{
+ metrics {
+ per_host
+ }
+}
+```
+
+##### `trace`
+
+Log each individual handler that is invoked. Requires that the log emit at `DEBUG` level ( You may do so with the [`debug` global option](#debug)).
+
+NOTE: This may log the configuration of your HTTP handler modules; do not enable this in insecure contexts when there is sensitive data in the configuration.
+
+⚠️ This is an experimental feature. Subject to change or removal.
+
```caddy
{
servers {
- metrics
+ trace
}
}
```
@@ -956,7 +1081,7 @@ Test thoroughly with your HTTP clients, as some older clients may not support fu
##### `log_credentials`
-Since Caddy v2.5, by default, headers with potentially sensitive information (`Cookie`, `Set-Cookie`, `Authorization` and `Proxy-Authorization`) will be logged with empty values in access logs (see the [`log` directive](/docs/caddyfile/directives/log)).
+By default, access logs (enabled with the [`log` directive](/docs/caddyfile/directives/log)) with headers that contain potentially sensitive information (`Cookie`, `Set-Cookie`, `Authorization` and `Proxy-Authorization`) will be logged as `REDACTED`.
If you wish to _not_ have these headers redacted, you may enable the `log_credentials` option.
diff --git a/src/docs/markdown/caddyfile/patterns.md b/src/docs/markdown/caddyfile/patterns.md
index adcba9c..770dd12 100644
--- a/src/docs/markdown/caddyfile/patterns.md
+++ b/src/docs/markdown/caddyfile/patterns.md
@@ -66,7 +66,7 @@ With a PHP FastCGI service running, something like this works for most modern PH
```caddy
example.com {
root * /srv/public
- encode gzip
+ encode
php_fastcgi localhost:9000
file_server
}
@@ -217,7 +217,7 @@ A typical SPA config usually looks something like this:
```caddy
example.com {
root * /srv
- encode gzip
+ encode
try_files {path} /index.html
file_server
}
@@ -227,7 +227,7 @@ If your SPA is coupled with an API or other server-side-only endpoints, you will
```caddy
example.com {
- encode gzip
+ encode
handle /api/* {
reverse_proxy backend:8000
@@ -241,6 +241,15 @@ example.com {
}
```
+If your `index.html` contains references to your JS/CSS assets with hashed filenames, you may want to consider adding a `Cache-Control` header to instruct clients to _not_ cache it (so that if the assets change, browsers fetch the new ones). Since the `try_files` rewrite is used to serve your `index.html` from any path that doesn't match another file on disk, you can wrap the `try_files` with a `route` so that the `header` handler runs _after_ the rewrite (it normally would run before due to the [directive order](/docs/caddyfile/directives#directive-order)):
+
+```caddy-d
+route {
+ try_files {path} /index.html
+ header /index.html Cache-Control "public, max-age=0, must-revalidate"
+}
+```
+
## Caddy proxying to another Caddy
diff --git a/src/docs/markdown/caddyfile/response-matchers.md b/src/docs/markdown/caddyfile/response-matchers.md
new file mode 100644
index 0000000..be9e11f
--- /dev/null
+++ b/src/docs/markdown/caddyfile/response-matchers.md
@@ -0,0 +1,108 @@
+---
+title: Response matchers (Caddyfile)
+---
+
+
+
+# Response Matchers
+
+**Response matchers** can be used to filter (or classify) responses by specific criteria.
+
+These typically only appear as config inside of certain other directives, to make decisions on the response as it's being written out to the client.
+
+- [Syntax](#syntax)
+- [Matchers](#matchers)
+ - [status](#status)
+ - [header](#header)
+
+## Syntax
+
+```caddy-d
+@name {
+ status
+ header []
+}
+```
+
+
+
+## Matchers
+
+### status
+
+```caddy-d
+status
+```
+
+By HTTP status code.
+
+- **<code...>** is a list of HTTP status codes. Special cases are strings like `2xx` and `3xx`, which match against all status codes in the range of `200`-`299` and `300`-`399`, respectively.
+
+#### Example:
+
+```caddy-d
+@success status 2xx
+```
+
+
+
+### header
+
+```caddy-d
+header []
+```
+
+By response header fields.
+
+- `` is the name of the HTTP header field to check.
+ - If prefixed with `!`, the field must not exist to match (omit value arg).
+- `` is the value the field must have to match.
+ - If prefixed with `*`, it performs a fast suffix match (appears at the end).
+ - If suffixed with `*`, it performs a fast prefix match (appears at the start).
+ - If enclosed by `*`, it performs a fast substring match (appears anywhere).
+ - Otherwise, it is a fast exact match.
+
+Different header fields within the same set are AND-ed. Multiple values per field are OR'ed.
+
+Note that header fields may be repeated and have different values. Backend applications MUST consider that header field values are arrays, not singular values, and Caddy does not interpret meaning in such quandaries.
+
+#### Example:
+
+Match responses with the `Foo` header containing the value `bar`:
+
+```caddy-d
+@upgrade header Foo *bar*
+```
+
+Match responses with the `Foo` header having the value `bar` OR `baz`:
+
+```caddy-d
+@foo {
+ header Foo bar
+ header Foo baz
+}
+```
+
+Match responses that do not have the `Foo` header field at all:
+
+```caddy-d
+@not_foo header !Foo
+```
diff --git a/src/docs/markdown/command-line.md b/src/docs/markdown/command-line.md
index 90196d1..e61a1a3 100644
--- a/src/docs/markdown/command-line.md
+++ b/src/docs/markdown/command-line.md
@@ -38,7 +38,7 @@ The `--flags` may have a single-letter shortcut like `-f`.
A simple but production-ready file server
- **[caddy file-server export-template](#caddy-file-server-export-template)**
- Auxilary command for the file server to export the default file browser template
+ Auxiliary command for the file server to export the default file browser template
- **[caddy fmt](#caddy-fmt)**
Formats a Caddyfile
@@ -319,7 +319,7 @@ Because this command uses the API, the admin endpoint must not be disabled.
`--config` is the config file to apply. If `-`, the config is read from stdin. If not specified, it will try a file called `Caddyfile` in the current working directory and, if it exists, it will adapt it using the `caddyfile` config adapter; otherwise, it is an error if there is no config file to load.
-`--adapter` specifies a config adapter to use, if any.
+`--adapter` specifies a config adapter to use, if any. This flag is not necessary if the `--config` filename starts with `Caddyfile` or ends with `.caddyfile` which assumes the `caddyfile` adapter. Otherwise, this flag is required if the provided config file is not in Caddy's native JSON format.
`--address` needs to be used if the admin endpoint is not listening on the default address and if it is different from the address in the provided config file. Note that only TCP addresses are supported at this time.
@@ -455,7 +455,7 @@ Runs Caddy and blocks indefinitely; i.e. "daemon" mode.
`--config` specifies an initial config file to immediately load and use. If `-`, the config is read from stdin. If no config is specified, Caddy will run with a blank configuration and use default settings for the [admin API endpoints](/docs/api), which can be used to feed it new configuration. As a special case, if the current working directory has a file called "Caddyfile" and the `caddyfile` config adapter is plugged in (default), then that file will be loaded and used to configure Caddy, even without any command line flags.
-`--adapter` is the name of the config adapter to use when loading the initial config, if any. This flag is not necessary if the `--config` filename starts with "Caddyfile" which assumes the `caddyfile` adapter. Otherwise, this flag is required if the provided config file is not in Caddy's native JSON format. Any warnings will be printed to the log, but beware that any adaptation without errors will immediately be used, even if there are warnings. If you want to review the results of the adaptation first, use the [`caddy adapt`](#caddy-adapt) subcommand.
+`--adapter` is the name of the config adapter to use when loading the initial config, if any. This flag is not necessary if the `--config` filename starts with `Caddyfile` or ends with `.caddyfile` which assumes the `caddyfile` adapter. Otherwise, this flag is required if the provided config file is not in Caddy's native JSON format. Any warnings will be printed to the log, but beware that any adaptation without errors will immediately be used, even if there are warnings. If you want to review the results of the adaptation first, use the [`caddy adapt`](#caddy-adapt) subcommand.
`--pidfile` writes the PID to the specified file.
@@ -654,7 +654,7 @@ Validates a configuration file, then exits. This command deserializes the config
`--config` is the config file to validate. If `-`, the config is read from stdin. Default is the `Caddyfile` in the current directory, if any.
-`--adapter` is the name of the config adapter to use, if the config file is not in Caddy's native JSON format. If the config file starts with `Caddyfile`, the `caddyfile` adapter is used by default.
+`--adapter` is the name of the config adapter to use. This flag is not necessary if the `--config` filename starts with `Caddyfile` or ends with `.caddyfile` which assumes the `caddyfile` adapter. Otherwise, this flag is required if the provided config file is not in Caddy's native JSON format.
`--envfile` loads environment variables from the specified file, in `KEY=VALUE` format. Comments starting with `#` are supported; keys may be prefixed with `export`; values may be double-quoted (double-quotes within can be escaped); multi-line values are supported.
diff --git a/src/docs/markdown/conventions.md b/src/docs/markdown/conventions.md
index 2b4b932..9a62741 100644
--- a/src/docs/markdown/conventions.md
+++ b/src/docs/markdown/conventions.md
@@ -38,11 +38,14 @@ The address part may be any of these forms:
- `host`
- `host:port`
- `:port`
+- `[ipv6%zone]:port`
- `/path/to/unix/socket`
- `/path/to/unix/socket|0200`
The host may be any hostname, resolvable domain name, or IP address.
+In the case of IPv6 addresses, the address must be enclosed in square brackets `[]`. The zone identifier (starting with `%`) is optional (often used for link-local addresses).
+
The port may be a single value (`:8080`) or an inclusive range (`:8080-8085`). A port range will be multiplied into singular addresses. Not all config fields accept port ranges. The special port `:0` means any available port.
A unix socket path is only acceptable when using a `unix*` network type. The forward slash that separates the network and address is not considered part of the path.
@@ -59,6 +62,8 @@ localhost:8080-8085
tcp/localhost:8080
tcp/localhost:8080-8085
udp/localhost:9005
+[::1]:8080
+tcp6/[fe80::1%eth0]:8080
unix//path/to/socket
unix//path/to/socket|0200
```
@@ -74,24 +79,25 @@ Caddy network addresses are not URLs. URLs couple the lower and higher layers of
## Placeholders
-Caddy's configuration supports the use of _placeholders_ (variables). Using placeholders is a simple way to inject dynamic values into a static configuration.
+Caddy's configuration supports the use of _placeholders_. Using placeholders is a simple way to inject dynamic values into a static configuration.
-Placeholders are bounded on either side by curly braces `{ }` and contain the variable name inside, for example: `{foo.bar}`. Placeholder braces can be escaped, `\{like so\}`. Variable names are typically namespaced with dots to avoid collisions across modules.
+Placeholders are bounded on either side by curly braces `{ }` and contain the identifier inside, for example: `{foo.bar}`. The opening placeholder brace can be escaped `\{like.this}` to prevent replacement. Placeholder identifiers are typically namespaced with dots to avoid collisions across modules.
Which placeholders are available depends on the context. Not all placeholders are available in all parts of the config. For example, [the HTTP app sets placeholders](/docs/json/apps/http/#docs) that are only available in areas of the config related to handling HTTP requests.
-The following placeholders are always available:
+The following placeholders are always available (global):
Placeholder | Description
------------|-------------
-`{env.*}` | Environment variable (example: `{env.HOME}`)
+`{env.*}` | Environment variable; example: `{env.HOME}`
+`{file.*}` | Contents from a file; example: `{file./path/to/secret.txt}`
`{system.hostname}` | The system's local hostname
`{system.slash}` | The system's filepath separator
`{system.os}` | The system's OS
@@ -104,7 +110,7 @@ Placeholder | Description
`{time.now.common_log}` | The current time in Common Log Format
`{time.now.year}` | The current year in YYYY format
-Not all config fields support placeholders, but most do where you would expect it.
+Not all config fields support placeholders, but most do where you would expect it. Support for placeholders needs to have been explicitly added to those fields. Plugin authors can [read this article](/docs/extending-caddy/placeholders) to learn how to add support for placeholders in their own modules.
diff --git a/src/docs/markdown/extending-caddy.md b/src/docs/markdown/extending-caddy.md
index 54b849c..13c2d77 100644
--- a/src/docs/markdown/extending-caddy.md
+++ b/src/docs/markdown/extending-caddy.md
@@ -15,7 +15,7 @@ Caddy is easy to extend because of its modular architecture. Most kinds of Caddy
## Quick Start
-A Caddy module is any named type that registers itself as a Caddy module when its package is imported. Crucially, a module always implements the [caddy.Module](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#Module) interface, which provides its name and a constructor function.
+A Caddy module is any named type that registers itself as a Caddy module when its package is imported. Crucially, a module always implements the [`caddy.Module`](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#Module) interface, which provides its name and a constructor function.
In a new Go module, paste the following template into a Go file and customize your package name, type name, and Caddy module ID:
@@ -108,7 +108,7 @@ The name within a namespace is significant and highly visible to users, but is n
## App Modules
-Apps are modules with an empty namespace, and which conventionally become their own top-level namespace. App modules implement the [caddy.App](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#App) interface.
+Apps are modules with an empty namespace, and which conventionally become their own top-level namespace. App modules implement the [`caddy.App`](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#App) interface.
These modules appear in the [`"apps"`](/docs/json/#apps) property of the top-level of Caddy's config:
@@ -138,7 +138,7 @@ type Gizmo struct {
}
```
-Using struct tags in this way will ensure that config properties are consisently named across all of Caddy.
+Using the `omitempty` option in the struct tag will omit the field from the JSON output if it is the zero value for its type. This is useful to keep the JSON config clean and concise when marshaled (e.g. adapting from Caddyfile to JSON).
When a module is initialized, it will already have its configuration filled out. It is also possible to perform additional [provisioning](#provisioning) and [validation](#validating) steps after a module is initialized.
@@ -149,18 +149,18 @@ A module's life begins when it is loaded by a host module. The following happens
1. [`New()`](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#ModuleInfo.New) is called to get an instance of the module's value.
2. The module's configuration is unmarshaled into that instance.
-3. If the module is a [caddy.Provisioner](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#Provisioner), the `Provision()` method is called.
-4. If the module is a [caddy.Validator](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#Validator), the `Validate()` method is called.
+3. If the module is a [`caddy.Provisioner`](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#Provisioner), the `Provision()` method is called.
+4. If the module is a [`caddy.Validator`](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#Validator), the `Validate()` method is called.
5. At this point, the host module is given the loaded guest module as an `interface{}` value, so the host module will usually type-assert the guest module into a more useful type. Check the documentation for the host module to know what is required of a guest module in its namespace, e.g. what methods need to be implemented.
-6. When a module is no longer needed, and if it is a [caddy.CleanerUpper](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#CleanerUpper), the `Cleanup()` method is called.
+6. When a module is no longer needed, and if it is a [`caddy.CleanerUpper`](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#CleanerUpper), the `Cleanup()` method is called.
-Note that multiple loaded instances of your module may overlap at a given time! During config changes, new modules are started before the old ones are stopped. Be sure to use global state carefully. Use the [caddy.UsagePool](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#UsagePool) type to help manage global state across module loads. If your module listens on a socket, use `caddy.Listen*()` to get a socket that supports overlapping usage.
+Note that multiple loaded instances of your module may overlap at a given time! During config changes, new modules are started before the old ones are stopped. Be sure to use global state carefully. Use the [`caddy.UsagePool`](https://pkg.go.dev/github.com/caddyserver/caddy/v2#UsagePool) type to help manage global state across module loads. If your module listens on a socket, use `caddy.Listen*()` to get a socket that supports overlapping usage.
### Provisioning
-A module's configuration will be unmarshaled into its value automatically. This means, for example, that struct fields will be filled out for you.
+A module's configuration will be unmarshaled into its value automatically (when loading the JSON config). This means, for example, that struct fields will be filled out for you.
-However, if your module requires additional provisioning steps, you can implement the (optional) [caddy.Provisioner](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#Provisioner) interface:
+However, if your module requires additional provisioning steps, you can implement the (optional) [`caddy.Provisioner`](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#Provisioner) interface:
```go
// Provision sets up the module.
@@ -170,7 +170,9 @@ func (g *Gizmo) Provision(ctx caddy.Context) error {
}
```
-This is typically where host modules will load their guest/child modules, but it can be used for pretty much anything. Module provisioning is done in an arbitrary order.
+This is where you should set default values for fields that were not provided by the user (fields that are not their zero value). If a field is required, you may return an error if it is not set. For numeric fields where the zero value has meaning (e.g. some timeout duration), you may want to support `-1` to mean "off" rather than `0`, so you may set a default value if the user did not configure it.
+
+This is also typically where host modules will load their guest/child modules.
A module may access other apps by calling `ctx.App()`, but modules must not have circular dependencies. In other words, a module loaded by the `http` app cannot depend on the `tls` app if a module loaded by the `tls` app depends on the `http` app. (Very similar to rules forbidding import cycles in Go.)
diff --git a/src/docs/markdown/extending-caddy/caddyfile.md b/src/docs/markdown/extending-caddy/caddyfile.md
index 1e84606..68d204e 100644
--- a/src/docs/markdown/extending-caddy/caddyfile.md
+++ b/src/docs/markdown/extending-caddy/caddyfile.md
@@ -15,7 +15,7 @@ An unmarshaler's job is simply to set up your module's type, e.g. by populating
```go
// UnmarshalCaddyfile implements caddyfile.Unmarshaler. Syntax:
//
-// gizmo [