Big Caddyfile docs update

This commit is contained in:
Francis Lavoie 2024-02-15 19:03:58 -05:00
parent 3ec3033602
commit 1f6c20639b
No known key found for this signature in database
GPG key ID: 0F66EE1687682239
34 changed files with 1732 additions and 512 deletions

View file

@ -75,8 +75,8 @@ Because HTTPS utilizes a shared, public infrastructure, you as the server admin
Caddy implicitly activates automatic HTTPS when it knows a domain name (i.e. hostname) or IP address it is serving. There are various ways to tell Caddy your domain/IP, depending on how you run or configure Caddy: Caddy implicitly activates automatic HTTPS when it knows a domain name (i.e. hostname) or IP address it is serving. There are various ways to tell Caddy your domain/IP, depending on how you run or configure Caddy:
- A [site address](/docs/caddyfile/concepts#addresses) in the [Caddyfile](/docs/caddyfile) - A [site address](/docs/caddyfile/concepts#addresses) in the [Caddyfile](/docs/caddyfile)
- A [host matcher](/docs/json/apps/http/servers/routes/match/host/) in a [JSON route](/docs/modules/http#servers/routes) - A [host matcher](/docs/json/apps/http/servers/routes/match/host/) at the top-level in the [JSON routes](/docs/modules/http#servers/routes)
- Command line flags like [--domain](/docs/command-line#caddy-file-server) or [--from](/docs/command-line#caddy-reverse-proxy) - Command line flags like [`--domain`](/docs/command-line#caddy-file-server) or [`--from`](/docs/command-line#caddy-reverse-proxy)
- The [automate](/docs/json/apps/tls/certificates/automate/) certificate loader - The [automate](/docs/json/apps/tls/certificates/automate/) certificate loader
Any of the following will prevent automatic HTTPS from being activated, either in whole or in part: Any of the following will prevent automatic HTTPS from being activated, either in whole or in part:
@ -96,11 +96,12 @@ Any of the following will prevent automatic HTTPS from being activated, either i
When automatic HTTPS is activated, the following occurs: When automatic HTTPS is activated, the following occurs:
- Certificates are obtained and renewed for [all domain names](#hostname-requirements) - Certificates are obtained and renewed for [all qualifying domain names](#hostname-requirements)
- The default port (if any) is changed to the [HTTPS port](/docs/modules/http#https_port) `443`
- HTTP is redirected to HTTPS (this uses [HTTP port](/docs/modules/http#http_port) `80`) - HTTP is redirected to HTTPS (this uses [HTTP port](/docs/modules/http#http_port) `80`)
Automatic HTTPS never overrides explicit configuration. Automatic HTTPS never overrides explicit configuration, it only augments it.
If you already have a [server](/docs/json/apps/http/servers/) listening on the HTTP port, the HTTP->HTTPS redirect routes will be inserted after your routes with a host matcher, but before a user-defined catch-all route.
You can [customize or disable automatic HTTPS](/docs/json/apps/http/servers/automatic_https/) if necessary; for example, you can skip certain domain names or disable redirects (for Caddyfile, do this with [global options](/docs/caddyfile/options)). You can [customize or disable automatic HTTPS](/docs/json/apps/http/servers/automatic_https/) if necessary; for example, you can skip certain domain names or disable redirects (for Caddyfile, do this with [global options](/docs/caddyfile/options)).

View file

@ -30,13 +30,18 @@ The Caddyfile's structure can be described visually:
Key points: Key points:
- An optional [**global options block**](#global-options) can be the very first thing in the file. - An optional [**global options block**](#global-options) can be the very first thing in the file.
- [Snippets](#snippets) or [named routes](#named-routes) may optionally appear next. - [Snippets](#snippets) or [named routes](#named-routes) may optionally appear next.
- Otherwise, the first line of the Caddyfile is **always** the [address(es)](#addresses) of the site to serve. - Otherwise, the first line of the Caddyfile is **always** the [address(es)](#addresses) of the site to serve.
- All [directives](#directives) and [matchers](#matchers) **must** go in a site block. There is no global scope or inheritance across site blocks. - All [directives](#directives) and [matchers](#matchers) **must** go in a site block. There is no global scope or inheritance across site blocks.
- If there is only one site block, its curly braces `{ }` are optional. - If there is only one site block, its curly braces `{ }` are optional.
A Caddyfile consists of at least one or more site blocks, which always starts with one or more [addresses](#addresses) for the site. Any directives appearing before the address will be confusing to the parser. A Caddyfile consists of at least one or more site blocks, which always starts with one or more [addresses](#addresses) for the site. Any directives appearing before the address will be confusing to the parser.
### Blocks ### Blocks
Opening and closing a **block** is done with curly braces: Opening and closing a **block** is done with curly braces:
@ -48,6 +53,7 @@ Opening and closing a **block** is done with curly braces:
``` ```
- The open curly brace `{` must be at the end of its line and preceded by a space. - The open curly brace `{` must be at the end of its line and preceded by a space.
- The close curly brace `}` must be on its own line. - The close curly brace `}` must be on its own line.
When there is only one site block, the curly braces (and indentation) are optional. This is for convenience to quickly define a single site, for example, this: When there is only one site block, the curly braces (and indentation) are optional. This is for convenience to quickly define a single site, for example, this:
@ -120,7 +126,7 @@ localhost {
Here, `lb_policy` is a subdirective to [`reverse_proxy`](/docs/caddyfile/directives/reverse_proxy) (it sets the load balancing policy to use between backends). Here, `lb_policy` is a subdirective to [`reverse_proxy`](/docs/caddyfile/directives/reverse_proxy) (it sets the load balancing policy to use between backends).
**Unless otherwise documented, directives cannot be used within other directive blocks.** For example, `basicauth` cannot be used within `file_server` because the file server does not know how to do authentication; but you can use directives within [`route`](/docs/caddyfile/directives/route), [`handle`](/docs/caddyfile/directives/handle), and [`handle_path`](/docs/caddyfile/directives/handle_path) blocks because they are specifically designed to group directives together. **Unless otherwise documented, directives cannot be used within other directive blocks.** For example, [`basicauth`](/docs/caddyfile/directives/basicauth) cannot be used within [`file_server`](/docs/caddyfile/directives/file_server) because the file server does not know how to do authentication; but you can use directives within [`route`](/docs/caddyfile/directives/route), [`handle`](/docs/caddyfile/directives/handle), and [`handle_path`](/docs/caddyfile/directives/handle_path) blocks because they are specifically designed to group directives together.
Note that when the HTTP Caddyfile is adapted, HTTP handler directives are sorted according to a specific default [directive order](/docs/caddyfile/directives#directive-order) unless in a [`route`](/docs/caddyfile/directives/route) block, so the order of appearance of the directives does not matter except in `route` blocks. Note that when the HTTP Caddyfile is adapted, HTTP handler directives are sorted according to a specific default [directive order](/docs/caddyfile/directives#directive-order) unless in a [`route`](/docs/caddyfile/directives/route) block, so the order of appearance of the directives does not matter except in `route` blocks.
@ -202,7 +208,15 @@ If present, it must be the very first block in the config.
It is used to set options that apply globally, or not to any one site in particular. Inside, only global options can be set; you cannot use regular site directives in them. It is used to set options that apply globally, or not to any one site in particular. Inside, only global options can be set; you cannot use regular site directives in them.
[Learn more](/docs/caddyfile/options) about the global options block. For example, to enable the `debug` global option, which is commonly used to produce verbose logs for troubleshooting:
```caddy
{
debug
}
```
**[Read the Global Options page](/docs/caddyfile/options) to learn more.**
@ -212,20 +226,28 @@ An address always appears at the top of the site block, and is usually the first
These are examples of valid addresses: These are examples of valid addresses:
- `localhost` | Address | Effect |
- `example.com` |----------------------|-----------------------------------|
- `:443` | `example.com` | HTTPS with managed [publicly-trusted certificate](/docs/automatic-https#hostname-requirements) |
- `http://example.com` | `*.example.com` | HTTPS with managed [wildcard publicly-trusted certificate](/docs/caddyfile/patterns#wildcard-certificates) |
- `localhost:8080` | `localhost` | HTTPS with managed [locally-trusted certificate](/docs/automatic-https#local-https) |
- `127.0.0.1` | `http://` | HTTP catch-all, affected by [`http_port`](/docs/caddyfile/options#http-port) |
- `[::1]:2015` | `https://` | HTTPS catch-all, affected by [`https_port`](/docs/caddyfile/options#http-port) |
- `*.example.com` | `http://example.com` | HTTP explicitly, with a `Host` matcher |
- `http://` | `example.com:443` | HTTPS due to matching the [`https_port`](/docs/caddyfile/options#http-port) default |
| `:443` | HTTPS catch-all due to matching the [`https_port`](/docs/caddyfile/options#http-port) default |
| `:8080` | HTTP on non-standard port, no `Host` matcher |
| `localhost:8080` | HTTPS on non-standard port, due to having a valid domain |
| `https://example.com:443` | HTTPS, but both `https://` and `:443` are redundant |
| `127.0.0.1` | HTTPS, with a locally-trusted IP certificate |
| `http://127.0.0.1` | HTTP, with an IP address `Host` matcher (rejects `localhost`) |
<aside class="tip"> <aside class="tip">
[Automatic HTTPS](/docs/automatic-https) is enabled if your site's address contains a hostname or IP address. This behavior is purely implicit, however, so it never overrides any explicit configuration. For example, if the site's address is `http://example.com`, auto-HTTPS will not activate because the scheme is explicitly `http://`. [Automatic HTTPS](/docs/automatic-https) is enabled if your site's address contains a hostname or IP address. This behavior is purely implicit, however, so it never overrides any explicit configuration.
For example, if the site's address is `http://example.com`, auto-HTTPS will not activate because the scheme is explicitly `http://`.
</aside> </aside>
@ -238,21 +260,44 @@ Wildcards (`*`) may be used, but only to represent precisely one label of the ho
To catch all hosts, omit the host portion of the address, for example, simply `https://`. This is useful when using [On-Demand TLS](/docs/automatic-https#on-demand-tls), when you don't know the domains ahead of time. To catch all hosts, omit the host portion of the address, for example, simply `https://`. This is useful when using [On-Demand TLS](/docs/automatic-https#on-demand-tls), when you don't know the domains ahead of time.
If multiple sites share the same definition, you can list all of them together; notice how the commas indicate the continuation of addresses: If multiple sites share the same definition, you can list all of them together, either with spaces or commas. The following three examples are equivalent:
```caddy ```caddy
localhost:8080, example.com, www.example.com # Comma separated site addresses
localhost:8080, example.com, www.example.com {
...
}
``` ```
or or
```caddy ```caddy
localhost:8080, # Space separated site addresses
example.com, localhost:8080 example.com www.example.com {
www.example.com ...
}
``` ```
An address must be unique; you cannot specify the same address more than once. [Placeholders](#placeholders) **cannot** be used in addresses, but you may use Caddyfile-style [environment variables](#environment-variables) in them. or
```caddy
# Comma and new-line separated site addresses
localhost:8080,
example.com,
www.example.com {
...
}
```
An address must be unique; you cannot specify the same address more than once.
[Placeholders](#placeholders) **cannot** be used in addresses, but you may use Caddyfile-style [environment variables](#environment-variables) in them:
```caddy
{$DOMAIN:localhost} {
...
}
```
By default, sites bind on all network interfaces. If you wish to override this, use the [`bind` directive](/docs/caddyfile/directives/bind) or the [`default_bind` global option](/docs/caddyfile/options#default-bind) to do so. By default, sites bind on all network interfaces. If you wish to override this, use the [`bind` directive](/docs/caddyfile/directives/bind) or the [`default_bind` global option](/docs/caddyfile/options#default-bind) to do so.
@ -260,7 +305,7 @@ By default, sites bind on all network interfaces. If you wish to override this,
## Matchers ## Matchers
HTTP handler directives apply to all requests by default (unless otherwise documented). HTTP handler [directives](#directives) apply to all requests by default (unless otherwise documented).
[Request matchers](/docs/caddyfile/matchers) can be used to classify requests by a given criteria. With matchers, you can specify exactly which requests a certain directive applies to. [Request matchers](/docs/caddyfile/matchers) can be used to classify requests by a given criteria. With matchers, you can specify exactly which requests a certain directive applies to.
@ -274,7 +319,7 @@ root @post /var/www # matcher token: @post
Matcher tokens can be omitted entirely to match all requests; for example, `*` does not need to be given if the next argument does not look like a path matcher. Matcher tokens can be omitted entirely to match all requests; for example, `*` does not need to be given if the next argument does not look like a path matcher.
**[Read the page about request matchers](/docs/caddyfile/matchers) to learn more.** **[Read the Request Matchers page](/docs/caddyfile/matchers) to learn more.**
@ -328,27 +373,41 @@ You can use any [Caddy placeholders](/docs/conventions#placeholders) in the Cadd
You can define special blocks called snippets by giving them a name surrounded in parentheses: You can define special blocks called snippets by giving them a name surrounded in parentheses:
```caddy ```caddy
(redirect) { (logging) {
@http { log {
protocol http output file /var/log/caddy.log
format json
} }
redir @http https://{host}{uri}
} }
``` ```
And then you can reuse this anywhere you need: And then you can reuse this anywhere you need, using the special [`import`](/docs/caddyfile/directives/import) directive:
```caddy-d ```caddy
import redirect example.com {
import logging
}
www.example.com {
import logging
}
``` ```
The [`import`](/docs/caddyfile/directives/import) directive can also be used to include other files in its place. As a special case, it can appear almost anywhere within the Caddyfile. The [`import`](/docs/caddyfile/directives/import) directive can also be used to include other files in its place. If the argument does not match a defined snippet, it will be tried as a file. It also supports globs to import multiple files. As a special case, it can appear anywhere within the Caddyfile (except as an argument to another directive), including outside of site blocks:
You can pass arguments to imported configuration and use them like so: ```caddy
{
email admin@example.com
}
import sites/*
```
You can pass arguments to an imported configuration (snippets or files) and use them like so:
```caddy ```caddy
(snippet) { (snippet) {
respond "Yahaha! You found {args[0]}!" respond "Yahaha! You found {args[0]}!"
} }
a.example.com { a.example.com {
@ -360,10 +419,12 @@ b.example.com {
} }
``` ```
**[Read the `import` directive page](/docs/caddyfile/directives/import) to learn more.**
## Named Routes ## Named Routes
<i>⚠️ Experimental</i> ⚠️ <i>Experimental</i>
Named routes use syntax similar to [snippets](#snippets); they're a special block defined outside of site blocks, prefixed with `&(` and ending in `)` with the name in between. Named routes use syntax similar to [snippets](#snippets); they're a special block defined outside of site blocks, prefixed with `&(` and ending in `)` with the name in between.
@ -375,13 +436,20 @@ Named routes use syntax similar to [snippets](#snippets); they're a special bloc
And then you can reuse this named route within any site: And then you can reuse this named route within any site:
```caddy-d ```caddy
invoke app-proxy example.com {
invoke app-proxy
}
www.example.com {
invoke app-proxy
}
``` ```
This is particularly useful to reduce memory usage if the same route is needed in many different sites, or if multiple different matcher conditions are needed to invoke the same route. This is particularly useful to reduce memory usage if the same route is needed in many different sites, or if multiple different matcher conditions are needed to invoke the same route.
See the [`invoke` directive](/docs/caddyfile/directives/invoke) documentation for more details. **[Read the `invoke` directive page](/docs/caddyfile/directives/invoke) to learn more.**
## Comments ## Comments
@ -402,16 +470,35 @@ The hash character `#` for a comment cannot appear in the middle of a token (i.e
If your configuration relies on environment variables, you can use them in the Caddyfile: If your configuration relies on environment variables, you can use them in the Caddyfile:
```caddy ```caddy
{$SITE_ADDRESS} {$ENV}
``` ```
Environment variables in this form are substituted before Caddyfile parsing begins, so they can expand to empty values, partial tokens, complete tokens, or even multiple tokens and lines. Environment variables in this form are substituted **before Caddyfile parsing begins**, so they can expand to empty values (i.e. `""`), partial tokens, complete tokens, or even multiple tokens and lines.
For example, a environement variable `UPSTREAMS="app1:8080 app2:8080 app3:8080"` would expand to multiple [tokens](#tokens-and-quotes):
```caddy
example.com {
reverse_proxy {$UPSTREAMS}
}
```
A default value can be specified for when the environment variable is not found, by using `:` as the delimiter between the variable name and the default value: A default value can be specified for when the environment variable is not found, by using `:` as the delimiter between the variable name and the default value:
```caddy ```caddy
{$DOMAIN:localhost} {$DOMAIN:localhost} {
}
``` ```
If you want to defer the substitution of an environment variable until runtime, you can use the [standard `{env.*}` placeholders](/docs/conventions#placeholders). Note that not all config parameters support these placeholders though, since module developers need to add a line of code to perform the replacement. If it doesn't seem to work, please file an issue to request support for it. If you want to **defer the substitution** of an environment variable until runtime, you can use the [standard `{env.*}` placeholders](/docs/conventions#placeholders). Note that not all config parameters support these placeholders though, since module developers need to add a line of code to perform the replacement. If it doesn't seem to work, please file an issue to request support for it.
For example, if you have the [`caddy-dns/cloudflare` plugin <img src="/old/resources/images/external-link.svg" class="external-link">](https://github.com/caddy-dns/cloudflare) installed and wish to configure the [DNS challenge](/docs/automatic-https#dns-challenge), you can pass your `CLOUDFLARE_API_TOKEN` environment variable to the plugin like this:
```caddy
{
acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
```
If you're running Caddy as a systemd service, see [these instructions](/docs/running#overrides) for setting service overrides to define your environment variables.

View file

@ -29,3 +29,42 @@ acme_server [<matcher>] {
- **lifetime** (Default: `12h`) is a [duration](/docs/conventions#durations) which specifies the validity period for issued certificates. This value must be less than the lifetime of the [intermediate certificate](/docs/caddyfile/options#intermediate-lifetime) used for signing. It is not recommended to change this unless absolutely necessary. - **lifetime** (Default: `12h`) is a [duration](/docs/conventions#durations) which specifies the validity period for issued certificates. This value must be less than the lifetime of the [intermediate certificate](/docs/caddyfile/options#intermediate-lifetime) used for signing. It is not recommended to change this unless absolutely necessary.
- **resolvers** are the addresses of DNS resolvers to use when looking up the TXT records for solving ACME DNS challenges. Accepts [network addresses](/docs/conventions#network-addresses) defaulting to UDP and port 53 unless specified. If the host is an IP address, it will be dialed directly to resolve the upstream server. If the hot is not an IP address, the addresses are resolved using the [name resolution convention](https://golang.org/pkg/net/#hdr-Name_Resolution) of the Go standard library. If multiple resolvers are specified, then one is chosen at random. - **resolvers** are the addresses of DNS resolvers to use when looking up the TXT records for solving ACME DNS challenges. Accepts [network addresses](/docs/conventions#network-addresses) defaulting to UDP and port 53 unless specified. If the host is an IP address, it will be dialed directly to resolve the upstream server. If the hot is not an IP address, the addresses are resolved using the [name resolution convention](https://golang.org/pkg/net/#hdr-Name_Resolution) of the Go standard library. If multiple resolvers are specified, then one is chosen at random.
## Examples
To serve an ACME server with ID `home` on the domain `acme.example.com`, with the CA customized via the [`pki` global option](/docs/caddyfile/options#pki-options), and issuing its own certificate using the `internal` issuer:
```caddy
{
pki {
ca home {
name "My Home CA"
}
}
}
acme.example.com {
tls {
issuer internal {
ca home
}
}
acme_server {
ca home
}
}
```
If you have another Caddy server, it can use the above ACME server to issue its own certificates:
```caddy
{
acme_ca https://acme.example.com/acme/home/directory
acme_ca_root /path/to/home_ca_root.crt
}
example.com {
respond "Hello, world!"
}
```

View file

@ -37,11 +37,30 @@ basicauth [<matcher>] [<hash_algorithm> [<realm>]] {
## Examples ## Examples
Protect all resources in /secret so only Bob can access them with the password "hiccup": Require authentication for all requests to `example.com`:
```caddy-d ```caddy
basicauth /secret/* { example.com {
Bob $2a$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNmpkT/5qqR7hx4IjWJPDhjvG basicauth {
# Username "Bob", password "hiccup"
Bob $2a$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNmpkT/5qqR7hx4IjWJPDhjvG
}
respond "Welcome, {http.auth.user.id}" 200
}
```
Protect files in `/secret/` so only `Bob` can access them (and anyone can see other paths):
```caddy
example.com {
root * /srv
basicauth /secret/* {
# Username "Bob", password "hiccup"
Bob $2a$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNmpkT/5qqR7hx4IjWJPDhjvG
}
file_server
} }
``` ```

View file

@ -4,7 +4,9 @@ title: bind (Caddyfile directive)
# bind # bind
Overrides the interface to which the server's socket should bind. Normally, the listener binds to the empty (wildcard) interface. However, you may force the listener to bind to another hostname or IP instead. (This directive accepts only a host, not a port.) Overrides the interface to which the server's socket should bind.
Normally, the listener binds to the empty (wildcard) interface. However, you may force the listener to bind to another hostname or IP instead. This directive accepts only a host, not a port. The port is determined by the [site address](/docs/caddyfile/concepts#addresses) (defaulting to `443`).
Note that binding sites inconsistently may result in unintended consequences. For example, if two sites on the same port resolve to `127.0.0.1` and only one of those sites is configured with `bind 127.0.0.1`, then only one site will be accessible since the other will bind to the port without a specific host; the OS will choose the more specific matching socket. (Virtual hosts are not shared across different listeners.) Note that binding sites inconsistently may result in unintended consequences. For example, if two sites on the same port resolve to `127.0.0.1` and only one of those sites is configured with `bind 127.0.0.1`, then only one site will be accessible since the other will bind to the port without a specific host; the OS will choose the more specific matching socket. (Virtual hosts are not shared across different listeners.)
@ -24,18 +26,54 @@ bind <hosts...>
To make a socket accessible only on the current machine, bind to the loopback interface (localhost): To make a socket accessible only on the current machine, bind to the loopback interface (localhost):
```caddy-d ```caddy
bind 127.0.0.1 example.com {
bind 127.0.0.1
}
``` ```
To include IPv6: To include IPv6:
```caddy-d ```caddy
bind 127.0.0.1 [::1] example.com {
bind 127.0.0.1 [::1]
}
```
To bind to `10.0.0.1:8080`:
```caddy
example.com:8080 {
bind 10.0.0.1
}
``` ```
To bind to a Unix domain socket at `/run/caddy`: To bind to a Unix domain socket at `/run/caddy`:
```caddy-d ```caddy
bind unix//run/caddy example.com {
bind unix//run/caddy
}
```
To change the file permission to be writable by all users ([defaults](/docs/conventions#network-addresses) to `0200`, which is only writable by the owner):
```caddy
example.com {
bind unix//run/caddy|0222
}
```
To bind one domain to two different interfaces, with different responses:
```caddy
example.com {
bind 10.0.0.1
respond "One"
}
example.com {
bind 10.0.0.2
respond "Two"
}
``` ```

View file

@ -55,10 +55,12 @@ encode [<matcher>] <formats...> {
} }
``` ```
## Response matcher ## Response matcher
**Response matchers** can be used to filter (or classify) responses by specific criteria. **Response matchers** can be used to filter (or classify) responses by specific criteria.
### status ### status
```caddy-d ```caddy-d
@ -69,10 +71,12 @@ By HTTP status code.
- **&lt;code...&gt;** is a list of HTTP status codes. Special cases are `2xx`, `3xx`, ... which match against all status codes in the range of 200-299, 300-399, ... respectively - **&lt;code...&gt;** is a list of HTTP status codes. Special cases are `2xx`, `3xx`, ... which match against all status codes in the range of 200-299, 300-399, ... respectively
### header ### header
See the [header](/docs/caddyfile/matchers#header) request matcher for the supported syntax. See the [header](/docs/caddyfile/matchers#header) request matcher for the supported syntax.
## Examples ## Examples
Enable Gzip compression: Enable Gzip compression:
@ -86,3 +90,13 @@ Enable Zstandard and Gzip compression (with Zstandard implicitly preferred, sinc
```caddy-d ```caddy-d
encode zstd gzip encode zstd gzip
``` ```
And in a full site, compressing static files served by [`file_server`](file_server):
```caddy
example.com {
root * /srv
encode zstd gzip
file_server
}
```

View file

@ -23,6 +23,7 @@ error [<matcher>] <status>|<message> [<status>] {
To clarify, the first non-matcher argument can be either a 3-digit status code, or an error message string. If it is an error message, the next argument can be the status code. To clarify, the first non-matcher argument can be either a 3-digit status code, or an error message string. If it is an error message, the next argument can be the status code.
## Examples ## Examples
Trigger an error on certain request paths, and use [`handle_errors`](handle_errors) to write a response: Trigger an error on certain request paths, and use [`handle_errors`](handle_errors) to write a response:

View file

@ -85,9 +85,11 @@ file_server /static/*
The `file_server` directive is usually paired with the [`root` directive](root) to set the root path from which to serve files: The `file_server` directive is usually paired with the [`root` directive](root) to set the root path from which to serve files:
```caddy-d ```caddy
root * /home/user/public_html example.com {
file_server root * /srv
file_server
}
``` ```
<aside class="tip"> <aside class="tip">

View file

@ -2,6 +2,29 @@
title: forward_auth (Caddyfile directive) title: forward_auth (Caddyfile directive)
--- ---
<script>
window.$(function() {
// Fix > in code blocks
window.$('pre.chroma .k:contains(">")')
.each(function() {
const e = window.$(this);
// Skip if ends with >
if (e.text().trim().endsWith('>')) return;
// Replace > with <span class="p">&gt;</span>
e.html(e.html().replace(/&gt;/g, '<span class="p">&gt;</span>'));
});
// Fix uri subdirective, gets parsed as matcher arg because of "uri" directive
window.$('.k:contains("uri") + .nd')
.each(function() {
window.$(this)
.removeClass('nd')
.addClass('s')
.text(window.$(this).text());
});
});
</script>
# forward_auth # forward_auth
An opinionated directive which proxies a clone of the request to an authentication gateway, which can decide whether handling should continue, or needs to be sent to a login page. An opinionated directive which proxies a clone of the request to an authentication gateway, which can decide whether handling should continue, or needs to be sent to a login page.

View file

@ -6,7 +6,11 @@ title: handle (Caddyfile directive)
Evaluates a group of directives mutually exclusively from other `handle` blocks at the same level of nesting. Evaluates a group of directives mutually exclusively from other `handle` blocks at the same level of nesting.
The `handle` directive is kind of similar to the `location` directive from nginx config: the first matching `handle` block will be evaluated. `handle` directives at the same level of nesting will be tried in the order they're written in the `Caddyfile`, except if there is a single path matcher, which orders them by longest (most specific) path pattern first. Handle blocks can be nested if needed. Only HTTP handler directives can be used inside handle blocks. In other words, when multiple `handle` directives appear in sequence, only the first _matching_ `handle` block will be evaluated. A handle with no matcher acts like a _fallback_ route.
The `handle` directives are sorted according to the [directive sorting algorithm](/docs/caddyfile/directives#sorting-algorithm) by their matchers. The [`handle_path`](handle_path) directive is a special case which sorts at the same priority as a `handle` with a path matcher.
Handle blocks can be nested if needed. Only HTTP handler directives can be used inside handle blocks.
## Syntax ## Syntax
@ -19,39 +23,67 @@ handle [<matcher>] {
- **<directives...>** is a list of HTTP handler directives or directive blocks, one per line, just like would be used outside of a handle block. - **<directives...>** is a list of HTTP handler directives or directive blocks, one per line, just like would be used outside of a handle block.
## Utility
If you prefer crafting HTTP handler logic in a more inheritance-based way like nginx location blocks, you may prefer the use of `handle` blocks rather than defining mutually-exclusive matchers for your directives. If inheritance is a desired characteristic of your HTTP handler configurations, then the `handle` directive may suit you well.
## Similar directives ## Similar directives
There are other directives that can wrap HTTP handler directives, but each has its use depending on the behavior you want to convey: There are other directives that can wrap HTTP handler directives, but each has its use depending on the behavior you want to convey:
- [`handle_path`](handle_path) does the same as `handle`, but it strips a prefix from the request before running its handlers. - [`handle_path`](handle_path) does the same as `handle`, but it strips a prefix from the request before running its handlers.
- [`handle_errors`](handle_errors) is like `handle`, but is only invoked when Caddy encounters an error during request handling. - [`handle_errors`](handle_errors) is like `handle`, but is only invoked when Caddy encounters an error during request handling.
- [`route`](route) wraps other directives like `handle` does, but with two distinctions: 1) route blocks are not mutually exclusive to each other, and 2) directives within a route are not [re-ordered](/docs/caddyfile/directives#directive-order), giving you more control if needed.
- [`route`](route) wraps other directives like `handle` does, but with two distinctions:
1. route blocks are not mutually exclusive to each other,
2. directives within a route are not [re-ordered](/docs/caddyfile/directives#directive-order), giving you more control if needed.
## Examples ## Examples
Handle requests in `/foo/` by the static file server, and send all other requests to the reverse proxy: Handle requests in `/foo/` with the static file server, and other requests with the reverse proxy:
```caddy-d ```caddy
handle /foo/* { example.com {
file_server handle /foo/* {
} file_server
handle { }
reverse_proxy 127.0.0.1:8080
handle {
reverse_proxy 127.0.0.1:8080
}
} }
``` ```
You can mix `handle` and [`handle_path`](handle_path) directives in the same site, and they will still be mutually exclusive from each other: You can mix `handle` and [`handle_path`](handle_path) in the same site, and they will still be mutually exclusive from each other:
```caddy-d ```caddy
handle_path /foo/* { example.com {
# The path has the "/foo" prefix stripped handle_path /foo/* {
} # The path has the "/foo" prefix stripped
}
handle /bar/* { handle /bar/* {
# The path still retains "/bar" # The path still retains "/bar"
}
}
```
You can nest `handle` blocks to create more complex routing logic:
```caddy
example.com {
handle /foo* {
handle /foo/bar* {
# This block only matches paths under /foo/bar
}
handle {
# This block matches everything else under /foo/
}
}
handle {
# This block matches everything else (acts as a fallback)
}
} }
``` ```

View file

@ -97,12 +97,12 @@ To handle specific error codes differently, use an [`expression`](/docs/caddyfil
```caddy-d ```caddy-d
handle_errors { handle_errors {
@404-410 expression `{err.status_code} in [404, 410]` @404-410 `{err.status_code} in [404, 410]`
handle @404-410 { handle @404-410 {
respond "It's a 404 or 410 error!" respond "It's a 404 or 410 error!"
} }
@5xx expression `{err.status_code} >= 500 && {err.status_code} < 600` @5xx `{err.status_code} >= 500 && {err.status_code} < 600`
handle @5xx { handle @5xx {
respond "It's a 5xx error." respond "It's a 5xx error."
} }

View file

@ -20,7 +20,7 @@ window.$(function() {
# handle_path # handle_path
Works the same as the [`handle` directive](/docs/caddyfile/directives/handle), but implicitly uses [`uri strip_prefix`](/docs/caddyfile/directives/uri) to strip the matched path prefix. Works the same as the [`handle` directive](handle), but implicitly uses [`uri strip_prefix`](uri) to strip the matched path prefix.
Handling a request matching a certain path (while stripping that path from the request URI) is a common enough use case that it has its own directive for convenience. Handling a request matching a certain path (while stripping that path from the request URI) is a common enough use case that it has its own directive for convenience.
@ -47,7 +47,7 @@ handle_path /prefix/* {
} }
``` ```
is effectively the same as this: 👆 is effectively the same as this 👇, but the `handle_path` form 👆 is slightly more succinct
```caddy-d ```caddy-d
handle /prefix/* { handle /prefix/* {
@ -56,4 +56,19 @@ handle /prefix/* {
} }
``` ```
but the `handle_path` form is slightly more succinct. A full Caddyfile example, where `handle_path` and `handle` are mutually exclusive; but, be aware of the [subfolder problem <img src="/old/resources/images/external-link.svg" class="external-link">](https://caddy.community/t/the-subfolder-problem-or-why-cant-i-reverse-proxy-my-app-into-a-subfolder/8575)
```caddy
example.com {
# Serve your API, stripping the /api prefix
handle_path /api/* {
reverse_proxy localhost:9000
}
# Serve your static site
handle {
root * /srv
file_server
}
}
```

View file

@ -4,10 +4,12 @@ title: header (Caddyfile directive)
# header # header
Manipulates HTTP header fields on the response. It can set, add, and delete header values, or perform replacements using regular expressions. Manipulates HTTP response header fields. It can set, add, and delete header values, or perform replacements using regular expressions.
By default, header operations are performed immediately unless any of the headers are being deleted (`-` prefix) or setting a default value (`?` prefix). In those cases, the header operations are automatically deferred until the time they are being written to the client. By default, header operations are performed immediately unless any of the headers are being deleted (`-` prefix) or setting a default value (`?` prefix). In those cases, the header operations are automatically deferred until the time they are being written to the client.
To manipulate HTTP request headers, you may use the [`request_header`](request_header) directive.
## Syntax ## Syntax
@ -38,7 +40,9 @@ header [<matcher>] [[+|-|?|>]<field> [<value>|<find>] [<replace>]] {
} }
``` ```
- **&lt;field&gt;** is the name of the header field. By default, will overwrite any existing field of the same name. - **&lt;field&gt;** is the name of the header field.
With no prefix, the field is set (overwritten).
Prefix with `+` to add the field instead of overwriting (setting) the field if it already exists; header fields can appear more than once in a request. Prefix with `+` to add the field instead of overwriting (setting) the field if it already exists; header fields can appear more than once in a request.
@ -48,7 +52,7 @@ header [<matcher>] [[+|-|?|>]<field> [<value>|<find>] [<replace>]] {
Prefix with `>` to set the field, and enable `defer`, as a shortcut. Prefix with `>` to set the field, and enable `defer`, as a shortcut.
- **&lt;value&gt;** is the header field value, if adding or setting a field. - **&lt;value&gt;** is the header field value, when adding or setting a field.
- **&lt;find&gt;** is the substring or regular expression to search for. - **&lt;find&gt;** is the substring or regular expression to search for.
@ -58,7 +62,7 @@ header [<matcher>] [[+|-|?|>]<field> [<value>|<find>] [<replace>]] {
For multiple header manipulations, you can open a block and specify one manipulation per line in the same way. For multiple header manipulations, you can open a block and specify one manipulation per line in the same way.
When using the `?` prefix to set a default header value, it is recommended to separate this into its own `header` directive. [Under the hood](/docs/modules/http.handlers.headers#response/require), using `?` configures a response matcher which applies to the directive's entire handler which only applies the header operations if the field is not yet set. For example, if in the same directive, you have these two manipulations: `-Hidden` and `?Foo default`, then the `Hidden` header is _only_ removed if `Foo` is empty, which is typically not the intended effect. When using the `?` prefix to set a default header value, it is recommended to separate this into its own `header` directive. [Under the hood](/docs/modules/http.handlers.headers#response/require), using `?` configures a response matcher which applies to the directive's entire handler, which only applies the header operations if the field is not yet set. For example, in the same directive, you have these two manipulations: `-Hidden` and `?Foo default`, then the `Hidden` header is _only_ removed if `Foo` is empty, which is typically not the intended effect.
## Examples ## Examples

View file

@ -4,6 +4,16 @@ title: log (Caddyfile directive)
<script> <script>
window.$(function() { window.$(function() {
// Fix > in code blocks
window.$('pre.chroma .k:contains(">")')
.each(function() {
const e = window.$(this);
// Skip if ends with >
if (e.text().trim().endsWith('>')) return;
// Replace > with <span class="p">&gt;</span>
e.html(e.html().replace(/&gt;/g, '<span class="p">&gt;</span>'));
});
// We'll add links to all the subdirectives if a matching anchor tag is found on the page. // We'll add links to all the subdirectives if a matching anchor tag is found on the page.
addLinksToSubdirectives(); addLinksToSubdirectives();
}); });
@ -15,14 +25,14 @@ Enables and configures HTTP request logging (also known as access logs).
<aside class="tip"> <aside class="tip">
If you're looking to configure Caddy's runtime logs, you're looking for the [`log` global option](/docs/caddyfile/options#log) instead. To configure Caddy's runtime logs, see the [`log` global option](/docs/caddyfile/options#log) instead.
</aside> </aside>
The `log` directive applies to the host/port of the site block it appears in, not any other part of the site address (e.g. path). The `log` directive applies to the hostnames of the site block it appears in, unless overridden with the `hostnames` subdirective.
When configured, by default all requests to the site will be logged. To conditionally skip some requests from logging, use the [`skip_log` directive](/docs/caddyfile/directives/skip_log). When configured, by default all requests to the site will be logged. To conditionally skip some requests from logging, use the [`skip_log` directive](skip_log).
- [Syntax](#syntax) - [Syntax](#syntax)
@ -60,25 +70,35 @@ log [<logger_name>] {
} }
``` ```
- **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. - **logger_name** is an optional override of the logger name for this site.
- **hostnames** overrides 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. 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.
- **output** configures where to write the logs. See [Output modules](#output-modules) below. Default: `stderr`. - **hostnames** is an optional override of the hostnames that this logger applies to.
- **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. 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.
- **level** is the minimum entry level to log. Default: `INFO`. Note that access logs currently only emit `INFO` and `ERROR` level logs. - **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.
Default: `console` if `stderr` is detected to be a terminal, `json` otherwise.
- **level** is the minimum entry level to log. Default: `INFO`.
Note that access logs currently only emit `INFO` and `ERROR` level logs.
### Output modules ### Output modules
The **output** subdirective lets you customize where logs get written. It appears within a `log` block. The **output** subdirective lets you customize where logs get written.
#### stderr #### stderr
Standard error (console, default). Standard error (console, is the default).
```caddy-d ```caddy-d
output stderr output stderr
@ -104,6 +124,8 @@ output discard
A file. By default, log files are rotated ("rolled") to prevent disk space exhaustion. A file. By default, log files are rotated ("rolled") to prevent disk space exhaustion.
Log rolling is provided by [lumberjack <img src="/old/resources/images/external-link.svg" class="external-link">](https://github.com/natefinch/lumberjack)
```caddy-d ```caddy-d
output file <filename> { output file <filename> {
roll_disabled roll_disabled
@ -116,11 +138,25 @@ output file <filename> {
``` ```
- **&lt;filename&gt;** is the path to the log file. - **&lt;filename&gt;** is the path to the log file.
- **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. - **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.
- **roll_size** is the size at which to roll the log file. The current implementation supports megabyte resolution; fractional values are rounded up to the next whole megabyte. For example, `1.1MiB` is rounded up to `2MiB`. Default: `100MiB`
- **roll_uncompressed** turns off gzip log compression. Default: gzip compression is enabled. - **roll_size** is the size at which to roll the log file. The current implementation supports megabyte resolution; fractional values are rounded up to the next whole megabyte. For example, `1.1MiB` is rounded up to `2MiB`.
- **roll_local_time** sets the rolling to use local timestamps in filenames. Default: uses UTC time.
- **roll_keep** is how many log files to keep before deleting the oldest ones. Default: `10` Default: `100MiB`
- **roll_uncompressed** turns off gzip log compression.
Default: gzip compression is enabled.
- **roll_local_time** sets the rolling to use local timestamps in filenames.
Default: uses UTC time.
- **roll_keep** is how many log files to keep before deleting the oldest ones.
Default: `10`
- **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) - **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)
@ -136,7 +172,9 @@ output net <address> {
``` ```
- **&lt;address&gt;** is the [address](/docs/conventions#network-addresses) to write logs to. - **&lt;address&gt;** is the [address](/docs/conventions#network-addresses) to write logs to.
- **dial_timeout** is how long to wait for a successful connection to the log socket. Log emissions may be blocked for up to this long if the socket goes down. - **dial_timeout** is how long to wait for a successful connection to the log socket. Log emissions may be blocked for up to this long if the socket goes down.
- **soft_start** will ignore errors when connecting to the socket, allowing you to load your config even if the remote log service is down. Logs will be emitted to stderr instead. - **soft_start** will ignore errors when connecting to the socket, allowing you to load your config even if the remote log service is down. Logs will be emitted to stderr instead.
@ -171,33 +209,57 @@ format <encoder_module> {
``` ```
- **message_key** The key for the message field of the log entry. Default: `msg` - **message_key** The key for the message field of the log entry. Default: `msg`
- **level_key** The key for the level field of the log entry. Default: `level` - **level_key** The key for the level field of the log entry. Default: `level`
- **time_key** The key for the time field of the log entry. Default: `ts` - **time_key** The key for the time field of the log entry. Default: `ts`
- **name_key** The key for the name field of the log entry (i.e. the name of the logger itself). Default: `name`
- **name_key** The key for the name field of the log entry. Default: `name`
- **caller_key** The key for the caller field of the log entry. - **caller_key** The key for the caller field of the log entry.
- **stacktrace_key** The key for the stacktrace field of the log entry. - **stacktrace_key** The key for the stacktrace field of the log entry.
- **line_ending** The line endings to use. - **line_ending** The line endings to use.
- **time_format** The format for timestamps. May be one of:
- **unix_seconds_float** Floating-point number of seconds since the Unix epoch; this is the default. - **time_format** The format for timestamps.
- **unix_milli_float** Floating-point number of milliseconds since the Unix epoch.
- **unix_nano** Integer number of nanoseconds since the Unix epoch. Default: `wall_milli` if the format defaulted to `console`, `unix_seconds_float` otherwise.
- **iso8601** Example: `2006-01-02T15:04:05.000Z0700`
- **rfc3339** Example: `2006-01-02T15:04:05Z07:00` May be one of:
- **rfc3339_nano** Example: `2006-01-02T15:04:05.999999999Z07:00` - `unix_seconds_float` Floating-point number of seconds since the Unix epoch.
- **wall** Example: `2006/01/02 15:04:05` - `unix_milli_float` Floating-point number of milliseconds since the Unix epoch.
- **wall_milli** Example: `2006/01/02 15:04:05.000` - `unix_nano` Integer number of nanoseconds since the Unix epoch.
- **wall_nano** Example: `2006/01/02 15:04:05.000000000` - `iso8601` Example: `2006-01-02T15:04:05.000Z0700`
- **common_log** Example: `02/Jan/2006:15:04:05 -0700` - `rfc3339` Example: `2006-01-02T15:04:05Z07:00`
- `rfc3339_nano` Example: `2006-01-02T15:04:05.999999999Z07:00`
- `wall` Example: `2006/01/02 15:04:05`
- `wall_milli` Example: `2006/01/02 15:04:05.000`
- `wall_nano` Example: `2006/01/02 15:04:05.000000000`
- `common_log` Example: `02/Jan/2006:15:04:05 -0700`
- Or, any compatible time layout string; see the [Go documentation](https://pkg.go.dev/time#pkg-constants) for full details. - Or, any compatible time layout string; see the [Go documentation](https://pkg.go.dev/time#pkg-constants) for full details.
Note that the parts of the format string are special constants for the layout; so `2006` is the year, `01` is the month, `Jan` is the month as a string, `02` is the day. Do not use the actual current date numbers in the format string.
- **time_local** Logs with the local system time rather than the default of UTC time. - **time_local** Logs with the local system time rather than the default of UTC time.
- **duration_format** The format for durations. May be one of:
- **seconds** Floating-point number of seconds elapsed; this is the default. - **duration_format** The format for durations.
- **nano** Integer number of nanoseconds elapsed.
- **string** Using Go's built-in string format, for example `1m32.05s` or `6.31ms`. Default: `seconds`.
- **level_format** The format for levels. May be one of:
- **lower** Lowercase; this is the default. May be one of:
- **upper** Uppercase. - `seconds` Floating-point number of seconds elapsed.
- **color** Uppercase, with console colors. - `nano` 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.
Default: `color` if the format defaulted to `console`, `lower` otherwise.
May be one of:
- `lower` Lowercase.
- `upper` Uppercase.
- `color` Uppercase, with ANSI colors.
#### console #### console
@ -244,6 +306,7 @@ Marks a field to be skipped from being encoded.
<field> delete <field> delete
``` ```
##### rename ##### rename
Rename the key of a log field. Rename the key of a log field.
@ -252,6 +315,7 @@ Rename the key of a log field.
<field> rename <key> <field> rename <key>
``` ```
##### replace ##### replace
Marks a field to be replaced with the provided string at encoding time. Marks a field to be replaced with the provided string at encoding time.
@ -260,13 +324,17 @@ Marks a field to be replaced with the provided string at encoding time.
<field> replace <replacement> <field> replace <replacement>
``` ```
##### ip_mask ##### ip_mask
Masks IP addresses in the field using a CIDR mask, i.e. the number of bits from the IP to retain, starting from the left side. If the field is an array of strings (e.g. HTTP headers), each value in the array is masked. The value may be a comma separated string of IP addresses. Masks IP addresses in the field using a CIDR mask, i.e. the number of bits from the IP to retain, starting from the left side. If the field is an array of strings (e.g. HTTP headers), each value in the array is masked. The value may be a comma separated string of IP addresses.
There is separate configuration for IPv4 and IPv6 addresses, since they have a different total number of bits. There is separate configuration for IPv4 and IPv6 addresses, since they have a different total number of bits.
Most commonly, the fields to filter would be `request>remote_ip` for the directly connecting client, `request>client_ip` for the parsed "real client" when [`trusted_proxies`](/docs/caddyfile/options#trusted-proxies) is configured, or `request>headers>X-Forwarded-For` if behind a reverse proxy. Most commonly, the fields to filter would be:
- `request>remote_ip` for the directly connecting client
- `request>client_ip` for the parsed "real client" when [`trusted_proxies`](/docs/caddyfile/options#trusted-proxies) is configured
- `request>headers>X-Forwarded-For` if behind a reverse proxy
```caddy-d ```caddy-d
<field> ip_mask { <field> ip_mask {
@ -275,9 +343,10 @@ Most commonly, the fields to filter would be `request>remote_ip` for the directl
} }
``` ```
##### query ##### query
Marks a field to have one or more actions performed, to manipulate the query part of a URL field. Most commonly, the field to filter would be `request>uri`. The available actions are: Marks a field to have one or more actions performed, to manipulate the query part of a URL field. Most commonly, the field to filter would be `request>uri`.
```caddy-d ```caddy-d
<field> query { <field> query {
@ -287,13 +356,18 @@ Marks a field to have one or more actions performed, to manipulate the query par
} }
``` ```
The available actions are:
- **delete** removes the given key from the query. - **delete** removes the given key from the query.
- **replace** replaces the value of the given query key with **replacement**. Useful to insert a redaction placeholder; you'll see that the query key was in the URL, but the value is hidden. - **replace** replaces the value of the given query key with **replacement**. Useful to insert a redaction placeholder; you'll see that the query key was in the URL, but the value is hidden.
- **hash** replaces the value of the given query key with the first 4 bytes of the SHA-256 hash of the value, lowercase hexadecimal. Useful to obscure the value if it's sensitive, while being able to notice whether each request had a different value. - **hash** replaces the value of the given query key with the first 4 bytes of the SHA-256 hash of the value, lowercase hexadecimal. Useful to obscure the value if it's sensitive, while being able to notice whether each request had a different value.
##### cookie ##### cookie
Marks a field to have one or more actions performed, to manipulate a `Cookie` HTTP header's value. Most commonly, the field to filter would be `request>headers>Cookie`. The available actions are: Marks a field to have one or more actions performed, to manipulate a `Cookie` HTTP header's value. Most commonly, the field to filter would be `request>headers>Cookie`.
```caddy-d ```caddy-d
<field> cookie { <field> cookie {
@ -303,12 +377,17 @@ Marks a field to have one or more actions performed, to manipulate a `Cookie` HT
} }
``` ```
The available actions are:
- **delete** removes the given cookie by name from the header. - **delete** removes the given cookie by name from the header.
- **replace** replaces the value of the given cookie with **replacement**. Useful to insert a redaction placeholder; you'll see that the cookie was in the header, but the value is hidden. - **replace** replaces the value of the given cookie with **replacement**. Useful to insert a redaction placeholder; you'll see that the cookie was in the header, but the value is hidden.
- **hash** replaces the value of the given cookie with the first 4 bytes of the SHA-256 hash of the value, lowercase hexadecimal. Useful to obscure the value if it's sensitive, while being able to notice whether each request had a different value. - **hash** replaces the value of the given cookie with the first 4 bytes of the SHA-256 hash of the value, lowercase hexadecimal. Useful to obscure the value if it's sensitive, while being able to notice whether each request had a different value.
If many actions are defined for the same cookie name, only the first action will be applied. If many actions are defined for the same cookie name, only the first action will be applied.
##### regexp ##### regexp
Marks a field to have a regular expression replacement applied at encoding time. If the field is an array of strings (e.g. HTTP headers), each value in the array has replacements applied. Marks a field to have a regular expression replacement applied at encoding time. If the field is an array of strings (e.g. HTTP headers), each value in the array has replacements applied.
@ -321,6 +400,7 @@ The regular expression language used is RE2, included in Go. See the [RE2 syntax
In the replacement string, capture groups can be referenced with `${group}` where `group` is either the name or number of the capture group in the expression. Capture group `0` is the full regexp match, `1` is the first capture group, `2` is the second capture group, and so on. In the replacement string, capture groups can be referenced with `${group}` where `group` is either the name or number of the capture group in the expression. Capture group `0` is the full regexp match, `1` is the first capture group, `2` is the second capture group, and so on.
##### hash ##### hash
Marks a field to be replaced with the first 4 bytes (8 hex characters) of the SHA-256 hash of the value at encoding time. If the field is a string array (e.g. HTTP headers), each value in the array is hashed. Marks a field to be replaced with the first 4 bytes (8 hex characters) of the SHA-256 hash of the value at encoding time. If the field is a string array (e.g. HTTP headers), each value in the array is hashed.
@ -337,30 +417,36 @@ Useful to obscure the value if it's sensitive, while being able to notice whethe
Enable access logging to the default logger. Enable access logging to the default logger.
In other words, by default this logs to the console or stderr, but this can be changed by reconfiguring the default logger with the [`log` global option](/docs/caddyfile/options#log): In other words, by default this logs to `stderr`, but this can be changed by reconfiguring the `default` logger with the [`log` global option](/docs/caddyfile/options#log):
```caddy-d ```caddy
log example.com {
log
}
``` ```
Write logs to a file (with log rolling, which is enabled by default): Write logs to a file (with log rolling, which is enabled by default):
```caddy-d ```caddy
log { example.com {
output file /var/log/access.log log {
output file /var/log/access.log
}
} }
``` ```
Customize log rolling: Customize log rolling:
```caddy-d ```caddy
log { example.com {
output file /var/log/access.log { log {
roll_size 1gb output file /var/log/access.log {
roll_keep 5 roll_size 1gb
roll_keep_for 720h roll_keep 5
roll_keep_for 720h
}
} }
} }
``` ```
@ -368,12 +454,14 @@ log {
Delete the `User-Agent` request header from the logs: Delete the `User-Agent` request header from the logs:
```caddy-d ```caddy
log { example.com {
format filter { log {
wrap console format filter {
fields { wrap console
request>headers>User-Agent delete fields {
request>headers>User-Agent delete
}
} }
} }
} }
@ -382,14 +470,16 @@ log {
Redact multiple sensitive cookies. (Note that some sensitive headers are logged with empty values by default; see the [`log_credentials` global option](/docs/caddyfile/options#log-credentials) to enable logging `Cookie` header values): Redact multiple sensitive cookies. (Note that some sensitive headers are logged with empty values by default; see the [`log_credentials` global option](/docs/caddyfile/options#log-credentials) to enable logging `Cookie` header values):
```caddy-d ```caddy
log { example.com {
format filter { log {
wrap console format filter {
fields { wrap console
request>headers>Cookie cookie { fields {
replace session REDACTED request>headers>Cookie cookie {
delete secret replace session REDACTED
delete secret
}
} }
} }
} }
@ -401,14 +491,16 @@ Mask the remote address from the request, keeping the first 16 bits (i.e. 255.25
Note that as of Caddy v2.7, both `remote_ip` and `client_ip` are logged, where `client_ip` is the "real IP" when [`trusted_proxies`](/docs/caddyfile/options#trusted-proxies) is configured: Note that as of Caddy v2.7, both `remote_ip` and `client_ip` are logged, where `client_ip` is the "real IP" when [`trusted_proxies`](/docs/caddyfile/options#trusted-proxies) is configured:
```caddy-d ```caddy
log { example.com {
format filter { log {
wrap console format filter {
fields { wrap console
request>remote_ip ip_mask { fields {
ipv4 16 request>remote_ip ip_mask {
ipv6 32 ipv4 16
ipv6 32
}
} }
} }
} }
@ -416,23 +508,24 @@ log {
``` ```
<span id="wildcard-logs" /> To write separate log files for each subdomain in a [wildcard site block](/docs/caddyfile/patterns#wildcard-certificates), by overriding `hostnames` for each logger: <span id="wildcard-logs" /> To write separate log files for each subdomain in a [wildcard site block](/docs/caddyfile/patterns#wildcard-certificates), by overriding `hostnames` for each logger. This uses a [snippet](/docs/caddyfile/concepts#snippets) to avoid repetition:
```caddy ```caddy
*.example.com { (subdomain-log) {
log { log {
hostnames foo.example.com hostnames {args[0]}
output file /var/log/foo.example.com.log output file /var/log/{args[0]}.log
} }
}
*.example.com {
import subdomain-log foo.example.com
@foo host foo.example.com @foo host foo.example.com
handle @foo { handle @foo {
respond "foo" respond "foo"
} }
log { import subdomain-log bar.example.com
hostnames bar.example.com
output file /var/log/bar.example.com.log
}
@bar host bar.example.com @bar host bar.example.com
handle @bar { handle @bar {
respond "bar" respond "bar"

View file

@ -175,8 +175,14 @@ app2.example.com {
For a PHP site which does not use `index.php` as an entrypoint, you may fallback to emitting a `404` error instead. The error may be caught and handled with the [`handle_errors` directive](handle_errors): For a PHP site which does not use `index.php` as an entrypoint, you may fallback to emitting a `404` error instead. The error may be caught and handled with the [`handle_errors` directive](handle_errors):
```caddy-d ```caddy
php_fastcgi localhost:9000 { example.com {
try_files {path} {path}/index.php =404 php_fastcgi localhost:9000 {
try_files {path} {path}/index.php =404
}
handle_errors {
respond "{err.status_code} {err.status_text}"
}
} }
``` ```

View file

@ -6,7 +6,7 @@ title: redir (Caddyfile directive)
Issues an HTTP redirect to the client. Issues an HTTP redirect to the client.
This directive implies that a matched request is to be rejected. It is ordered very early in the [handler chain](/docs/caddyfile/directives#directive-order) (before [`rewrite`](/docs/caddyfile/directives/rewrite)). This directive implies that a matched request is to be rejected as-is, and the client should try again at a different URL. For that reason, its [directive order](/docs/caddyfile/directives#directive-order) is very early.
## Syntax ## Syntax
@ -15,12 +15,18 @@ This directive implies that a matched request is to be rejected. It is ordered v
redir [<matcher>] <to> [<code>] redir [<matcher>] <to> [<code>]
``` ```
- **&lt;to&gt;** is the target location. Becomes the response's Location header. - **&lt;to&gt;** is the target location. Becomes the response's [`Location` header <img src="/old/resources/images/external-link.svg" class="external-link">](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location).
- **&lt;code&gt;** is the HTTP status code to use for the redirect. Can be: - **&lt;code&gt;** is the HTTP status code to use for the redirect. Can be:
- A positive integer in the 3xx range, or 401
- `temporary` for a temporary redirect (302; default) - A positive integer in the `3xx` range, or `401`
- `permanent` for a permanent redirect (301)
- `temporary` for a temporary redirect (`302`, this is the default)
- `permanent` for a permanent redirect (`301`)
- `html` to use an HTML document to perform the redirect (useful for redirecting browsers but not API clients) - `html` to use an HTML document to perform the redirect (useful for redirecting browsers but not API clients)
- A placeholder with a status code value - A placeholder with a status code value
@ -29,24 +35,33 @@ redir [<matcher>] <to> [<code>]
Redirect all requests to `https://example.com`: Redirect all requests to `https://example.com`:
```caddy-d ```caddy
redir https://example.com www.example.com {
redir https://example.com
}
``` ```
Same, but preserve the existing URI by appending the [`{uri}` placeholder](/docs/caddyfile/concepts#placeholders): Same, but preserve the existing URI by appending the [`{uri}` placeholder](/docs/caddyfile/concepts#placeholders):
```caddy-d ```caddy
redir https://example.com{uri} www.example.com {
redir https://example.com{uri}
}
``` ```
Same, but permanent: Same, but permanent:
```caddy-d ```caddy
redir https://example.com{uri} permanent www.example.com {
redir https://example.com{uri} permanent
}
``` ```
Redirect your old `/about-us` page to your new `/about` page: Redirect your old `/about-us` page to your new `/about` page:
```caddy-d ```caddy
redir /about-us /about example.com {
redir /about-us /about
reverse_proxy localhost:9000
}
``` ```

View file

@ -11,19 +11,22 @@ Manipulates or sets restrictions on the bodies of incoming requests.
```caddy-d ```caddy-d
request_body [<matcher>] { request_body [<matcher>] {
max_size <value> max_size <value>
} }
``` ```
- **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. - **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`.
## Examples ## Examples
Limit request body sizes to 10 megabytes: Limit request body sizes to 10 megabytes:
```caddy-d ```caddy
request_body { example.com {
max_size 10MB request_body {
max_size 10MB
}
reverse_proxy localhost:8080
} }
``` ```

View file

@ -8,6 +8,8 @@ Manipulates HTTP header fields on the request. It can set, add, and delete heade
If you intend to manipulate headers for proxying, use the [`header_up` subdirective](/docs/caddyfile/directives/reverse_proxy#header_up) of `reverse_proxy` instead, as those manipulations are proxy-aware. If you intend to manipulate headers for proxying, use the [`header_up` subdirective](/docs/caddyfile/directives/reverse_proxy#header_up) of `reverse_proxy` instead, as those manipulations are proxy-aware.
To manipulate HTTP response headers, you may use the [`header`](header) directive.
## Syntax ## Syntax
@ -15,7 +17,9 @@ If you intend to manipulate headers for proxying, use the [`header_up` subdirect
request_header [<matcher>] [[+|-]<field> [<value>|<find>] [<replace>]] request_header [<matcher>] [[+|-]<field> [<value>|<find>] [<replace>]]
``` ```
- **&lt;field&gt;** is the name of the header field. By default, will overwrite any existing field of the same name. - **&lt;field&gt;** is the name of the header field.
With no prefix, the field is set (overwritten).
Prefix with `+` to add the field instead of overwriting (setting) the field if it already exists; header fields can appear more than once in a request. Prefix with `+` to add the field instead of overwriting (setting) the field if it already exists; header fields can appear more than once in a request.

View file

@ -18,7 +18,11 @@ respond [<matcher>] <status>|<body> [<status>] {
} }
``` ```
- **&lt;status&gt;** is the HTTP status code to write. If 103 (Early Hints), the response will be written without a body and the handler chain will continue. (HTTP 1xx responses are informational, not final.) Default: 200. - **&lt;status&gt;** is the HTTP status code to write.
If `103` (Early Hints), the response will be written without a body and the handler chain will continue. (HTTP `1xx` responses are informational, not final.)
Default: `200`
- **&lt;body&gt;** is the response body to write. - **&lt;body&gt;** is the response body to write.
@ -29,40 +33,49 @@ respond [<matcher>] <status>|<body> [<status>] {
To clarify, the first non-matcher argument can be either a 3-digit status code or a response body string. If it is a body, the next argument can be the status code. To clarify, the first non-matcher argument can be either a 3-digit status code or a response body string. If it is a body, the next argument can be the status code.
<aside class="tip"> <aside class="tip">
Responding with an error status code is different than returning an error in the handler chain, which invokes error handlers internally.
Responding with an error status code is different than returning an error in the handler chain, which invokes error handlers internally.
</aside> </aside>
## Examples ## Examples
Write a 200 status with an empty body to all health checks: Write an empty 200 status with an empty body to all health checks, and a simple response body to all other requests:
```caddy-d ```caddy
respond /health-check 200 example.com {
``` respond /health-check 200
respond "Hello, world!"
Write a simple response body to all requests: }
```caddy-d
respond "Hello, world!"
``` ```
Write an error response and close the connection: Write an error response and close the connection:
```caddy-d <aside class="tip">
respond /secret/* "Access denied" 403 {
close You might prefer to use the [`error` directive](error) instead, which triggers an error that can be handled with the [`handle_errors` directive](handle_errors).
</aside>
```caddy
example.com {
respond /secret/* "Access denied" 403 {
close
}
} }
``` ```
Write an HTML response, using [heredoc syntax](/docs/caddyfile/concepts#heredocs) to control whitespace, and also setting the `Content-Type` header to match the response body: Write an HTML response, using [heredoc syntax](/docs/caddyfile/concepts#heredocs) to control whitespace, and also setting the `Content-Type` header to match the response body:
```caddy-d ```caddy
header Content-Type text/html example.com {
respond <<HTML header Content-Type text/html
<html> respond <<HTML
<head><title>Foo</title></head> <html>
<body>Foo</body> <head><title>Foo</title></head>
</html> <body>Foo</body>
HTML 200 </html>
HTML 200
}
``` ```

View file

@ -530,7 +530,7 @@ transport http {
- **max_response_header** <span id="max_response_header"/> is the maximum amount of bytes to read from response headers. It accepts all formats supported by [go-humanize](https://github.com/dustin/go-humanize/blob/master/bytes.go). Default: `10MiB`. - **max_response_header** <span id="max_response_header"/> is the maximum amount of bytes to read from response headers. It accepts all formats supported by [go-humanize](https://github.com/dustin/go-humanize/blob/master/bytes.go). Default: `10MiB`.
- **proxy_protocol** <span id="proxy_protocol"/> enables [PROXY protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) (popularized by HAProxy) on the connection to the upstream, prepending the real client IP data. This is best paired with the [`servers > trusted_proxies` global option](/docs/caddyfile/options#trusted-proxies) if Caddy is behind another proxy. Versions `v1` and `v2` are supported. This should only be used if you know the upstream server is able to parse PROXY protocol. By default, this is disabled. - **proxy_protocol** <span id="proxy_protocol"/> enables [PROXY protocol](https://github.com/haproxy/haproxy/blob/master/doc/proxy-protocol.txt) (popularized by HAProxy) on the connection to the upstream, prepending the real client IP data. This is best paired with the [`servers > trusted_proxies` global option](/docs/caddyfile/options#trusted-proxies) if Caddy is behind another proxy. Versions `v1` and `v2` are supported. This should only be used if you know the upstream server is able to parse PROXY protocol. By default, this is disabled.
- **dial_timeout** <span id="dial_timeout"/> is the maximum [duration](/docs/conventions#durations) to wait when connecting to the upstream socket. Default: `3s`. - **dial_timeout** <span id="dial_timeout"/> is the maximum [duration](/docs/conventions#durations) to wait when connecting to the upstream socket. Default: `3s`.
@ -672,44 +672,54 @@ See the [`header`](/docs/caddyfile/matchers#header) request matcher for the supp
Reverse proxy all requests to a local backend: Reverse proxy all requests to a local backend:
```caddy-d ```caddy
reverse_proxy localhost:9005 example.com {
reverse_proxy localhost:9005
}
``` ```
[Load-balance](#load-balancing) all requests [between 3 backends](#upstreams): [Load-balance](#load-balancing) all requests [between 3 backends](#upstreams):
```caddy-d ```caddy
reverse_proxy node1:80 node2:80 node3:80 example.com {
reverse_proxy node1:80 node2:80 node3:80
}
``` ```
Same, but only requests within `/api`, and sticky by using the [`cookie` policy](#lb_policy): Same, but only requests within `/api`, and sticky by using the [`cookie` policy](#lb_policy):
```caddy-d ```caddy
reverse_proxy /api/* node1:80 node2:80 node3:80 { example.com {
lb_policy cookie api_sticky reverse_proxy /api/* node1:80 node2:80 node3:80 {
lb_policy cookie api_sticky
}
} }
``` ```
Using [active health checks](#active-health-checks) to determine which backends are healthy, and enabling [retries](#lb_try_duration) on failed connections, holding the request until a healthy backend is found: Using [active health checks](#active-health-checks) to determine which backends are healthy, and enabling [retries](#lb_try_duration) on failed connections, holding the request until a healthy backend is found:
```caddy-d ```caddy
reverse_proxy node1:80 node2:80 node3:80 { example.com {
health_uri /healthz reverse_proxy node1:80 node2:80 node3:80 {
lb_try_duration 5s health_uri /healthz
lb_try_duration 5s
}
} }
``` ```
Configure some [transport options](#transports): Configure some [transport options](#transports):
```caddy-d ```caddy
reverse_proxy localhost:8080 { example.com {
transport http { reverse_proxy localhost:8080 {
dial_timeout 2s transport http {
response_header_timeout 30s dial_timeout 2s
response_header_timeout 30s
}
} }
} }
``` ```
@ -717,19 +727,23 @@ reverse_proxy localhost:8080 {
Reverse proxy to an [HTTPS upstream](#https): Reverse proxy to an [HTTPS upstream](#https):
```caddy-d ```caddy
reverse_proxy https://example.com { example.com {
header_up Host {upstream_hostport} reverse_proxy https://example.com {
header_up Host {upstream_hostport}
}
} }
``` ```
Reverse proxy to an HTTPS upstream, but [⚠️ disable TLS verification](#tls_insecure_skip_verify). this is NOT RECOMMENDED, since it disables all security checks that HTTPS offers; proxying over HTTP in private networks is preferred if possible, because it avoids the false sense of security: Reverse proxy to an HTTPS upstream, but [⚠️ disable TLS verification](#tls_insecure_skip_verify). This is NOT RECOMMENDED, since it disables all security checks that HTTPS offers; proxying over HTTP in private networks is preferred if possible, because it avoids the false sense of security:
```caddy-d ```caddy
reverse_proxy 10.0.0.1:443 { example.com {
transport http { reverse_proxy 10.0.0.1:443 {
tls_insecure_skip_verify transport http {
tls_insecure_skip_verify
}
} }
} }
``` ```
@ -737,46 +751,54 @@ reverse_proxy 10.0.0.1:443 {
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_trusted_ca_certs), and (optionally) setting TLS-SNI to match the hostname in the upstream's certificate:
```caddy-d ```caddy
reverse_proxy 10.0.0.1:443 { example.com {
transport http { reverse_proxy 10.0.0.1:443 {
tls_trusted_ca_certs /path/to/cert.pem transport http {
tls_server_name app.example.com tls_trusted_ca_certs /path/to/cert.pem
tls_server_name app.example.com
}
} }
} }
``` ```
[Strip a path prefix](/docs/caddyfile/directives/handle_path) before proxying; but be aware of the [subfolder problem <img src="/old/resources/images/external-link.svg" class="external-link">](https://caddy.community/t/the-subfolder-problem-or-why-cant-i-reverse-proxy-my-app-into-a-subfolder/8575): [Strip a path prefix](handle_path) before proxying; but be aware of the [subfolder problem <img src="/old/resources/images/external-link.svg" class="external-link">](https://caddy.community/t/the-subfolder-problem-or-why-cant-i-reverse-proxy-my-app-into-a-subfolder/8575):
```caddy-d ```caddy
handle_path /prefix/* { example.com {
reverse_proxy localhost:9000 handle_path /prefix/* {
reverse_proxy localhost:9000
}
} }
``` ```
Replace a path prefix before proxying, using a [rewrite](/docs/caddyfile/directives/rewrite): Replace a path prefix before proxying, using a [`rewrite`](/docs/caddyfile/directives/rewrite):
```caddy-d ```caddy
handle_path /old-prefix/* { example.com {
rewrite * /new-prefix{path} handle_path /old-prefix/* {
reverse_proxy localhost:9000 rewrite * /new-prefix{path}
reverse_proxy localhost:9000
}
} }
``` ```
`X-Accel-Redirect` support, i.e. serving static files as requested, by [intercepting the response](#intercepting-responses): `X-Accel-Redirect` support, i.e. serving static files as requested, by [intercepting the response](#intercepting-responses):
```caddy-d ```caddy
reverse_proxy localhost:8080 { example.com {
@accel header X-Accel-Redirect * reverse_proxy localhost:8080 {
handle_response @accel { @accel header X-Accel-Redirect *
root * /path/to/private/files handle_response @accel {
rewrite * {rp.header.X-Accel-Redirect} root * /path/to/private/files
method * GET rewrite * {rp.header.X-Accel-Redirect}
file_server method * GET
file_server
}
} }
} }
``` ```
@ -784,13 +806,15 @@ reverse_proxy localhost:8080 {
Custom error page for errors from upstream, by [intercepting error responses](#intercepting-responses) by status code: Custom error page for errors from upstream, by [intercepting error responses](#intercepting-responses) by status code:
```caddy-d ```caddy
reverse_proxy localhost:8080 { example.com {
@error status 500 503 reverse_proxy localhost:8080 {
handle_response @error { @error status 500 503
root * /path/to/error/pages handle_response @error {
rewrite * /{rp.status_code}.html root * /path/to/error/pages
file_server rewrite * /{rp.status_code}.html
file_server
}
} }
} }
``` ```
@ -798,18 +822,22 @@ reverse_proxy localhost:8080 {
Get backends [dynamically](#dynamic-upstreams) from [`A`/`AAAA` record](#aaaaa) DNS queries: Get backends [dynamically](#dynamic-upstreams) from [`A`/`AAAA` record](#aaaaa) DNS queries:
```caddy-d ```caddy
reverse_proxy { example.com {
dynamic a example.com 9000 reverse_proxy {
dynamic a example.com 9000
}
} }
``` ```
Get backends [dynamically](#dynamic-upstreams) from [`SRV` record](#srv) DNS queries: Get backends [dynamically](#dynamic-upstreams) from [`SRV` record](#srv) DNS queries:
```caddy-d ```caddy
reverse_proxy { example.com {
dynamic srv _api._tcp.example.com reverse_proxy {
dynamic srv _api._tcp.example.com
}
} }
``` ```

View file

@ -4,11 +4,15 @@ title: rewrite (Caddyfile directive)
# rewrite # rewrite
Rewrites the request internally. A rewrite changes some or all of the request URI. Note that the URI does not include scheme or authority (host & port), and clients typically do not send fragments. Thus, this directive is mostly used for path and query string manipulation. Rewrites the request URI internally.
The `rewrite` directive implies the intent to accept the request, but with modifications. It is mutually exclusive to other `rewrite` directives in the same block, so it is safe to define rewrites that would otherwise cascade into each other as only the first matching rewrite will be executed. A rewrite changes some or all of the request URI. Note that the URI does not include scheme or authority (host & port), and clients typically do not send fragments. Thus, this directive is mostly used for **path** and **query** string manipulation.
Because `rewrite` essentially performs an internal redirect, the Caddyfile adapter will not fold any subsequent, adjacent handlers into the same route if their matchers happen to be exactly the same. This allows the matchers of the next handlers to be deferred until after the rewrite. In other words, a matcher that matches a request before the `rewrite` might not match the same request after the `rewrite`. If you want your `rewrite` to share a route with other handlers, use the [`route`](route) or [`handle`](handle) directives. The `rewrite` directive implies the intent to accept the request, but with modifications.
It is mutually exclusive to other `rewrite` directives in the same block, so it is safe to define rewrites that would otherwise cascade into each other as only the first matching rewrite will be executed.
A [request matcher](/docs/caddyfile/matchers) that matches a request before the `rewrite` might not match the same request after the `rewrite`. If you want your `rewrite` to share a route with other handlers, use the [`route`](route) or [`handle`](handle) directives.
## Syntax ## Syntax
@ -20,36 +24,55 @@ rewrite [<matcher>] <to>
- **&lt;to&gt;** is the URI to rewrite the request to. Only the components of the URI (path or query string) that are specified in the rewrite will be operated on. The URI path is any substring that comes before `?`. If `?` is omitted, then the whole token is considered to be the path. - **&lt;to&gt;** is the URI to rewrite the request to. Only the components of the URI (path or query string) that are specified in the rewrite will be operated on. The URI path is any substring that comes before `?`. If `?` is omitted, then the whole token is considered to be the path.
## Examples
Rewrite all requests to `foo.html`, leaving any query string unchanged:
```caddy-d
rewrite * /foo.html
```
Replace the query string on API requests with `a=b`, leaving the path unchanged:
```caddy-d
rewrite /api/* ?a=b
```
Preserve the existing query string and add a key-value pair:
```caddy-d
rewrite /api/* ?{query}&a=b
```
Change both the path and query string, preserving the original query string while adding the original path as the `p` parameter:
```caddy-d
rewrite * /index.php?{query}&p={path}
```
## Similar directives ## Similar directives
There are other directives that perform rewrites, but imply a different intent or do the rewrite without a complete replacement of the URI: There are other directives that perform rewrites, but imply a different intent or do the rewrite without a complete replacement of the URI:
- [`uri`](uri) manipulates a URI (strip prefix, suffix, or substring replacement). - [`uri`](uri) manipulates a URI (strip prefix, suffix, or substring replacement).
- [`try_files`](try_files) rewrites the request based on the existence of files. - [`try_files`](try_files) rewrites the request based on the existence of files.
## Examples
Rewrite all requests to `index.html`, leaving any query string unchanged:
```caddy
example.com {
rewrite * /index.html
}
```
Prefixing all requests with `/api`, preserving the rest of the URI, then reverse proxying to an app:
```caddy
api.example.com {
rewrite * /api{uri}
reverse_proxy localhost:8080
}
```
Replace the query string on API requests with `a=b`, leaving the path unchanged:
```caddy
example.com {
rewrite * ?a=b
}
```
For only requests to `/api/`, preserve the existing query string and add a key-value pair:
```caddy
example.com {
rewrite /api/* ?{query}&a=b
}
```
Change both the path and query string, preserving the original query string while adding the original path as the `p` parameter:
```caddy
example.com {
rewrite * /index.php?{query}&p={path}
}
```

View file

@ -8,7 +8,7 @@ Sets the root path of the site, used by various matchers and directives that acc
Specifically, this directive sets the `{http.vars.root}` placeholder. It is mutually exclusive to other `root` directives in the same block, so it is safe to define multiple roots with matchers that intersect: they will not cascade and overwrite each other. Specifically, this directive sets the `{http.vars.root}` placeholder. It is mutually exclusive to other `root` directives in the same block, so it is safe to define multiple roots with matchers that intersect: they will not cascade and overwrite each other.
This directive does not automatically enable serving static files, so it is often used in conjunction with the [`file_server` directive](/docs/caddyfile/directives/file_server) or the [`php_fastcgi` directive](/docs/caddyfile/directives/php_fastcgi). This directive does not automatically enable serving static files, so it is often used in conjunction with the [`file_server` directive](file_server) or the [`php_fastcgi` directive](php_fastcgi).
## Syntax ## Syntax
@ -21,16 +21,30 @@ root [<matcher>] <path>
Note that the `<path>` argument could be confused by the parser for a [matcher token](/docs/caddyfile/matchers#syntax) if it begins with `/`. To disambiguate, specify a wildcard matcher token (`*`). See examples below. Note that the `<path>` argument could be confused by the parser for a [matcher token](/docs/caddyfile/matchers#syntax) if it begins with `/`. To disambiguate, specify a wildcard matcher token (`*`). See examples below.
## Examples ## Examples
Set the site root to `/home/user/public_html` for all requests: Set the site root to `/home/bob/public_html` (assumes Caddy is running as the user `bob`):
<aside class="tip">
If you're running Caddy as a systemd service, reading files from `/home` will not work, because the `caddy` user does not have "executable" permission on the `/home` directory (necessary for traversal). It's recommended that you place your files in `/srv` or `/var/www/html` instead.
</aside>
(Note that a [wildcard matcher](/docs/caddyfile/matchers#wildcard-matchers) is required here because the first argument is ambiguous with a [path matcher](/docs/caddyfile/matchers#path-matchers).)
```caddy-d ```caddy-d
root * /home/user/public_html root * /home/bob/public_html
``` ```
<aside class="tip">
Note that a [wildcard matcher](/docs/caddyfile/matchers#wildcard-matchers) is required here because the first argument is ambiguous with a [path matcher](/docs/caddyfile/matchers#path-matchers).
</aside>
Set the site root to `public_html` (relative to current working directory) for all requests: Set the site root to `public_html` (relative to current working directory) for all requests:
(No matcher token is required here because our site root is a relative path, so it does not start with a forward slash and thus is not ambiguous.) (No matcher token is required here because our site root is a relative path, so it does not start with a forward slash and thus is not ambiguous.)
@ -45,9 +59,11 @@ Change the site root only for requests in `/foo/*`:
root /foo/* /home/user/public_html/foo root /foo/* /home/user/public_html/foo
``` ```
The `root` directive is commonly paired with [`file_server`](/docs/caddyfile/directives/file_server) to serve static files and/or with [`php_fastcgi`](/docs/caddyfile/directives/php_fastcgi) to serve a PHP site: The `root` directive is commonly paired with [`file_server`](file_server) to serve static files and/or with [`php_fastcgi`](php_fastcgi) to serve a PHP site:
```caddy-d ```caddy
root * /home/user/public_html example.com {
file_server root * /srv
file_server
}
``` ```

View file

@ -29,58 +29,78 @@ The `route` directive is helpful in certain advanced use cases or edge cases to
Because the order of HTTP middleware evaluation is significant, the Caddyfile will normally reorder directives after parsing to make the Caddyfile easier to use; you don't have to worry about what order you type things. Because the order of HTTP middleware evaluation is significant, the Caddyfile will normally reorder directives after parsing to make the Caddyfile easier to use; you don't have to worry about what order you type things.
While the built-in order is compatible with most sites, sometimes you need to take manual control over the order, either for the whole site or just a part of it. That's what the `route` directive is for. While the [built-in order](/docs/caddyfile/directives#directive-order) is compatible with most sites, sometimes you need to take manual control over the order, either for the whole site or just a part of it. That's what the `route` directive is for.
To illustrate, consider the case of two terminating handlers: `redir` and `file_server`. Both write the response to the client and do not call the next handler in the chain, so only one of these will be executed for a certain request. Which comes first? Normally, `redir` is executed before `file_server` because usually you would want to issue a redirect only in specific cases and serve files in the general case. To illustrate, consider the case of two terminating handlers: [`redir`](redir) and [`file_server`](file_server). Both write the response to the client and do not call the next handler in the chain, so only one of these will be executed for a certain request. So which comes first? Normally, `redir` is executed before `file_server` because usually you would want to issue a redirect only in specific cases and serve files in the general case.
However, there may be occasions where the second directive (`redir`) has a more specific matcher than the second (`file_server`). In other words, you want to redirect in the general case, and serve only a specific file. However, there may be occasions where the second directive (`redir`) has a more specific matcher than the second (`file_server`). In other words, you want to redirect in the general case, and serve only a specific file.
So you might try a Caddyfile like this (but this will not work as expected!): So you might try a Caddyfile like this (but this will not work as expected!):
```caddy ```caddy
example.com example.com {
file_server /specific.html
redir https://anothersite.com{uri}
```
The problem is that, internally, `redir` comes before `file_server`, but in this case the matcher for `redir` is a superset of the matcher for `file_server` (`*` is a superset of `/specific.html`).
Fortunately, the solution is easy: just wrap those two directives in a `route` block:
```caddy
example.com
route {
file_server /specific.html file_server /specific.html
redir https://anothersite.com{uri} redir https://anothersite.com{uri}
} }
``` ```
The problem is that after the [directives are sorted](/docs/caddyfile/directives#sorting-algorithm), `redir` comes before `file_server`.
But in this case the matcher for `redir` (an implicit [`*`](/docs/caddyfile/matchers#wildcard-matchers)) is a superset of the matcher for `file_server` (`*` is a superset of `/specific.html`).
Fortunately, the solution is easy: just wrap those two directives in a `route` block, to ensure that `file_server` is executed before `redir`:
```caddy
example.com {
route {
file_server /specific.html
redir https://anothersite.com{uri}
}
}
```
<aside class="tip"> <aside class="tip">
Another way to do this is to make the two matchers mutually exclusive, but this can quickly become complex if there are more than one or two conditions. With the `route` directive, the mutual exclusivity of the two handlers is implicit because they are both terminal handlers. Another way to do this is to make the two matchers mutually exclusive, but this can quickly become complex if there are more than one or two conditions. With the `route` directive, the mutual exclusivity of the two handlers is implicit because they are both terminal handlers.
</aside> </aside>
And now `file_server` will be chained in before `redir` because the order is taken literally. And now `file_server` will be chained in before `redir` because the order is taken literally.
## Similar directives ## Similar directives
There are other directives that can wrap HTTP handler directives, but each has its use depending on the behavior you want to convey: There are other directives that can wrap HTTP handler directives, but each has its use depending on the behavior you want to convey:
- [`handle`](handle) wraps other directives like `route` does, but with two distinctions: 1) handle blocks are mutually exclusive to each other, and 2) directives within a handle are [re-ordered](/docs/caddyfile/directives#directive-order) normally. - [`handle`](handle) wraps other directives like `route` does, but with two distinctions: 1) handle blocks are mutually exclusive to each other, and 2) directives within a handle are [re-ordered](/docs/caddyfile/directives#directive-order) normally.
- [`handle_path`](handle_path) does the same as `handle`, but it strips a prefix from the request before running its handlers. - [`handle_path`](handle_path) does the same as `handle`, but it strips a prefix from the request before running its handlers.
- [`handle_errors`](handle_errors) is like `handle`, but is only invoked when Caddy encounters an error during request handling. - [`handle_errors`](handle_errors) is like `handle`, but is only invoked when Caddy encounters an error during request handling.
## Examples ## Examples
Strip `/api` prefix from request path just before proxying all API requests to a backend: Proxy requests to `/api` as-is, and rewrite all other requests based on whether they match a file on disk, otherwise `/index.html`. Then that file is served.
```caddy-d Since [`try_files`](try_files) has a higher directive order than [`reverse_proxy`](reverse_proxy), then it would normally get sorted higher and run first; this would cause the API requests to all get rewritten to `/index.html` and fail to match `/api*`, so none of them would get proxied and instead would result in a `404` from [`file_server`](file_server). Wrapping it all in a `route` ensures that `reverse_proxy` always runs first, before the request is rewritten.
route /api/* {
uri strip_prefix /api ```caddy
reverse_proxy localhost:9000 example.com {
root * /srv
route {
reverse_proxy /api* localhost:9000
try_files {path} /index.html
file_server
}
} }
``` ```
<aside class="tip">
This is not the only solution to this problem. You could also use a pair of [`handle`](handle) blocks, with the first matching `/api*` to `reverse_proxy`, and the second acting as a fallback and serving the files. See [this example](/docs/caddyfile/patterns#single-page-apps-spas) of an SPA.
</aside>

View file

@ -20,8 +20,15 @@ skip_log [<matcher>]
Skip access logging for static files stored in a subpath: Skip access logging for static files stored in a subpath:
```caddy-d ```caddy
skip_log /static* example.com {
root * /srv
log
skip_log /static*
file_server
}
``` ```

View file

@ -17,17 +17,43 @@ templates [<matcher>] {
} }
``` ```
- **mime** are the MIME types the templates middleware will act on; any responses that do not have a qualifying Content-Type will not be evaluated as templates. Default: `text/html text/plain`. - **mime** are the MIME types the templates middleware will act on; any responses that do not have a qualifying `Content-Type` will not be evaluated as templates.
- **between** are the opening and closing delimiters for template actions. Default: `{{printf "{{ }}"}}`. You can change them if they interfere with the rest of your document.
Default: `text/html text/plain`.
- **between** are the opening and closing delimiters for template actions. You can change them if they interfere with the rest of your document.
Default: `{{printf "{{ }}"}}`.
- **root** is the site root, when using functions that access the file system. - **root** is the site root, when using functions that access the file system.
Defaults to the site root set by the [`root`](root) directive, or the current working directory if not set.
Documentation for the built-in template functions can be found in [templates module](/docs/modules/http.handlers.templates#docs).
## Examples ## Examples
Enable templates on all requests: For a complete example of a site using templates to serve markdown, take a look at the source for [this very website](https://github.com/caddyserver/website)! Specifically, take a look at the [`Caddyfile`](https://github.com/caddyserver/website/blob/master/Caddyfile) and [`src/docs/index.html`](https://github.com/caddyserver/website/blob/master/src/docs/index.html).
```caddy-d Enable templates for a static site:
templates
```caddy
example.com {
root * /srv
templates
file_server
}
``` ```
For a complete example of a site using templates to serve markdown, take a look at the source for [this very website](https://github.com/caddyserver/website)! Specifically, take a look at the [`Caddyfile`](https://github.com/caddyserver/website/blob/master/Caddyfile) and [`src/docs/index.html`](https://github.com/caddyserver/website/blob/master/src/docs/index.html). To serve a simple static response using a template, make sure to set `Content-Type`:
```caddy
example.com {
header Content-Type text/plain
templates
respond "Current year is: {{printf "{{"}}now | date "2006"{{printf "}}"}}"
}
```

View file

@ -168,7 +168,7 @@ These issuers come standard with the `tls` directive:
Obtains certificates using the ACME protocol. Note that `acme` is a default issuer (using Let's Encrypt), so configuring it explicitly is usually unnecessary. Obtains certificates using the ACME protocol. Note that `acme` is a default issuer (using Let's Encrypt), so configuring it explicitly is usually unnecessary.
```caddy ```caddy-d
... acme [<directory_url>] { ... acme [<directory_url>] {
dir <directory_url> dir <directory_url>
test_dir <test_directory_url> test_dir <test_directory_url>
@ -253,7 +253,7 @@ Obtains certificates using the ACME protocol. Note that `acme` is a default issu
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 the ACME protocol, specifically with ZeroSSL. Note that `zerossl` is a default issuer, so configuring it explicitly is usually unnecessary.
```caddy ```caddy-d
... zerossl [<api_key>] { ... zerossl [<api_key>] {
... ...
} }
@ -269,7 +269,7 @@ When explicitly configuring `zerossl`, configuring an `email` is required so tha
Obtains certificates from an internal certificate authority. Obtains certificates from an internal certificate authority.
```caddy ```caddy-d
... internal { ... internal {
ca <name> ca <name>
lifetime <duration> lifetime <duration>
@ -324,66 +324,82 @@ get_certificate http <url>
## Examples ## Examples
Use a custom certificate and key: Use a custom certificate and key. The certificate should have [SANs](https://en.wikipedia.org/wiki/Subject_Alternative_Name) that match the site address:
```caddy-d ```caddy
tls cert.pem key.pem example.com {
tls cert.pem key.pem
}
``` ```
Use locally-trusted certificates for all hosts on the current site block, rather than public certificates via ACME / Let's Encrypt (useful in dev environments): Use [locally-trusted](/docs/automatic-https#local-https) certificates for all hosts on the current site block, rather than public certificates via ACME / Let's Encrypt (useful in dev environments):
```caddy-d ```caddy
tls internal example.com {
tls internal
}
``` ```
Use locally-trusted certificates, but managed on-demand instead of in the background: Use locally-trusted certificates, but managed [On-Demand](/docs/automatic-https#on-demand-tls) instead of in the background. This allows you to point any domain at your Caddy instance and have it automatically provision a certificate for you. This SHOULD NOT be used if your Caddy instance is publicly accessible, since an attacker could use it to exhaust your server's resources:
```caddy-d ```caddy
tls internal { https:// {
on_demand tls internal {
on_demand
}
} }
``` ```
Use custom options for the internal CA (cannot use the `tls internal` shortcut): Use custom options for the internal CA (cannot use the `tls internal` shortcut):
```caddy-d ```caddy
tls { example.com {
issuer internal { tls {
ca foo issuer internal {
ca foo
}
} }
} }
``` ```
Specify an email address for your ACME account (but if only one email is used for all sites, we recommend the `email` [global option](/docs/caddyfile/options) instead): Specify an email address for your ACME account (but if only one email is used for all sites, we recommend the `email` [global option](/docs/caddyfile/options) instead):
```caddy-d ```caddy
tls your@email.com example.com {
``` tls your@email.com
Enable the DNS challenge for a domain managed on Cloudflare with account credentials in an environment variable:
```caddy-d
tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
} }
``` ```
Get the certificate chain via HTTP, instead of having Caddy manage it: Enable the DNS challenge for a domain managed on Cloudflare with account credentials in an environment variable. This unlocks wildcard certificate support, which requires DNS validation:
```caddy-d ```caddy
tls { *.example.com {
get_certificate http http://localhost:9007/certs tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
}
```
Get the certificate chain via HTTP, instead of having Caddy manage it. Note that [`get_certificate`](#certificate-managers) implies [`on_demand`](#on_demand) is enabled, fetching certificates using a module instead of triggering ACME issuance:
```caddy
https:// {
tls {
get_certificate http http://localhost:9007/certs
}
} }
``` ```
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 `trusted_ca_cert_file`
```caddy-d ```caddy
tls { example.com {
client_auth { tls {
mode require_and_verify client_auth {
trusted_ca_cert_file ../caddy.ca.cer mode require_and_verify
trusted_ca_cert_file ../root.ca.cer trusted_ca_cert_file ../caddy.ca.cer
trusted_ca_cert_file ../root.ca.cer
}
} }
} }
``` ```

View file

@ -4,12 +4,10 @@ title: tracing (Caddyfile directive)
# tracing # tracing
It provides integration with OpenTelemetry tracing facilities. Enables integration with OpenTelemetry tracing facilities, using [`opentelemetry-go` <img src="/old/resources/images/external-link.svg" class="external-link">](https://github.com/open-telemetry/opentelemetry-go).
When enabled, it will propagate an existing trace context or initialize a new one. When enabled, it will propagate an existing trace context or initialize a new one.
It is based on [github.com/open-telemetry/opentelemetry-go](https://github.com/open-telemetry/opentelemetry-go).
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. 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 is added to [access logs](/docs/caddyfile/directives/log) as the standard `traceID` field.
@ -47,11 +45,20 @@ export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://my-otlp-endpoint:55680
Here is a **Caddyfile** example: Here is a **Caddyfile** example:
```caddy-d ```caddy
handle /example* { example.com {
tracing { handle /api* {
span example tracing {
span api
}
reverse_proxy localhost:8081
}
handle {
tracing {
span app
}
reverse_proxy localhost:8080
} }
reverse_proxy 127.0.0.1:8081
} }
``` ```

View file

@ -17,13 +17,16 @@ try_files <files...> {
- **<files...>** is the list of files to try. The URI path will be rewritten to the first one that exists. - **<files...>** is the list of files to try. The URI path will be rewritten to the first one that exists.
To match directories, append a trailing forward slash `/` to the path. All file paths are relative to the site [root](/docs/caddyfile/directives/root), and [glob patterns](https://pkg.go.dev/path/filepath#Match) will be expanded. To match directories, append a trailing forward slash `/` to the path. All file paths are relative to the site [root](root), and [glob patterns](https://pkg.go.dev/path/filepath#Match) will be expanded.
Each argument may also contain a query string, in which case the query string will also be changed if it matches that particular file. Each argument may also contain a query string, in which case the query string will also be changed if it matches that particular file.
If the `try_policy` is `first_exist` (the default), then the last item in the list may be a number prefixed by `=` (e.g. `=404`), which as a fallback, will emit an error with that code; the error can be caught and handled with [`handle_errors`](/docs/caddyfile/directives/handle_errors). If the `try_policy` is `first_exist` (the default), then the last item in the list may be a number prefixed by `=` (e.g. `=404`), which as a fallback, will emit an error with that code; the error can be caught and handled with [`handle_errors`](handle_errors).
- **policy** is the policy for choosing the file among the list of files.
Default: `first_exist`
- **policy** is the policy for choosing the file among the list of files. Default: `first_exist`
## Expanded form ## Expanded form
@ -40,15 +43,16 @@ Note that this directive does not accept a matcher token. If you need more compl
See the [`file` matcher](/docs/caddyfile/matchers#file) for more details. See the [`file` matcher](/docs/caddyfile/matchers#file) for more details.
## Examples ## Examples
If the request does not match any static files, rewrite to an index/router file: If the request does not match any static files, rewrite to your PHP index/router entrypoint:
```caddy-d ```caddy-d
try_files {path} /index.php try_files {path} /index.php
``` ```
Same, but adding the original path to the query string: Same, but adding the original path to the query string (required by some legacy PHP apps):
```caddy-d ```caddy-d
try_files {path} /index.php?{query}&p={path} try_files {path} /index.php?{query}&p={path}
@ -60,7 +64,7 @@ Same, but also match directories:
try_files {path} {path}/ /index.php?{query}&p={path} try_files {path} {path}/ /index.php?{query}&p={path}
``` ```
Attempt to rewrite to a file or directory if it exists, otherwise emit a 404 error (which can be caught and handled with [`handle_errors`](/docs/caddyfile/directives/handle_errors)): Attempt to rewrite to a file or directory if it exists, otherwise emit a 404 error (which can be caught and handled with [`handle_errors`](handle_errors)):
```caddy-d ```caddy-d
try_files {path} {path}/ =404 try_files {path} {path}/ =404

View file

@ -21,12 +21,19 @@ uri [<matcher>] path_regexp <target> <replacement>
``` ```
- 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. - **path_regexp** performs a regular expression replacement on the path portion of the URI.
- **&lt;target&gt;** 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. - **&lt;target&gt;** 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.
- **&lt;replacement&gt;** 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. - **&lt;replacement&gt;** 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.
- **&lt;limit&gt;** is an optional limit to the maximum number of replacements (only valid with `replace`). - **&lt;limit&gt;** is an optional limit to the maximum number of replacements (only valid with `replace`).
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`. 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`.
@ -38,6 +45,7 @@ The URI path is cleaned of directory traversal dots before modifications. Additi
Some other directives can also manipulate the request URI. Some other directives can also manipulate the request URI.
- [`rewrite`](rewrite) changes the entire path and query to a new value instead of partially changing the value. - [`rewrite`](rewrite) changes the entire path and query to a new value instead of partially changing the value.
- [`handle_path`](handle_path) does the same as [`handle`](handle), but it strips a prefix from the request before running its handlers. Can be used instead of `uri strip_prefix` to eliminate one extra line of configuration in many cases. - [`handle_path`](handle_path) does the same as [`handle`](handle), but it strips a prefix from the request before running its handlers. Can be used instead of `uri strip_prefix` to eliminate one extra line of configuration in many cases.

View file

@ -27,11 +27,13 @@ vars [<matcher>] [<name> <value>] {
To set a single variable, the value being conditional based on the request path, then responding with the value: To set a single variable, the value being conditional based on the request path, then responding with the value:
```caddy-d ```caddy
vars /foo* isFoo "yep" example.com {
vars isFoo "nope" vars /foo* isFoo "yep"
vars isFoo "nope"
respond {vars.isFoo} respond {vars.isFoo}
}
``` ```
To set multiple variables, each converted to the appropriate scalar type: To set multiple variables, each converted to the appropriate scalar type:

View file

@ -140,19 +140,25 @@ or, if there is only one matcher in the set, you can put it on the same line:
@name ... @name ...
``` ```
Then you can use the matcher like so: `@name` Then you can use the matcher like so, by specifying it as the first argument to a directive:
For example:
```caddy-d ```caddy-d
@websockets { directive @name
header Connection *Upgrade*
header Upgrade websocket
}
reverse_proxy @websockets localhost:6001
``` ```
This proxies only the requests that have a header field named "Connection" containing the word "Upgrade", and another field named "Upgrade" with a value of "websocket". 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`:
```caddy
example.com {
@websockets {
header Connection *Upgrade*
header Upgrade websocket
}
reverse_proxy @websockets localhost:6001
reverse_proxy localhost:8080
}
```
If the matcher set consists of only one matcher, a one-liner syntax also works: If the matcher set consists of only one matcher, a one-liner syntax also works:
@ -161,19 +167,19 @@ If the matcher set consists of only one matcher, a one-liner syntax also works:
reverse_proxy @post localhost:6001 reverse_proxy @post localhost:6001
``` ```
As a special case, the [`expression` matcher](#expression) may be used without specifying its name as long as a single quoted argument (the CEL expression itself) follows the matcher name: As a special case, the [`expression` matcher](#expression) may be used without specifying its name as long as one [quoted](/docs/caddyfile/concepts#tokens-and-quotes) argument (the CEL expression itself) follows the matcher name:
```caddy-d ```caddy-d
@notFound `{err.status_code} == 404` @not-found `{err.status_code} == 404`
``` ```
Like directives, named matcher definitions must go inside the site blocks that use them. Like directives, named matcher definitions must go inside the [site blocks](/docs/caddyfile/concepts#structure) that use them.
A named matcher definition constitutes a _matcher set_. Matchers in a set are AND'ed together; i.e. all must match. For example, if you have both a `header` and `path` matcher in the set, both must match. A named matcher definition constitutes a _matcher set_. Matchers in a set are AND'ed together; i.e. all must match. For example, if you have both a [`header`](#header) and [`path`](#path) matcher in the set, both must match.
Multiple matchers of the same type may be unioned (e.g. multiple `path` matchers in the same set) using boolean algebra (AND/OR), as described in their respective sections below. Multiple matchers of the same type may be merged (e.g. multiple [`path`](#path) matchers in the same set) using boolean algebra (AND/OR), as described in their respective sections below.
For more complex boolean matching logic, it's recommended to the [`expression` matcher](#expression) to write a CEL expression, which supports _and_ `&&`, _or_ `||`, and _parentheses_ `( )`. For more complex boolean matching logic, it's recommended to the [`expression` matcher](#expression) to write a CEL expression, which supports **and** `&&`, **or** `||`, and **parentheses** `( )`.
@ -208,14 +214,24 @@ There can be multiple `client_ip` matchers per named matcher, and their ranges w
Match requests from private IPv4 addresses: Match requests from private IPv4 addresses:
```caddy-d ```caddy-d
client_ip 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 127.0.0.1/8 @private-ipv4 client_ip 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 127.0.0.1/8
``` ```
This matcher is commonly paired with the [`not`](#not) matcher to invert the match. For example, to abort all connections from _public_ IPv4 and IPv6 addresses (which is the inverse of all private ranges): This matcher is commonly paired with the [`not`](#not) matcher to invert the match. For example, to abort all connections from _public_ IPv4 and IPv6 addresses (which is the inverse of all private ranges):
```caddy
example.com {
@denied not client_ip private_ranges
abort @denied
respond "Hello, you must be from a private network!"
}
```
In a [CEL expression](#expression), it would look like this:
```caddy-d ```caddy-d
@denied not client_ip private_ranges @my-friends `client_ip('12.23.34.45', '23.34.45.56')`
abort @denied
``` ```
@ -230,9 +246,9 @@ By any [CEL (Common Expression Language)](https://github.com/google/cel-spec) ex
Caddy [placeholders](/docs/conventions#placeholders) (or [Caddyfile shorthands](/docs/caddyfile/concepts#placeholders)) may be used in these CEL expressions, as they are preprocessed and converted to regular CEL function calls before being interpreted by the CEL environment. Caddy [placeholders](/docs/conventions#placeholders) (or [Caddyfile shorthands](/docs/caddyfile/concepts#placeholders)) may be used in these CEL expressions, as they are preprocessed and converted to regular CEL function calls before being interpreted by the CEL environment.
Since v2.5.2, most other request matchers can also be used in expressions as functions, which allows for more flexibility for boolean logic than outside expressions. See the documentation for each matcher for the supported syntax within CEL expressions. Most other request matchers can also be used in expressions as functions, which allows for more flexibility for boolean logic than outside expressions. See the documentation for each matcher for the supported syntax within CEL expressions.
For convenience, the matcher name may be omitted if defining a named matcher that consists solely of a CEL expression. This reads quite nicely: For convenience, the matcher name may be omitted if defining a named matcher that consists solely of a CEL expression. The CEL expression must be [quoted](/docs/caddyfile/concepts#tokens-and-quotes) (backticks or heredocs recommended). This reads quite nicely:
```caddy-d ```caddy-d
@mutable `{method}.startsWith("P")` @mutable `{method}.startsWith("P")`
@ -245,19 +261,35 @@ In this case the CEL matcher is assumed.
Match requests whose methods start with `P`, e.g. `PUT` or `POST`: Match requests whose methods start with `P`, e.g. `PUT` or `POST`:
```caddy-d ```caddy-d
expression {method}.startsWith("P") @methods expression {method}.startsWith("P")
``` ```
Match requests where handler returned error status code `404`, would be used in conjunction with the [`handle_errors` directive](/docs/caddyfile/directives/handle_errors): Match requests where handler returned error status code `404`, would be used in conjunction with the [`handle_errors` directive](/docs/caddyfile/directives/handle_errors):
```caddy-d ```caddy-d
expression {err.status_code} == 404 @404 expression {err.status_code} == 404
``` ```
Match requests where the path matches one of two different regular expressions; this is only possible to write using an expression, because the [`path_regexp`](#path-regexp) matcher can normally only exist once per named matcher: Match requests where the path matches one of two different regular expressions; this is only possible to write using an expression, because the [`path_regexp`](#path-regexp) matcher can normally only exist once per named matcher:
```caddy-d ```caddy-d
expression path_regexp('^/user/(\w*)') || path_regexp('^/(\w*)') @user expression path_regexp('^/user/(\w*)') || path_regexp('^/(\w*)')
```
Or the same, omitting the matcher name, and wrapping in [backticks](/docs/caddyfile/concepts#tokens-and-quotes) so it's parsed as a single token:
```caddy-d
@user `path_regexp('^/user/(\w*)') || path_regexp('^/(\w*)')`
```
You may use [heredoc syntax](/docs/caddyfile/concepts#heredocs) to write multi-line CEL expressions:
```caddy-d
@api <<CEL
{method} == "GET"
&& {path}.startsWith("/api/")
CEL
respond @api "Hello, API!"
``` ```
@ -268,7 +300,7 @@ expression path_regexp('^/user/(\w*)') || path_regexp('^/(\w*)')
file { file {
root <path> root <path>
try_files <files...> try_files <files...>
try_policy first_exist|smallest_size|largest_size|most_recent_modified try_policy first_exist|smallest_size|largest_size|most_recently_modified
split_path <delims...> split_path <delims...>
} }
file <files...> file <files...>
@ -276,7 +308,7 @@ file <files...>
expression `file({ expression `file({
'root': '<path>', 'root': '<path>',
'try_files': ['<files...>'], 'try_files': ['<files...>'],
'try_policy': 'first_exist|smallest_size|largest_size|most_recent_modified', 'try_policy': 'first_exist|smallest_size|largest_size|most_recently_modified',
'split_path': ['<delims...>'] 'split_path': ['<delims...>']
})` })`
expression file('<files...>') expression file('<files...>')
@ -302,7 +334,7 @@ By files.
- `largest_size` chooses the file with the largest size. - `largest_size` chooses the file with the largest size.
- `most_recent_modified` chooses the file that was most recently modified. - `most_recently_modified` chooses the file that was most recently modified.
- `split_path` will cause the path to be split at the first delimiter in the list that is found in each filepath to try. For each split value, the left-hand side of the split including the delimiter itself will be the filepath that is tried. For example, `/remote.php/dav/` using a delimiter of `.php` would try the file `/remote.php`. Each delimiter must appear at the end of a URI path component in order to be used as a split delimiter. This is a niche setting and is mostly used when serving PHP sites. - `split_path` will cause the path to be split at the first delimiter in the list that is found in each filepath to try. For each split value, the left-hand side of the split including the delimiter itself will be the filepath that is tried. For example, `/remote.php/dav/` using a delimiter of `.php` would try the file `/remote.php`. Each delimiter must appear at the end of a URI path component in order to be used as a split delimiter. This is a niche setting and is mostly used when serving PHP sites.
@ -335,13 +367,13 @@ Upon matching, four new placeholders will be made available:
Match requests where the path is a file that exists: Match requests where the path is a file that exists:
```caddy-d ```caddy-d
file @file file
``` ```
Match requests where the path followed by `.html` is a file that exists, or if not, where the path is a file that exists: Match requests where the path followed by `.html` is a file that exists, or if not, where the path is a file that exists:
```caddy-d ```caddy-d
file { @html file {
try_files {path}.html {path} try_files {path}.html {path}
} }
``` ```
@ -349,9 +381,16 @@ file {
Same as above, except using the one-line shortcut, and falling back to emitting a 404 error if a file is not found: Same as above, except using the one-line shortcut, and falling back to emitting a 404 error if a file is not found:
```caddy-d ```caddy-d
file {path}.html {path} =404 @html-or-error file {path}.html {path} =404
``` ```
Some more examples using [CEL expressions](#expression). Keep in mind that placeholders are preprocessed and converted to regular CEL function calls before being interpreted by the CEL environment, so concatenation is used here. Additionally, the long-form must be used if concatenating with placeholders due to current parsing limitations:
```caddy-d
@file `file()`
@first `file({'try_files': [{path}, {path} + '/', 'index.html']})`
@smallest `file({'try_policy': 'smallest_size', 'try_files': ['a.txt', 'b.txt']})`
```
--- ---
@ -382,10 +421,11 @@ Note that header fields may be repeated and have different values. Backend appli
Match requests with the `Connection` header containing `Upgrade`: Match requests with the `Connection` header containing `Upgrade`:
```caddy-d ```caddy-d
header Connection *Upgrade* @upgrade header Connection *Upgrade*
``` ```
Match requests with the `Foo` header containing `bar` OR `baz`: Match requests with the `Foo` header containing `bar` OR `baz`:
```caddy-d ```caddy-d
@foo { @foo {
header Foo bar header Foo bar
@ -394,11 +434,13 @@ Match requests with the `Foo` header containing `bar` OR `baz`:
``` ```
Match requests that do not have the `Foo` header field at all: Match requests that do not have the `Foo` header field at all:
```caddy-d ```caddy-d
@not_foo header !Foo @not_foo header !Foo
``` ```
Match WebSocket requests by checking for the `Connection` header containing `Upgrade` and the `Upgrade` header equalling `websocket`, using an [expression](#expression) matcher: Using an [CEL expression](#expression), match WebSocket requests by checking for the `Connection` header containing `Upgrade` and the `Upgrade` header equalling `websocket`:
```caddy-d ```caddy-d
@websockets `header({'Connection':'*Upgrade*','Upgrade':'websocket'})` @websockets `header({'Connection':'*Upgrade*','Upgrade':'websocket'})`
``` ```
@ -425,7 +467,13 @@ Only one regular expression is supported per header field. Multiple different fi
Match requests where the Cookie header contains `login_` followed by a hex string, with a capture group that can be accessed with `{re.login.1}`. Match requests where the Cookie header contains `login_` followed by a hex string, with a capture group that can be accessed with `{re.login.1}`.
```caddy-d ```caddy-d
header_regexp login Cookie login_([a-f0-9]+) @login header_regexp login Cookie login_([a-f0-9]+)
```
Or the same, using a [CEL expression](#expression):
```caddy-d
@login `header_regexp('login', 'Cookie', 'login_([a-f0-9]+)')`
``` ```
@ -439,14 +487,30 @@ host <hosts...>
expression host('<hosts...>') expression host('<hosts...>')
``` ```
Matches request by the `Host` header field of the request. It is not common to use this in the Caddyfile, since most site blocks already indicate hosts in the address of the site. This matcher is mostly used in site blocks that don't define specific hostnames (like wildcard subdomains), but where hostname-specific logic is required. Matches request by the `Host` header field of the request.
Since most site blocks already indicate hosts in the address of the site, this matcher is more commonly used in site blocks that use a wildcard hostname (see the [wildcard certificates pattern](/docs/caddyfile/patterns#wildcard-certificates)), but where hostname-specific logic is required.
Multiple `host` matchers will be OR'ed together. Multiple `host` matchers will be OR'ed together.
#### Example: #### Example:
Matching one subdomain:
```caddy-d ```caddy-d
host sub.example.com @sub host sub.example.com
```
Matching the apex domain and a subdomain:
```caddy-d
@site host example.com www.example.com
```
Multiple subdomains using a [CEL expression](#expression):
```caddy-d
@app `host('app1.example.com', 'app2.example.com')`
``` ```
@ -469,13 +533,19 @@ Multiple `method` matchers will be OR'ed together.
Match requests with the `GET` method: Match requests with the `GET` method:
```caddy-d ```caddy-d
method GET @get method GET
``` ```
Match requests with the `PUT` or `DELETE` methods: Match requests with the `PUT` or `DELETE` methods:
```caddy-d ```caddy-d
method PUT DELETE @put-delete method PUT DELETE
```
Match read-only methods using a [CEL expression](#expression):
```caddy-d
@read `method('GET', 'HEAD', 'OPTIONS')`
``` ```
@ -484,14 +554,14 @@ method PUT DELETE
### not ### not
```caddy-d ```caddy-d
not <any other matcher> not <matcher>
``` ```
or, to negate multiple matchers which get AND'ed, open a block: or, to negate multiple matchers which get AND'ed, open a block:
```caddy-d ```caddy-d
not { not {
<any other matchers...> <matchers...>
} }
``` ```
@ -502,7 +572,9 @@ The results of the enclosed matchers will be negated.
Match requests with paths that do NOT begin with `/css/` OR `/js/`. Match requests with paths that do NOT begin with `/css/` OR `/js/`.
```caddy-d ```caddy-d
not path /css/* /js/* @not-assets {
not path /css/* /js/*
}
``` ```
Match requests WITH NEITHER: Match requests WITH NEITHER:
@ -512,8 +584,10 @@ Match requests WITH NEITHER:
i.e. must have none of these to match: i.e. must have none of these to match:
```caddy-d ```caddy-d
not path /api/* @with-neither {
not method POST not path /api/*
not method POST
}
``` ```
Match requests WITHOUT BOTH: Match requests WITHOUT BOTH:
@ -523,12 +597,27 @@ Match requests WITHOUT BOTH:
i.e. must have neither or either of these to match: i.e. must have neither or either of these to match:
```caddy-d ```caddy-d
not { @without-both {
path /api/* not {
method POST path /api/*
method POST
}
} }
``` ```
There's no [CEL expression](#expression) for this matcher, because you may use the `!` operator for negation instead. For example:
```caddy-d
@without-both `!path('/api*') && !method('POST')`
```
Which is the same as this, using parentheses:
```caddy-d
@without-both `!(path('/api*') || method('POST'))`
```
--- ---
@ -557,6 +646,32 @@ The special wildcard escape `%*` can also be used instead of `*` to leave its ma
Multiple paths will be OR'ed together. Multiple paths will be OR'ed together.
#### Examples:
Match multiple directories and their contents:
```caddy-d
@assets path /js/* /css/* /images/*
```
Match a specific file:
```caddy-d
@favicon path /favicon.ico
```
Match file extensions:
```caddy-d
@extensions path *.js *.css
```
With a [CEL expression](#expression):
```caddy-d
@assets `path('/js/*', '/css/*', '/images/*')`
```
--- ---
@ -582,7 +697,13 @@ There can only be one `path_regexp` pattern per named matcher.
Match requests where the path ends a 6 character hex string followed by `.css` or `.js` as the file extension, with capture groups that can be accessed with `{re.static.1}` and `{re.static.2}` for each part enclosed in `( )`, respectively: Match requests where the path ends a 6 character hex string followed by `.css` or `.js` as the file extension, with capture groups that can be accessed with `{re.static.1}` and `{re.static.2}` for each part enclosed in `( )`, respectively:
```caddy-d ```caddy-d
path_regexp static \.([a-f0-9]{6})\.(css|js)$ @static path_regexp static \.([a-f0-9]{6})\.(css|js)$
```
Or the same, using a [CEL expression](#expression), also validating that the [`file`](#file) exists on disk:
```caddy-d
@static `path_regexp('static', '\.([a-f0-9]{6})\.(css|js)$') && file()`
``` ```
@ -593,13 +714,27 @@ path_regexp static \.([a-f0-9]{6})\.(css|js)$
```caddy-d ```caddy-d
protocol http|https|grpc|http/<version>[+] protocol http|https|grpc|http/<version>[+]
expression protocol('http|https|grpc') expression protocol('http|https|grpc|http/<version>[+]')
``` ```
By request protocol. A broad protocol name such as `http`, `https`, or `grpc` can be used; or specific or minimum HTTP versions such as `http/1.1` or `http/2+`. By request protocol. A broad protocol name such as `http`, `https`, or `grpc` can be used; or specific or minimum HTTP versions such as `http/1.1` or `http/2+`.
There can only be one `protocol` matcher per named matcher. There can only be one `protocol` matcher per named matcher.
#### Example:
Match requests using HTTP/2:
```caddy-d
@http2 protocol http/2+
```
With a [CEL expression](#expression):
```caddy-d
@http2 `protocol('http/2+')`
```
--- ---
@ -619,12 +754,25 @@ There can be multiple `query` matchers per named matcher, and pairs with the sam
Illegal query strings (bad syntax, unescaped semicolons, etc.) will fail to parse and thus will not match. Illegal query strings (bad syntax, unescaped semicolons, etc.) will fail to parse and thus will not match.
**NOTE:** Query string parameters are arrays, not singular values. This is because repeated keys are valid in query strings, and each one may have a different value. This matcher will match for a key if any one of its configured values is assigned in the query string. Backend applications using query strings MUST take into consideration that query string values are arrays and can have multiple values. **NOTE:** Query string parameters are arrays, not singular values. This is because repeated keys are valid in query strings, and each one may have a different value. This matcher will match for a key if any one of its configured values is assigned in the query string. Backend applications using query strings MUST take into consideration that query string values are arrays and can have multiple values.
#### Example: #### Example:
Match requests with a `sort` query parameter with the value `asc`: Match a `q` query parameter with any value:
```caddy-d ```caddy-d
query sort=asc @search query q=*
```
Match a `sort` query parameter with the value `asc` or `desc`:
```caddy-d
@sorted query sort=asc sort=desc
```
Matching both `q` and `sort`, with a [CEL expression](#expression):
```caddy-d
@search-sort `query({'sort': ['asc', 'desc'], 'q': '*'})`
``` ```
@ -652,14 +800,24 @@ There can be multiple `remote_ip` matchers per named matcher, and their ranges w
Match requests from private IPv4 addresses: Match requests from private IPv4 addresses:
```caddy-d ```caddy-d
remote_ip 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 127.0.0.1/8 @private-ipv4 remote_ip 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 127.0.0.1/8
``` ```
This matcher is commonly paired with the [`not`](#not) matcher to invert the match. For example, to abort all connections from _public_ IPv4 and IPv6 addresses (which is the inverse of all private ranges): This matcher is commonly paired with the [`not`](#not) matcher to invert the match. For example, to abort all connections from _public_ IPv4 and IPv6 addresses (which is the inverse of all private ranges):
```caddy
example.com {
@denied not remote_ip private_ranges
abort @denied
respond "Hello, you must be from a private network!"
}
```
In a [CEL expression](#expression), it would look like this:
```caddy-d ```caddy-d
@denied not remote_ip private_ranges @my-friends `remote_ip('12.23.34.45', '23.34.45.56')`
abort @denied
``` ```

View file

@ -33,6 +33,7 @@ window.$(function() {
}); });
</script> </script>
# Global options # Global options
The Caddyfile has a way for you to specify options that apply globally. Some options act as default values; others customize HTTP servers and don't apply to just one particular site; while yet others customize the behavior of the Caddyfile [adapter](/docs/config-adapters). The Caddyfile has a way for you to specify options that apply globally. Some options act as default values; others customize HTTP servers and don't apply to just one particular site; while yet others customize the behavior of the Caddyfile [adapter](/docs/config-adapters).
@ -61,8 +62,6 @@ Possible options are (click on each option to jump to its documentation):
<options...> <options...>
} }
storage_clean_interval <duration> storage_clean_interval <duration>
renew_interval <duration>
ocsp_interval <duration>
admin off|<addr> { admin off|<addr> {
origins <origins...> origins <origins...>
enforce_origin enforce_origin
@ -96,6 +95,8 @@ Possible options are (click on each option to jump to its documentation):
} }
key_type ed25519|p256|p384|rsa2048|rsa4096 key_type ed25519|p256|p384|rsa2048|rsa4096
cert_issuer <name> ... cert_issuer <name> ...
renew_interval <duration>
ocsp_interval <duration>
ocsp_stapling off ocsp_stapling off
preferred_chains [smallest] { preferred_chains [smallest] {
root_common_name <common_names...> root_common_name <common_names...>
@ -165,11 +166,19 @@ Enables debug mode, which sets the log level to `DEBUG` for the [default logger]
##### `http_port` ##### `http_port`
The port for the server to use for HTTP. For internal use only; does not change the HTTP port for clients. Default: `80` The port for the server to use for HTTP.
**For internal use only**; does not change the HTTP port for clients. This is typically used if within your internal network, you needed to port forward `80` to a different port (e.g. `8080`) before it reaches Caddy, for routing purposes.
Default: `80`
##### `https_port` ##### `https_port`
The port for the server to use for HTTPS. For internal use only; does not change the HTTPS port for clients. Default: `443` The port for the server to use for HTTPS.
**For internal use only**; does not change the HTTPS port for clients. This is typically used if within your internal network, you needed to port forward `443` to a different port (e.g. `8443`) before it reaches Caddy, for routing purposes.
Default: `443`
##### `default_bind` ##### `default_bind`
@ -181,6 +190,12 @@ Keep in mind that this will only apply to servers which are generated by the Cad
</aside> </aside>
```caddy
{
default_bind 10.0.0.1
}
```
##### `order` ##### `order`
@ -188,8 +203,10 @@ Assigns an order to HTTP handler directive(s). As HTTP handlers execute in a seq
For example, to use the [`replace-response` plugin](https://github.com/caddyserver/replace-response), you'd want to make sure its directive is ordered after `encode` so that it can perform replacements before the response is encoded (because responses flow up the handler chain, not down): For example, to use the [`replace-response` plugin](https://github.com/caddyserver/replace-response), you'd want to make sure its directive is ordered after `encode` so that it can perform replacements before the response is encoded (because responses flow up the handler chain, not down):
```caddy-d ```caddy
order replace after encode {
order replace after encode
}
``` ```
@ -198,76 +215,186 @@ Configures Caddy's storage mechanism. The default is [`file_system`](/docs/json/
For example, to change the file system's storage location: For example, to change the file system's storage location:
```caddy-d ```caddy
storage file_system /path/to/custom/location {
storage file_system /path/to/custom/location
}
``` ```
Customizing the storage module is typically needed when syncing Caddy's storage across multiple instances of Caddy to make sure they all use the same certificates and keys. See the [Automatic HTTPS section on storage](/docs/automatic-https#storage) for more details. Customizing the storage module is typically needed when syncing Caddy's storage across multiple instances of Caddy to make sure they all use the same certificates and keys. See the [Automatic HTTPS section on storage](/docs/automatic-https#storage) for more details.
##### `storage_clean_interval` ##### `storage_clean_interval`
How often to scan storage units for old or expired assets and remove them. These scans exert lots of reads (and list operations) on the storage module, so choose a longer interval for large deployments. Accepts [duration values](/docs/conventions#durations). Default: `24h`. How often to scan storage units for old or expired assets and remove them. These scans exert lots of reads (and list operations) on the storage module, so choose a longer interval for large deployments. Accepts [duration values](/docs/conventions#durations).
Storage will always be cleaned when the process first starts. Then, a new cleaning will be started this duration after the previous cleaning started if the previous cleaning finished in less than half the time of this interval (otherwise next start will be skipped). Storage will always be cleaned when the process first starts. Then, a new cleaning will be started this duration after the previous cleaning started if the previous cleaning finished in less than half the time of this interval (otherwise next start will be skipped).
Default: `24h`
##### `renew_interval` ```caddy
How often to scan all loaded, managed certificates for expiration, and trigger renewal if expired. Default: `10m`. {
storage_clean_interval 7d
}
```
##### `ocsp_interval`
How often to check if OCSP staples need updating. Default: `1h`.
##### `admin` ##### `admin`
Customizes the [admin API endpoint](/docs/api). Accepts placeholders. If `off`, then the admin endpoint will be disabled. If disabled, config changes will be impossible without stopping and starting the server. Remember to use the `--address` CLI flag to specify the current admin endpoint when changing this value if the currently-running admin endpoint is not at the default address. Customizes the [admin API endpoint](/docs/api). Accepts placeholders. Takes [network addresses](/docs/conventions#network-addresses).
- **origins** configures the list of remotes/origins that are allowed to connect to the endpoint. Default: `localhost:2019`, unless the `CADDY_ADMIN` environment variable is set.
If set to `off`, then the admin endpoint will be disabled. When disabled, **config changes will be impossible** without stopping and starting the server, since the [`caddy reload` command](/docs/command-line#caddy-reload) uses the admin API to push the new config to the running server.
Remember to use the `--address` CLI flag with compatible [commands](/docs/command-line) to specify the current admin endpoint, if the address of the running server was changed from the default.
Also supports these sub-options:
- **origins** configures the list of origins that are allowed to connect to the endpoint.
A default is intelligently chosen:
- if the listen address is loopback (e.g. `localhost` or a loopback IP, or a unix socket) then the allowed origins are `localhost`, `::1` and `127.0.0.1`, joined with the listen address port (so `localhost:2019` is a valid origin).
- if the listen address is not loopback, then the allowed origin is the same as the listen address.
If the listen address host is not a wildcard interface (wildcards include: empty string, or `0.0.0.0`, or `[::]`), then `Host` header enforcement is performed. Effectively, this means that by default, the `Host` header is validated to be in `origins`, since the interface is `localhost`. But for an address like `:2020` which has a wildcard interface, `Host` header validation is not performed.
- **enforce_origin** enables enforcement of the `Origin` request header.
This is most useful when the listen address is a wildcard interface (since `Host` is not validated), and the admin API is exposed to the public internet. It enables CORS preflight checks and ensures that the `Origin` header is validated against the `origins` list. Only use this if you're running Caddy on your development machine and need to access the admin API from a web browser.
For example, to expose the admin API on a different port, on all interfaces — ⚠️ this port **should not be exposed publicly**, otherwise anyone can control your server; consider enabling origin enforcement if you need it to be public:
```caddy
{
admin :2020
}
```
To turn off the admin API — ⚠️ this makes **config reloads impossible** without stopping and starting the server:
```caddy
{
admin off
}
```
To use a [unix socket](/docs/conventions#network-addresses) for the admin API, allowing access control via file permissions:
```caddy
{
admin unix//run/caddy-admin.sock
}
```
To only allow requests having a matching `Origin` header:
```caddy
{
admin :2019 {
origins localhost
enforce_origin
}
}
```
- **enforce_origin** enables enforcement of the Origin header. (This is different from enforcing origins generally, which is always done.)
##### `persist_config` ##### `persist_config`
Controls whether the current JSON config should be persisted to the [configuration directory](/docs/conventions#configuration-directory), to avoid losing config changes performed via the admin API. Currently, only the `off` option is supported. By default, the config is persisted. Controls whether the current JSON config should be persisted to the [configuration directory](/docs/conventions#configuration-directory), to avoid losing config changes performed via the admin API. Currently, only the `off` option is supported. By default, the config is persisted.
```caddy
{
persist_config off
}
```
##### `log` ##### `log`
Configures named loggers. The name can be passed to indicate a specific logger for which to customize the behavior. If no name is specified, the behavior of the `default` logger is modified. Multiple loggers with different names can be configured by using the `log` multiple times. You can read more about the `default` logger and an explanation of [how logging works in Caddy](/docs/logging). Configures named loggers.
The name can be passed to indicate a specific logger for which to customize the behavior. If no name is specified, the behavior of the `default` logger is modified. You can read more about the `default` logger and an explanation of [how logging works in Caddy](/docs/logging).
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. 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.
- **output** configures where to write the logs. See the [`log` directive](/docs/caddyfile/directives/log#output-modules) for complete documentation. - **output** configures where to write the logs.
- **format** describes how to encode, or format, the logs. See the [`log` directive](/docs/caddyfile/directives/log#format-modules) for complete documentation.
- **level** is the minimum entry level to log. Possible values: `DEBUG`, `INFO`, `WARN`, `ERROR`, `PANIC`, `FATAL`. Default: `INFO`. See the [`log` directive](/docs/caddyfile/directives/log#output-modules) for complete documentation.
- **include** specifies the log names to be included in this logger. For example, to include only logs emitted by the admin API, you would include `admin.api`. By default, this list is empty (i.e. all logs are included).
- **exclude** specifies the log names to be excluded from this logger. For example, to exclude only HTTP access logs, you would exclude `http.log.access`. By default, this list is empty (i.e. no logs are excluded). - **format** describes how to encode, or format, the logs.
See the [`log` directive](/docs/caddyfile/directives/log#format-modules) for complete documentation.
- **level** is the minimum entry level to log.
Default: `INFO`.
Possible values: `DEBUG`, `INFO`, `WARN`, `ERROR`, and very rarely, `PANIC`, `FATAL`.
- **include** specifies the log names to be included in this logger.
By default, this list is empty (i.e. all logs are included).
For example, to include only logs emitted by the admin API, you would include `admin.api`.
- **exclude** specifies the log names to be excluded from this logger.
By default, this list is empty (i.e. no logs are excluded).
For example, to exclude only HTTP access logs, you would exclude `http.log.access`.
The logger names that `include` and `exclude` accept depend on the modules used, and easiest way to discover them is from prior logs. The logger names that `include` and `exclude` accept depend on the modules used, and easiest way to discover them is from prior logs.
Here is an example logging as json all http access logs and admin logs to stdout: Here is an example logging as json all http access logs and admin logs to stdout:
```caddy ```caddy
log default { {
output stdout log default {
format json output stdout
include http.log.access admin.api format json
include http.log.access admin.api
}
} }
``` ```
##### `grace_period` ##### `grace_period`
Defines the grace period for shutting down HTTP servers (i.e. during config changes or when Caddy is stopping). During the grace period, no new connections are accepted, idle connections are closed, and active connections are impatiently waited upon to finish their requests. If clients do not finish their requests within the grace period, the server will be forcefully terminated to allow the reload to complete and free up resources. Accepts [duration values](/docs/conventions#durations). By default, the grace period is eternal, which means connections are never forcefully closed. Defines the grace period for shutting down HTTP servers (i.e. during config changes or when Caddy is stopping).
During the grace period, no new connections are accepted, idle connections are closed, and active connections are impatiently waited upon to finish their requests. If clients do not finish their requests within the grace period, the server will be forcefully terminated to allow the reload to complete and free up resources. Accepts [duration values](/docs/conventions#durations).
By default, the grace period is eternal, which means connections are never forcefully closed.
```caddy
{
grace_period 10s
}
```
##### `shutdown_delay` ##### `shutdown_delay`
Defines a duration before the grace period during which a server that is going to be stopped continues to operate normally, except the `{http.shutting_down}` placeholder evaluates to `true` and `{http.time_until_shutdown}` gives the time until the grace period begins. This causes a delay if any server is being shut down as part of a config change and effectively schedules the change for a later time. It is useful for announcing to health checkers of this server's impending doom and to give time for a load balancer to move it out of the rotation; for example: Defines a [duration](/docs/conventions#durations)
_before_ the [grace period](#grace_period) during which a server that is going to be stopped continues to operate normally, except the `{http.shutting_down}` placeholder evaluates to `true` and `{http.time_until_shutdown}` gives the time until the grace period begins.
```caddy-d This causes a delay if any server is being shut down as part of a config change, and effectively schedules the change for a later time. It is useful for announcing to health checkers of this server's impending doom and to give time for a load balancer to move it out of the rotation; for example:
handle /health-check {
@goingDown vars {http.shutting_down} true ```caddy
respond @goingDown "Bye-bye in {http.time_until_shutdown}" 503 {
respond 200 shutdown_delay 30s
}
example.com {
handle /health-check {
@goingDown vars {http.shutting_down} true
respond @goingDown "Bye-bye in {http.time_until_shutdown}" 503
respond 200
}
handle {
respond "Hello, world!"
}
} }
``` ```
@ -291,10 +418,16 @@ There are a few modes to choose from:
This option does not affect Caddy's default protocol, which is always HTTPS, when a site address has a valid domain name. This means that `auto_https off` will not cause your site to be served over HTTP, it will only disable automatic certificate management and redirects. This option does not affect Caddy's default protocol, which is always HTTPS, when a site address has a valid domain name. This means that `auto_https off` will not cause your site to be served over HTTP, it will only disable automatic certificate management and redirects.
This means that if you wish to serve your site over HTTP, you should change your [site address](/docs/caddyfile/concepts#addresses) to be prefixed with `http://` or suffixed with `:80`. This means that if you wish to serve your site over HTTP, you should change your [site address](/docs/caddyfile/concepts#addresses) to be prefixed with `http://` or suffixed with `:80` (or the [`http_port` option](#http_port)).
</aside> </aside>
```caddy
{
auto_https disable_redirects
}
```
##### `email` ##### `email`
Your email address. Mainly used when creating an ACME account with your CA, and is highly recommended in case there are problems with your certificates. Your email address. Mainly used when creating an ACME account with your CA, and is highly recommended in case there are problems with your certificates.
@ -305,44 +438,112 @@ Keep in mind that Let's Encrypt may send you emails about your certificate neari
</aside> </aside>
```caddy
{
email admin@example.com
}
```
##### `default_sni` ##### `default_sni`
Sets a default TLS ServerName for when clients do not use SNI in their ClientHello. Sets a default TLS ServerName for when clients do not use SNI in their ClientHello.
```caddy
{
default_sni example.com
}
```
##### `fallback_sni` ##### `fallback_sni`
If configured, the fallback becomes the TLS ServerName in the ClientHello if the original ServerName doesn't match any certificates in the cache. The uses for this are very niche; typically if a client is a CDN and passes through the ServerName of the downstream handshake but can accept a certificate with the origin's hostname instead, then you would set this as your origin's hostname. Note that Caddy must be managing a certificate for this name. <i>⚠️ Experimental</i> ⚠️ <i>Experimental</i>
If configured, the fallback becomes the TLS ServerName in the ClientHello if the original ServerName doesn't match any certificates in the cache.
The uses for this are very niche; typically if a client is a CDN and passes through the ServerName of the downstream handshake but can accept a certificate with the origin's hostname instead, then you would set this as your origin's hostname. Note that Caddy must be managing a certificate for this name.
```caddy
{
fallback_sni example.com
}
```
##### `local_certs` ##### `local_certs`
Causes all certificates to be issued internally by default, rather than through a (public) ACME CA such as Let's Encrypt. This is useful in development environments. Causes **all** certificates to be issued internally by default, rather than through a (public) ACME CA such as Let's Encrypt. This is useful as a quick toggle in development environments.
```caddy
{
local_certs
}
```
##### `skip_install_trust` ##### `skip_install_trust`
Skips the attempts to install the local CA's root into the system trust store, as well as into Java and Mozilla Firefox trust stores. Skips the attempts to install the local CA's root into the system trust store, as well as into Java and Mozilla Firefox trust stores.
```caddy
{
skip_install_trust
}
```
##### `acme_ca` ##### `acme_ca`
Specifies the URL to the ACME CA's directory. It is strongly recommended to set this to Let's Encrypt's [staging endpoint <img src="/old/resources/images/external-link.svg" class="external-link">](https://letsencrypt.org/docs/staging-environment/) for testing or development. Default: ZeroSSL and Let's Encrypt's production endpoints. Specifies the URL to the ACME CA's directory. It is strongly recommended to set this to Let's Encrypt's [staging endpoint <img src="/old/resources/images/external-link.svg" class="external-link">](https://letsencrypt.org/docs/staging-environment/) for testing or development. Default: ZeroSSL and Let's Encrypt's production endpoints.
Note that a globally-configured ACME CA may not apply to all sites; see the [hostname requirements](/docs/automatic-https#hostname-requirements) for using the default ACME issuer(s). Note that a globally-configured ACME CA may not apply to all sites; see the [hostname requirements](/docs/automatic-https#hostname-requirements) for using the default ACME issuer(s).
```caddy
{
acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
}
```
##### `acme_ca_root` ##### `acme_ca_root`
Specifies a PEM file that contains a trusted root certificate for ACME CA endpoints, if not in the system trust store. Specifies a PEM file that contains a trusted root certificate for ACME CA endpoints, if not in the system trust store.
```caddy
{
acme_ca_root /path/to/ca/root.pem
}
```
##### `acme_eab` ##### `acme_eab`
Specifies an External Account Binding to use for all ACME transactions. Specifies an External Account Binding to use for all ACME transactions.
For example, with mock ZeroSSL credentials:
```caddy
{
acme_eab GD-VvWydSVFuss_GhBwYQQ MjXU3MH-Z0WQ7piMAnVsCpD1shgMiWx6ggPWiTmydgUaj7dWWWfQfA
}
```
##### `acme_dns` ##### `acme_dns`
Configures the ACME DNS challenge provider to use for all ACME transactions. The tokens following the name of the provider set up the provider the same as if specified in the [`tls` directive's `acme` issuer](/docs/caddyfile/directives/tls#acme). Configures the [ACME DNS challenge](/docs/automatic-https#dns-challenge) provider to use for all ACME transactions.
Requires a custom build of Caddy with a plugin for your DNS provider.
The tokens following the name of the provider set up the provider the same as if specified in the [`tls` directive's `acme` issuer](/docs/caddyfile/directives/tls#acme).
```caddy
{
acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
```
##### `on_demand_tls` ##### `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. 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.
- **ask** will cause Caddy to make an HTTP request to the given URL with a query string of `?domain=` containing the value of the domain name. If the endpoint returns a `2xx` status code, Caddy will be authorized to obtain a certificate for that name. Any other status code will result in cancelling issuance of the certificate. - **ask** will cause Caddy to make an HTTP request to the given URL, asking whether a domain is allowed to have a certificate issued.
The request has a query string of `?domain=` containing the value of the domain name.
If the endpoint returns a `2xx` status code, Caddy will be authorized to obtain a certificate for that name. Any other status code will result in cancelling issuance of the certificate and erroring the TLS handshake.
<aside class="tip"> <aside class="tip">
@ -352,33 +553,115 @@ The ask endpoint should return _as fast as possible_, in a few milliseconds, ide
- **interval** and **burst** allows `<n>` certificate operations within `<duration>` interval. - **interval** and **burst** allows `<n>` certificate operations within `<duration>` interval.
```caddy
{
on_demand_tls {
ask http://localhost:9123/ask
}
}
https:// {
tls {
on_demand
}
}
```
##### `key_type` ##### `key_type`
Specifies the type of key to generate for TLS certificates; only change this if you have a specific need to customize it. The possible values are: `ed25519`, `p256`, `p384`, `rsa2048`, `rsa4096`. Specifies the type of key to generate for TLS certificates; only change this if you have a specific need to customize it.
The possible values are: `ed25519`, `p256`, `p384`, `rsa2048`, `rsa4096`.
```caddy
{
key_type ed25519
}
```
##### `cert_issuer` ##### `cert_issuer`
Defines the issuer (or source) of TLS certificates. The tokens following the name of the issuer set up the issuer the same as if specified in the [`tls` directive](/docs/caddyfile/directives/tls#issuer). May be repeated if you wish to configure more than one issuer to try. They will be tried in the order they are defined. Defines the issuer (or source) of TLS certificates.
This allows configuring issuers globally, instead of per-site as you would with the [`tls` directive's `issuer` subdirective](/docs/caddyfile/directives/tls#issuer).
May be repeated if you wish to configure more than one issuer to try. They will be tried in the order they are defined.
```caddy
{
cert_issuer acme {
...
}
cert_issuer zerossl {
...
}
}
```
##### `renew_interval`
How often to scan all loaded, managed certificates for expiration, and trigger renewal if expired.
Default: `10m`
```caddy
{
renew_interval 30m
}
```
##### `ocsp_interval`
How often to check if [OCSP staples <img src="/old/resources/images/external-link.svg" class="external-link">](https://en.wikipedia.org/wiki/OCSP_stapling) need updating.
Default: `1h`
```caddy
{
ocsp_interval 2h
}
```
##### `ocsp_stapling` ##### `ocsp_stapling`
Can be set to `off` to disable OCSP stapling. Useful in environments where responders are not reachable due to firewalls. Can be set to `off` to disable OCSP stapling. Useful in environments where responders are not reachable due to firewalls.
```caddy
{
ocsp_stapling off
}
```
##### `preferred_chains` ##### `preferred_chains`
If your CA provides multiple certificate chains, you can use this option to specify which chain Caddy should prefer. Set one of the following options: If your CA provides multiple certificate chains, you can use this option to specify which chain Caddy should prefer. Set one of the following options:
- **smallest** will tell Caddy to prefer chains with the fewest amount of bytes. - **smallest** will tell Caddy to prefer chains with the fewest amount of bytes.
- **root_common_name** is a list of one or more common names; Caddy will choose the first chain that has a root that matches with at least one of the specified common names. - **root_common_name** is a list of one or more common names; Caddy will choose the first chain that has a root that matches with at least one of the specified common names.
- **any_common_name** is a list of one or more common names; Caddy will choose the first chain that has an issuer that matches with at least one of the specified common names. - **any_common_name** is a list of one or more common names; Caddy will choose the first chain that has an issuer that matches with at least one of the specified common names.
Note that specifying `preferred_chains` as a global option will affect all issuers if there isn't any [overriding issuer level config](/docs/caddyfile/directives/tls#acme). Note that specifying `preferred_chains` as a global option will affect all issuers if there isn't any [overriding issuer level config](/docs/caddyfile/directives/tls#acme).
```caddy
{
preferred_chains smallest
}
```
```caddy
{
preferred_chains {
root_common_name "ISRG Root X2"
}
}
```
## Server Options ## Server Options
Customizes [HTTP servers](/docs/json/apps/http/servers/) with settings that potentially span multiple sites and thus can't be rightly configured in site blocks. These options affect the listener/socket or other facilities beneath the HTTP layer. Customizes [HTTP servers](/docs/json/apps/http/servers/) with settings that potentially span multiple sites, and thus can't be rightly configured in site blocks. These options affect the listener/socket or other facilities beneath the HTTP layer.
Can be specified more than once with different `listener_address` values to configure different options per server. For example, `servers :443` will only apply to the server that is bound to the listener address `:443`. Omitting the listener address will apply the options to any remaining server. Can be specified more than once with different `listener_address` values to configure different options per server. For example, `servers :443` will only apply to the server that is bound to the listener address `:443`. Omitting the listener address will apply the options to any remaining server.
@ -406,6 +689,8 @@ For example, to configure different options for the servers on ports `:80` and `
} }
``` ```
When using `servers`, it will **only** apply to servers that **actually appear** in your Caddyfile (i.e. are produced by a site block). Remember, [Automatic HTTPS](/docs/automatic-https) will create a server listening on port `80` (or the [`http_port` option](#http_port)), to serve HTTP->HTTPS redirects and to solve the ACME HTTP challenge; this happens at runtime, i.e. _after_ the Caddyfile adapter applies `servers`. So in other words, this means that `servers` **will not** apply to `:80` unless you explicitly declare a site block like `http://` or `:80`.
<aside class="tip"> <aside class="tip">
@ -439,12 +724,11 @@ If you are using the [`bind` directive](/docs/caddyfile/directives/bind) or the
##### `name` ##### `name`
A custom name to assign to this server. Usually helpful to identify a server by its name in logs and metrics. If not set, Caddy will define it dynamically using a `srvX` pattern, where `X` starts with 0 and increments based on the number of servers in the config. A custom name to assign to this server. Usually helpful to identify a server by its name in logs and metrics. If not set, Caddy will define it dynamically using a `srvX` pattern, where `X` starts with `0` and increments based on the number of servers in the config.
<aside class="tip"> Keep in mind that only servers produced by site blocks in your config will have settings applied. [Automatic HTTPS](/docs/automatic-https) creates an `:80` server (or [`http_port`](#http_port)) at runtime, so if you want rename it, you'll need at least an empty `http://` site block.
Keep in mind there's a caveat if you want to name your HTTP server and are using Auto-HTTPS. The server name config doesn't persist past adapting the config, and Auto-HTTPS happens at runtime, from the JSON config. For example:
To overcome this, you'll need to create an empty `:80` or `http://` site block and set this option. With that Auto-HTTPS will add its redirect routes to that server. For example:
```caddy ```caddy
{ {
@ -472,26 +756,34 @@ 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. 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. 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.
The standard distribution of Caddy includes the [`http_redirect`](/docs/json/apps/http/servers/listener_wrappers/http_redirect/) listener wrapper, which 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. It must be placed _before_ the `tls` listener wrapper. For example: 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:
```caddy-d ```caddy
listener_wrappers { {
http_redirect servers {
tls listener_wrappers {
http_redirect
tls
}
}
} }
``` ```
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://www.haproxy.org/download/1.8/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: 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:
```caddy-d ```caddy
listener_wrappers { {
proxy_protocol { servers {
timeout 2s listener_wrappers {
allow 192.168.86.1/24 192.168.86.1/24 proxy_protocol {
timeout 2s
allow 192.168.86.1/24 192.168.86.1/24
}
tls
}
} }
tls
} }
``` ```
@ -506,6 +798,18 @@ listener_wrappers {
- **idle** is a [duration value](/docs/conventions#durations) that sets the maximum time to wait for the next request when keep-alives are enabled. Defaults to 5 minutes to help avoid resource exhaustion. - **idle** is a [duration value](/docs/conventions#durations) that sets the maximum time to wait for the next request when keep-alives are enabled. Defaults to 5 minutes to help avoid resource exhaustion.
```caddy
{
servers {
timeouts {
read_body 10s
read_header 5s
write 30s
idle 10m
}
}
}
```
##### `trusted_proxies` ##### `trusted_proxies`
@ -514,7 +818,7 @@ Allows configuring IP ranges (CIDRs) of proxy servers from which requests should
Enabling this causes trusted requests to have the _real_ client IP parsed from HTTP headers (by default, `X-Forwarded-For`; see [`client_ip_headers`](#client-ip-headers) to configure other headers). If trusted, the client IP is added to [access logs](/docs/caddyfile/directives/log), is available as a `{client_ip}` [placeholder](/docs/caddyfile/concepts#placeholders), and allows the use of the [`client_ip` matcher](/docs/caddyfile/matchers#client-ip). If the request is not from a trusted proxy, then the client IP is set to the remote IP address of the direct incoming connection. Enabling this causes trusted requests to have the _real_ client IP parsed from HTTP headers (by default, `X-Forwarded-For`; see [`client_ip_headers`](#client-ip-headers) to configure other headers). If trusted, the client IP is added to [access logs](/docs/caddyfile/directives/log), is available as a `{client_ip}` [placeholder](/docs/caddyfile/concepts#placeholders), and allows the use of the [`client_ip` matcher](/docs/caddyfile/matchers#client-ip). If the request is not from a trusted proxy, then the client IP is set to the remote IP address of the direct incoming connection.
Some matchers or handlers may use the trust status of the request to make additional decisions. For example, if trusted, the [`reverse_proxy`](/docs/caddyfile/directives/reverse_proxy#defaults) handler will proxy and augment the sensitive `X-Forwarded-*` request headers. Some matchers or handlers may use the trust status of the request to make decisions. For example, if trusted, the [`reverse_proxy`](/docs/caddyfile/directives/reverse_proxy#defaults) handler will proxy and augment the sensitive `X-Forwarded-*` request headers.
Currently, only the `static` [IP source module](/docs/json/apps/http/servers/trusted_proxies/) is included with the standard distribution of Caddy, but this can be [extended](/docs/extending-caddy) with plugins to maintain a dynamic list of IP ranges. Currently, only the `static` [IP source module](/docs/json/apps/http/servers/trusted_proxies/) is included with the standard distribution of Caddy, but this can be [extended](/docs/extending-caddy) with plugins to maintain a dynamic list of IP ranges.
@ -523,7 +827,9 @@ Currently, only the `static` [IP source module](/docs/json/apps/http/servers/tru
Takes a static (unchanging) list of IP ranges (CIDRs) to trust. Takes a static (unchanging) list of IP ranges (CIDRs) to trust.
As a shortcut, `private_ranges` can be used to match all private IPv4 and IPv6 ranges. It's the same as specifying all of these ranges: `192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 127.0.0.1/8 fd00::/8 ::1` As a shortcut, `private_ranges` can be used to match all private IPv4 and IPv6 ranges. It's the same as specifying all of these ranges: `192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 127.0.0.1/8 fd00::/8 ::1`.
The syntax is as follows:
```caddy-d ```caddy-d
trusted_proxies static [private_ranges] <ranges...> trusted_proxies static [private_ranges] <ranges...>
@ -544,17 +850,41 @@ Here's a complete example, trusting an example IPv4 range and an IPv6 range:
Pairing with [`trusted_proxies`](#trusted-proxies), allows configuring which headers to use to determine the client's IP address. By default, only `X-Forwarded-For` is considered. Multiple header fields can be specified, in which case the first non-empty header value is used. Pairing with [`trusted_proxies`](#trusted-proxies), allows configuring which headers to use to determine the client's IP address. By default, only `X-Forwarded-For` is considered. Multiple header fields can be specified, in which case the first non-empty header value is used.
```caddy
{
servers {
trusted_proxies static private_ranges
client_ip_headers X-Forwarded-For X-Real-IP
}
}
```
##### `metrics` ##### `metrics`
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!) 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
{
servers {
metrics
}
}
```
##### `max_header_size` ##### `max_header_size`
The maximum size to parse from a client's HTTP request headers. If the limit is exceeded, the server will respond with HTTP status `431 Request Header Fields Too Large`. It accepts all formats supported by [go-humanize](https://github.com/dustin/go-humanize/blob/master/bytes.go). By default, the limit is `1MB`. The maximum size to parse from a client's HTTP request headers. If the limit is exceeded, the server will respond with HTTP status `431 Request Header Fields Too Large`. It accepts all formats supported by [go-humanize](https://github.com/dustin/go-humanize/blob/master/bytes.go). By default, the limit is `1MB`.
```caddy
{
servers {
max_header_size 5MB
}
}
```
##### `enable_full_duplex` ##### `enable_full_duplex`
@ -562,12 +892,20 @@ Enable full-duplex communication for HTTP/1 requests. Only has an effect if Cadd
For HTTP/1 requests, the Go HTTP server by default consumes any unread portion of the request body before beginning to write the response, preventing handlers from concurrently reading from the request and writing the response. Enabling this option disables this behavior and permits handlers to continue to read from the request while concurrently writing the response. For HTTP/1 requests, the Go HTTP server by default consumes any unread portion of the request body before beginning to write the response, preventing handlers from concurrently reading from the request and writing the response. Enabling this option disables this behavior and permits handlers to continue to read from the request while concurrently writing the response.
For HTTP/2 requests, the Go HTTP server always permits concurrent reads and responses, so this option has no effect. For HTTP/2+ requests, the Go HTTP server always permits concurrent reads and responses, so this option has no effect.
Test thoroughly with your HTTP clients, as some older clients may not support full-duplex HTTP/1 which can cause them to deadlock. See [golang/go#57786](https://github.com/golang/go/issues/57786) for more info. Test thoroughly with your HTTP clients, as some older clients may not support full-duplex HTTP/1 which can cause them to deadlock. See [golang/go#57786](https://github.com/golang/go/issues/57786) for more info.
⚠️ This is an experimental feature. Subject to change or removal. ⚠️ This is an experimental feature. Subject to change or removal.
```caddy
{
servers {
enable_full_duplex
}
}
```
##### `log_credentials` ##### `log_credentials`
@ -575,11 +913,23 @@ Since Caddy v2.5, by default, headers with potentially sensitive information (`C
If you wish to _not_ have these headers redacted, you may enable the `log_credentials` option. If you wish to _not_ have these headers redacted, you may enable the `log_credentials` option.
```caddy
{
servers {
log_credentials
}
}
```
##### `protocols` ##### `protocols`
The space-separated list of HTTP protocols to support. Default: `h1 h2 h3`. Accepted values are: The space-separated list of HTTP protocols to support.
Default: `h1 h2 h3`
Accepted values are:
- `h1` for HTTP/1.1 - `h1` for HTTP/1.1
- `h2` For HTTP/2 - `h2` For HTTP/2
- `h2c` for HTTP/2 over cleartext - `h2c` for HTTP/2 over cleartext
@ -589,6 +939,15 @@ Currently, enabling HTTP/2 (including H2C) necessarily implies enabling HTTP/1.1
Note that H2C ("Cleartext HTTP/2" or "H2 over TCP") and HTTP/3 are not implemented by the Go standard library, so some functionality or features may be limited. We recommend against enabling H2C unless it is absolutely necessary for your application. Note that H2C ("Cleartext HTTP/2" or "H2 over TCP") and HTTP/3 are not implemented by the Go standard library, so some functionality or features may be limited. We recommend against enabling H2C unless it is absolutely necessary for your application.
```caddy
{
servers :80 {
protocols h1 h2c
}
}
```
##### `strict_sni_host` ##### `strict_sni_host`
@ -596,6 +955,13 @@ Enabling this requires that a request's `Host` header matches the value of the `
This option will automatically be turned on if [client authentication](/docs/caddyfile/directives/tls#client_auth) is configured. This disallows TLS client auth bypass (domain fronting) which could otherwise be exploited by sending an unprotected SNI value during a TLS handshake, then putting a protected domain in the Host header after establishing connection. This behavior is a safe default, but you may explicitly turn it off with `insecure_off`; for example in the case of running a proxy where domain fronting is desired and access is not restricted based on hostname. This option will automatically be turned on if [client authentication](/docs/caddyfile/directives/tls#client_auth) is configured. This disallows TLS client auth bypass (domain fronting) which could otherwise be exploited by sending an unprotected SNI value during a TLS handshake, then putting a protected domain in the Host header after establishing connection. This behavior is a safe default, but you may explicitly turn it off with `insecure_off`; for example in the case of running a proxy where domain fronting is desired and access is not restricted based on hostname.
```caddy
{
servers {
strict_sni_host on
}
}
```
@ -606,16 +972,64 @@ The PKI (Public Key Infrastructure) app is the foundation for Caddy's [Local HTT
The default CA ID is `local`. If the ID is omitted when configuring the `ca`, then `local` is assumed. The default CA ID is `local`. If the ID is omitted when configuring the `ca`, then `local` is assumed.
##### `name` ##### `name`
The user-facing name of the certificate authority. Default: `Caddy Local Authority` The user-facing name of the certificate authority.
Default: `Caddy Local Authority`
```caddy
{
pki {
ca local {
name "My Local CA"
}
}
}
```
##### `root_cn` ##### `root_cn`
The name to put in the CommonName field of the root certificate. Default: `{pki.ca.name} - {time.now.year} ECC Root` The name to put in the CommonName field of the root certificate.
Default: `{pki.ca.name} - {time.now.year} ECC Root`
```caddy
{
pki {
ca local {
root_cn "My Local CA - 2024 ECC Root"
}
}
}
```
##### `intermediate_cn` ##### `intermediate_cn`
The name to put in the CommonName field of the intermediate certificates. Default: `{pki.ca.name} - ECC Intermediate` The name to put in the CommonName field of the intermediate certificates.
Default: `{pki.ca.name} - ECC Intermediate`
```caddy
{
pki {
ca local {
intermediate_cn "My Local CA - ECC Intermediate"
}
}
}
```
##### `intermediate_lifetime` ##### `intermediate_lifetime`
The [duration](/docs/conventions#durations) for which intermediate certificates are valid. This value must be less than the lifetime of the root cert (`3600d` or 10 years). Default: `7d`. It is recommended not to change this unless absolutely necessary. The [duration](/docs/conventions#durations) for which intermediate certificates are valid. This value **must** be less than the lifetime of the root cert (`3600d` or 10 years).
Default: `7d`. It is _not recommended_ to change this, unless absolutely necessary.
```caddy
{
pki {
ca local {
intermediate_lifetime 30d
}
}
}
```
##### `root` ##### `root`
A key pair (certificate and private key) to use as the root for the CA. If not specified, one will be generated and managed automatically. A key pair (certificate and private key) to use as the root for the CA. If not specified, one will be generated and managed automatically.
@ -631,6 +1045,25 @@ A key pair (certificate and private key) to use as the intermediate for the CA.
- **cert** is the certificate. This should be the path to a PEM file, when using `pem_file` format. - **cert** is the certificate. This should be the path to a PEM file, when using `pem_file` format.
- **key** is the private key. This should be the path to a PEM file, when using `pem_file` format. - **key** is the private key. This should be the path to a PEM file, when using `pem_file` format.
```caddy
{
pki {
ca local {
root {
format pem_file
cert /path/to/root.pem
key /path/to/root.key
}
intermediate {
format pem_file
cert /path/to/intermediate.pem
key /path/to/intermediate.key
}
}
}
}
```
## Event Options ## Event Options

View file

@ -15,6 +15,7 @@ These are not drop-in solutions; you will have to customize your domain name, po
- [Trailing slashes](#trailing-slashes) - [Trailing slashes](#trailing-slashes)
- [Wildcard certificates](#wildcard-certificates) - [Wildcard certificates](#wildcard-certificates)
- [Single-page apps (SPAs)](#single-page-apps-spas) - [Single-page apps (SPAs)](#single-page-apps-spas)
- [Caddy proxying to another Caddy](#caddy-proxying-to-another-caddy)
## Static file server ## Static file server
@ -58,6 +59,8 @@ There are many more [`reverse_proxy` examples here](/docs/caddyfile/directives/r
## PHP ## PHP
### PHP-FPM
With a PHP FastCGI service running, something like this works for most modern PHP apps: With a PHP FastCGI service running, something like this works for most modern PHP apps:
```caddy ```caddy
@ -80,6 +83,23 @@ php_fastcgi unix//run/php/php8.2-fpm.sock
The [`php_fastcgi` directive](/docs/caddyfile/directives/php_fastcgi) is actually just a shortcut for [several pieces of configuration](/docs/caddyfile/directives/php_fastcgi#expanded-form). The [`php_fastcgi` directive](/docs/caddyfile/directives/php_fastcgi) is actually just a shortcut for [several pieces of configuration](/docs/caddyfile/directives/php_fastcgi#expanded-form).
### FrankenPHP
Alternatively, you may use [FrankenPHP](https://frankenphp.dev/), which is a distribution of Caddy which calls PHP directly using CGO (Go to C bindings). This can be up to 4x faster than with PHP-FPM, and even better if you can use the worker mode.
```caddy
{
frankenphp
order php_server before file_server
}
example.com {
root * /srv/public
encode zstd br gzip
php_server
}
```
## Redirect `www.` subdomain ## Redirect `www.` subdomain
@ -196,7 +216,7 @@ A typical SPA config usually looks something like this:
```caddy ```caddy
example.com { example.com {
root * /path/to/site root * /srv
encode gzip encode gzip
try_files {path} /index.html try_files {path} /index.html
file_server file_server
@ -214,9 +234,50 @@ example.com {
} }
handle { handle {
root * /path/to/site root * /srv
try_files {path} /index.html try_files {path} /index.html
file_server file_server
} }
} }
``` ```
## Caddy proxying to another Caddy
If you have one Caddy instance publicly accessible (let's call it "front"), and another Caddy instance in your private network (let's call it "back") serving your actual app, you can use the [`reverse_proxy` directive](/docs/caddyfile/directives/reverse_proxy) to pass requests through.
Front instance:
```caddy
foo.example.com, bar.example.com {
reverse_proxy 10.0.0.1:80
}
```
Back instance:
```caddy
{
servers {
trusted_proxies static private_ranges
}
}
http://foo.example.com {
reverse_proxy foo-app:8080
}
http://bar.example.com {
reverse_proxy bar-app:9000
}
```
- This example serves two different domains, proxying both to the same back Caddy instance, on port `80`. Your back instance is serving the two domains different ways, so it's configured with two separate site blocks.
- On the back, [`http://`](/docs/caddyfile/concepts#addresses) is used to accept HTTP on port `80`. The front instance terminates TLS, and the traffic between front and back are on a private network, so there's no need to re-encrypt it.
- You may use a different port like `8080` on the back instance if you need to; just append `:8080` to each site address on the back's config, OR set the [`http_port` global option](/docs/caddyfile/options#http_port) to `8080`.
- On the back, the [`trusted_proxies` global option](/docs/caddyfile/options#trusted_proxies) is used to tell Caddy to trust the front instance as a proxy. This ensures the real client IP is preserved.
- Going further, you could have more than one back instance that you [load balance](/docs/caddyfile/directives/reverse_proxy#load-balancing) between. You could set up mTLS (mutual TLS) using the [`acme_server`](/docs/caddyfile/directives/acme_server) on the front instance such that it acts like the CA for the back instance (useful if the traffic between front and back cross untrusted networks).

View file

@ -471,7 +471,9 @@ Runs Caddy and blocks indefinitely; i.e. "daemon" mode.
`--watch` will watch the config file and automatically reload it after it changes. ⚠️ This feature is intended for use only in local development environments! `--watch` will watch the config file and automatically reload it after it changes. ⚠️ This feature is intended for use only in local development environments!
<aside class="advice"> <aside class="advice">
Do not stop the server to change configuration while running in production! That will result in downtime. (This should be obvious but you'd be surprised how many complaints we get about it.) Use the <a href="#caddy-reload">caddy reload</a> command instead.
Do not stop the server to change configuration while running in production! That will result in downtime. (This should be obvious but you'd be surprised how many complaints we get about it.) Use the [`caddy reload`](#caddy-reload) command instead.
</aside> </aside>