mirror of
https://github.com/caddyserver/website.git
synced 2025-05-06 11:47:12 -04:00
Rewrite Getting Started; move GS to Intro
This commit is contained in:
commit
371663688c
148 changed files with 19931 additions and 0 deletions
7
.editorconfig
Normal file
7
.editorconfig
Normal file
|
@ -0,0 +1,7 @@
|
|||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
[*.{md,css,js,html}]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
github: mholt
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
_gitignore/
|
17
Caddyfile
Normal file
17
Caddyfile
Normal file
|
@ -0,0 +1,17 @@
|
|||
localhost
|
||||
|
||||
root * src
|
||||
|
||||
file_server
|
||||
templates
|
||||
encode gzip
|
||||
|
||||
try_files {path}.html {path}
|
||||
|
||||
redir /docs/json /docs/json/
|
||||
redir /docs/modules /docs/modules/
|
||||
rewrite /docs/json/* /docs/json/index.html
|
||||
rewrite /docs/modules/* /docs/modules/index.html
|
||||
rewrite /docs/* /docs/index.html
|
||||
|
||||
reverse_proxy /api/* localhost:4444
|
22
README.md
Normal file
22
README.md
Normal file
|
@ -0,0 +1,22 @@
|
|||
The Caddy Website
|
||||
=================
|
||||
|
||||
This is the source of the Caddy website, [caddyserver.com](https://caddyserver.com).
|
||||
|
||||
|
||||
## Requirements
|
||||
|
||||
- Caddy 2 (installed in your PATH as `caddy`)
|
||||
|
||||
|
||||
## Quick start
|
||||
|
||||
1. `git clone https://github.com/caddyserver/website.git`
|
||||
2. `cd website`
|
||||
3. `caddy run`
|
||||
|
||||
Your first time, you may be prompted for a password. This is so Caddy can serve the site over local HTTPS. If you can't bind to low ports, change [the address at the top of the Caddyfile](https://github.com/caddyserver/website/blob/master/Caddyfile#L1), for example `localhost:2015`.
|
||||
|
||||
You can then load [https://localhost](https://localhost) (or whatever address you configured) in your browser.
|
||||
|
||||
|
28
src/account/create.html
Normal file
28
src/account/create.html
Normal file
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Create Account - Caddy</title>
|
||||
{{include "/includes/account/head.html"}}
|
||||
<script src="/resources/js/account/create.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<form action="/api/create-account" class="card">
|
||||
<section class="head">
|
||||
<a href="/"><img src="/resources/images/caddy-lock.png" alt="Caddy Portal" class="logo"></a>
|
||||
</section>
|
||||
<section>
|
||||
<h1>Create Account</h1>
|
||||
or <a href="/account/login">log in</a>
|
||||
<div class="form-fields">
|
||||
<input type="text" name="name" id="name" placeholder="Name">
|
||||
<input type="email" name="email" id="email" placeholder="Email address" required>
|
||||
<input type="password" name="password" placeholder="Password" required>
|
||||
<button type="submit" id="submit" class="blue">Create Account</button>
|
||||
<p>
|
||||
We will send you an email to verify your account.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
32
src/account/index.html
Normal file
32
src/account/index.html
Normal file
|
@ -0,0 +1,32 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Dashboard - Caddy</title>
|
||||
{{include "/includes/account/head.html"}}
|
||||
<link rel="stylesheet" href="/resources/css/account/dashboard.css">
|
||||
<script src="/resources/js/account/dashboard.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
{{include "/includes/account/nav.html"}}
|
||||
<main class="dashboard">
|
||||
<section>
|
||||
<h1 class="pad">Your packages<a href="/account/register-package" class="gray button float-right">Register package</a></h1>
|
||||
<table id="user-packages">
|
||||
<tr>
|
||||
<th>Import path</th>
|
||||
<th class="text-center"><span class="help" title="Whether package and module documentation is visible on the website.">Listed</span></th>
|
||||
<th class="text-center"><span class="help" title="Whether visitors can download Caddy with this package plugged in.">Available</span></th>
|
||||
<th>Downloads</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<!-- Filled by JS -->
|
||||
</table>
|
||||
<!-- <div class="text-right pad">
|
||||
<a href="/account/register-package" class="gray button">Register package</a>
|
||||
</div> -->
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
25
src/account/login.html
Normal file
25
src/account/login.html
Normal file
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Log In - Caddy</title>
|
||||
{{include "/includes/account/head.html"}}
|
||||
<script src="/resources/js/account/login.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<form action="/api/login" class="card">
|
||||
<section class="head">
|
||||
<a href="/"><img src="/resources/images/caddy-lock.png" alt="Caddy Portal" class="logo"></a>
|
||||
</section>
|
||||
<section>
|
||||
<h1>Log In</h1>
|
||||
or <a href="/account/create">create account</a>
|
||||
<div class="form-fields">
|
||||
<input type="email" name="email" id="email" placeholder="Email address" required>
|
||||
<input type="password" name="password" placeholder="Password" required>
|
||||
<button type="submit" id="submit" class="blue">Log In</button>
|
||||
<a href="/account/reset-password">Reset password</a>
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
11
src/account/logout.html
Normal file
11
src/account/logout.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Logout - Caddy</title>
|
||||
{{include "/includes/account/head.html"}}
|
||||
<script src="/resources/js/account/logout.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
Logging out...
|
||||
</body>
|
||||
</html>
|
42
src/account/register-package.html
Normal file
42
src/account/register-package.html
Normal file
|
@ -0,0 +1,42 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Register Package - Caddy</title>
|
||||
{{include "/includes/account/head.html"}}
|
||||
<script src="/resources/js/account/register-package.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
{{include "/includes/account/nav.html"}}
|
||||
<main>
|
||||
<section>
|
||||
<form action="/api/claim-package">
|
||||
<div class="form-fields">
|
||||
<div class="field">
|
||||
<label>
|
||||
<b>Package import path</b>
|
||||
<input type="text" name="package" required>
|
||||
</label>
|
||||
<div class="description">
|
||||
You must use <a href="https://github.com/golang/go/wiki/Modules#semantic-import-versioning" target="_blank">semantic import versioning</a>. Basically, this means if your module is at v2 or higher the import path must be suffixed with <b>/vN</b> (where <b>N</b> is the major version number).
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>
|
||||
<b>Version</b>
|
||||
<input type="text" name="version" placeholder="latest">
|
||||
</label>
|
||||
<div class="description">
|
||||
Optional. Any version string recognized by <a href="https://github.com/golang/go/wiki/Modules#version-selection">Go module</a> tooling is acceptable.
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button type="submit" id="submit" class="blue">Claim Package</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
38
src/account/reset-password.html
Normal file
38
src/account/reset-password.html
Normal file
|
@ -0,0 +1,38 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Reset Password - Caddy</title>
|
||||
{{include "/includes/account/head.html"}}
|
||||
<script src="/resources/js/account/reset-password.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<form action="/api/reset-password" class="card" id="reset-password-step1">
|
||||
<section class="head">
|
||||
<a href="/"><img src="/resources/images/caddy-lock.png" alt="Caddy Portal" class="logo"></a>
|
||||
</section>
|
||||
<section>
|
||||
<h1>Reset Password</h1>
|
||||
<a href="javascript:" id="goto-step2">I already have a reset token</a>
|
||||
<div class="form-fields">
|
||||
<input type="email" name="email" id="email-step1" placeholder="Email address" required>
|
||||
<button type="submit" id="submit" class="blue">Continue</button>
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
<form action="/api/reset-password" class="card" id="reset-password-step2">
|
||||
<section class="head">
|
||||
<a href="/"><img src="/resources/images/caddy-lock.png" alt="Caddy Portal" class="logo"></a>
|
||||
</section>
|
||||
<section>
|
||||
<h1>Reset Password</h1>
|
||||
<a href="javascript:" id="goto-step1">I still need a reset token</a>
|
||||
<div class="form-fields">
|
||||
<input type="email" name="email" id="email-step2" placeholder="Email address" required>
|
||||
<input type="text" name="token" id="token" placeholder="Token" required>
|
||||
<input type="password" name="password" placeholder="New Password" required>
|
||||
<button type="submit" id="submit" class="blue">Finish Reset</button>
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
24
src/account/verify.html
Normal file
24
src/account/verify.html
Normal file
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Confirm Account - Caddy</title>
|
||||
{{include "/includes/account/head.html"}}
|
||||
<script src="/resources/js/account/verify.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<form action="/api/verify-account" class="card">
|
||||
<section class="head">
|
||||
<a href="/"><img src="/resources/images/caddy-lock.png" alt="Caddy Portal" class="logo"></a>
|
||||
</section>
|
||||
<section>
|
||||
<h1>Confirm Account</h1>
|
||||
or <a href="/account/login">log in</a>
|
||||
<div class="form-fields">
|
||||
<input type="email" name="email" id="email" placeholder="Email address" required>
|
||||
<input type="text" name="account_id" placeholder="Account ID" required>
|
||||
<button type="submit" id="submit" class="blue">Confirm</button>
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
48
src/business.html
Normal file
48
src/business.html
Normal file
|
@ -0,0 +1,48 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Caddy for Business</title>
|
||||
{{include "/includes/head.html"}}
|
||||
<link rel="stylesheet" href="/resources/css/business.css">
|
||||
<meta property="og:title" content="Caddy 2 for Business">
|
||||
<meta name="twitter:title" value="Caddy 2 for Business">
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<header>
|
||||
<div id="logo-container">
|
||||
<a href="/"><img src="/resources/images/caddy-wordmark.svg" id="logo" alt="Caddy"></a>
|
||||
<br>
|
||||
a <a href="https://zerossl.com"><img src="/resources/images/zerossl-logo.svg" id="zerossl-logo"></a> project
|
||||
</div>
|
||||
{{include "/includes/header-nav.html"}}
|
||||
</header>
|
||||
|
||||
<h1>Ready for business</h1>
|
||||
|
||||
<section>
|
||||
<div class="panels">
|
||||
<div>
|
||||
<h2>Need help with something?</h2>
|
||||
<p>
|
||||
Most users should participate in our <a href="https://caddy.community">community forum</a> to help others and ask questions.
|
||||
</p>
|
||||
<p>
|
||||
The only price for this help is to put some effort into your question and say thank you. 😃
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<h2>Support and development for businesses</h2>
|
||||
<p>
|
||||
We highly recommend that companies using Caddy get a support plan and contract any related development work with our exclusive partner <a href="https://www.ardanlabs.com/">Ardan Labs</a>. Contact us to get started:
|
||||
</p>
|
||||
<a href="mailto:b%75s%69%6Eess@ca%64dyse%72ver.c%6Fm" class="button red">Email <b>business@caddyserver.com</b></a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
{{include "/includes/footer.html"}}
|
||||
|
||||
</body>
|
||||
</html>
|
30
src/docs/index.html
Normal file
30
src/docs/index.html
Normal file
|
@ -0,0 +1,30 @@
|
|||
{{$pathParts := splitList "/" .OriginalReq.URL.Path}}
|
||||
{{$markdownFilename := default "index" (slice $pathParts 2 | join "/")}}
|
||||
{{$markdownFilePath := printf "/docs/markdown/%s.md" $markdownFilename}}
|
||||
{{if not (fileExists $markdownFilePath)}}{{httpError 404}}{{end}}
|
||||
{{$markdownFile := (include $markdownFilePath | splitFrontMatter)}}
|
||||
{{$title := default $markdownFilename $markdownFile.Meta.title}}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{{$title}} — Caddy Documentation</title>
|
||||
{{include "/includes/docs/head.html"}}
|
||||
<meta property="og:title" content="{{$title}} - Caddy Documentation">
|
||||
<meta name="twitter:title" value="{{$title}} - Caddy Documentation">
|
||||
</head>
|
||||
<body>
|
||||
{{include "/includes/docs/header.html"}}
|
||||
<main>
|
||||
{{include "/includes/docs/nav.html"}}
|
||||
<div class="article-container">
|
||||
<div class="paper" id="paper1"></div>
|
||||
<div class="paper" id="paper2"></div>
|
||||
<div class="paper paper3">
|
||||
<article>{{markdown $markdownFile.Body}}</article>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar"></div>
|
||||
</main>
|
||||
{{include "/includes/footer.html"}}
|
||||
</body>
|
||||
</html>
|
35
src/docs/json/index.html
Normal file
35
src/docs/json/index.html
Normal file
|
@ -0,0 +1,35 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>JSON Config Structure - Caddy Documentation</title>
|
||||
{{include "/includes/docs/head.html"}}
|
||||
<link rel="stylesheet" href="/resources/css/docs-json.css">
|
||||
<script src="/resources/js/marked-0.8.0.min.js"></script>
|
||||
<script src="/resources/js/docs-api.js"></script>
|
||||
<script src="/resources/js/json-docs.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
{{include "/includes/docs/header.html"}}
|
||||
<main>
|
||||
{{include "/includes/docs/nav.html"}}
|
||||
<div class="article-container">
|
||||
<div class="paper" id="paper1"></div>
|
||||
<div class="paper" id="paper2"></div>
|
||||
<div class="paper paper3">
|
||||
<article id="json-docs-container">
|
||||
<div class="breadcrumbs">
|
||||
<!--Populated by JS-->
|
||||
</div>
|
||||
{{include "/includes/docs/renderbox.html"}}
|
||||
{{include "/includes/docs/details.html"}}
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar"></div>
|
||||
</main>
|
||||
|
||||
{{include "/includes/docs/hovercard.html"}}
|
||||
|
||||
{{include "/includes/footer.html"}}
|
||||
</body>
|
||||
</html>
|
218
src/docs/markdown/api-tutorial.md
Normal file
218
src/docs/markdown/api-tutorial.md
Normal file
|
@ -0,0 +1,218 @@
|
|||
---
|
||||
title: "API Tutorial"
|
||||
---
|
||||
|
||||
# API Tutorial
|
||||
|
||||
This tutorial will show you how to use Caddy's [admin API](/docs/api), which makes it possible to automate in a programmable fashion.
|
||||
|
||||
**Objectives:**
|
||||
- 🔲 Run the daemon
|
||||
- 🔲 Give Caddy a config
|
||||
- 🔲 Test config
|
||||
- 🔲 Replace active config
|
||||
- 🔲 Traverse config
|
||||
- 🔲 Use `@id` tags
|
||||
|
||||
**Prerequisites:**
|
||||
- Basic terminal / command line skills
|
||||
- Basic JSON experience
|
||||
- `caddy` and `curl` in your PATH
|
||||
|
||||
---
|
||||
|
||||
To start the Caddy daemon, use the `run` subcommand:
|
||||
|
||||
<pre><code class="cmd bash">caddy run</code></pre>
|
||||
|
||||
<aside class="complete">Run the daemon</aside>
|
||||
|
||||
This blocks forever, but what is it doing? At the moment... nothing. By default, Caddy's configuration ("config") is blank. We can verify this using the [admin API](/docs/api) in another terminal:
|
||||
|
||||
<pre><code class="cmd bash">curl localhost:2019/config/</code></pre>
|
||||
|
||||
We can make Caddy useful by giving it a config. One way to do this is by making a POST request to the [/load](/docs/api#post-load) endpoint. Just like any HTTP request, there are many ways to do this, but in this tutorial we'll use `curl`.
|
||||
|
||||
## Your first config
|
||||
|
||||
To prepare our request, we need to make a config. Caddy's configuration is simply a [JSON document](/docs/json/) (or [anything that converts to JSON](/docs/config-adapters)).
|
||||
|
||||
<aside class="tip">
|
||||
Config files are not required. The configuration API can always be used without files, which is handy when automating things. This tutorial uses a file because it is more convenient for editing by hand.
|
||||
</aside>
|
||||
|
||||
Save this to a JSON file:
|
||||
|
||||
```json
|
||||
{
|
||||
"apps": {
|
||||
"http": {
|
||||
"servers": {
|
||||
"example": {
|
||||
"listen": [":2015"],
|
||||
"routes": [
|
||||
{
|
||||
"handle": [{
|
||||
"handler": "static_response",
|
||||
"body": "Hello, world!"
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then upload it:
|
||||
|
||||
<pre><code class="cmd bash">curl localhost:2019/load \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @caddy.json
|
||||
</code></pre>
|
||||
|
||||
<aside class="tip">
|
||||
Make sure you don't forget the @ in front of your filename; this tells curl you are sending a file.
|
||||
</aside>
|
||||
|
||||
<aside class="complete">Give Caddy a config</aside>
|
||||
|
||||
We can verify that Caddy applied our new config with another GET request:
|
||||
|
||||
<pre><code class="cmd bash">curl localhost:2019/config/</code></pre>
|
||||
|
||||
Test that it works by going to [localhost:2015](http://localhost:2015) in your browser or using `curl`:
|
||||
|
||||
<pre><code class="cmd"><span class="bash">curl localhost:2015</span>
|
||||
Hello, world!</code></pre>
|
||||
|
||||
<aside class="complete">Test config</aside>
|
||||
|
||||
If you see _Hello, world!_, then congrats -- it's working! It's always a good idea to make sure your config works as you expect, especially before deploying into production.
|
||||
|
||||
Let's change our welcome message from "Hello world!" to something a little more motivational: "I can do hard things." Make this change in your config file, so that the handler object now looks like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"handler": "static_response",
|
||||
"body": "I can do hard things."
|
||||
}
|
||||
```
|
||||
|
||||
Save the config file, then update Caddy's active configuration by running the same POST request again:
|
||||
|
||||
<pre><code class="cmd bash">curl localhost:2019/load \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @caddy.json
|
||||
</code></pre>
|
||||
|
||||
<aside class="complete">Replace active config</aside>
|
||||
|
||||
For good measure, verify that the config was updated:
|
||||
|
||||
<pre><code class="cmd bash">curl localhost:2019/config/</code></pre>
|
||||
|
||||
Test it by refreshing the page in your browser (or running `curl` again), and you will see an inspirational message!
|
||||
|
||||
|
||||
## Config traversal
|
||||
|
||||
Instead of uploading the entire config file for a small change, let's use a powerful feature of Caddy's API to make the change without ever touching our config file.
|
||||
|
||||
<aside class="tip">
|
||||
Making little changes to production servers by replacing the entire config like we did above can be dangerous; it's like having root access to a file system. Caddy's API lets you limit the scope of your changes to guarantee that other parts of your config don't get changed accidentally.
|
||||
</aside>
|
||||
|
||||
Using the request URI's path, we can traverse into the config structure and update only the message string (be sure to scroll right if clipped):
|
||||
|
||||
<pre><code class="cmd bash">curl \
|
||||
localhost:2019/config/apps/http/servers/example/routes/0/handle/0/body \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '"Work smarter, not harder."'
|
||||
</code></pre>
|
||||
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
Every time you change the config using the API, Caddy persists a copy of the new config so you can [**--resume** it later](/docs/command-line#caddy-run)!
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
You can verify that it worked with a similar GET request, for example:
|
||||
|
||||
<pre><code class="cmd bash">curl localhost:2019/config/apps/http/servers/example/routes</code></pre>
|
||||
|
||||
You should see:
|
||||
|
||||
```json
|
||||
[{"handle":[{"body":"Work smarter, not harder.","handler":"static_response"}]}]
|
||||
```
|
||||
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
You can use the [`jq` command](https://stedolan.github.io/jq/) to prettify JSON output: **`curl ... | jq`**
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
<aside class="complete">Traverse config</aside>
|
||||
|
||||
**Important note:** This should be obvious, but once you use the API to make a change that is not in your original config file, your config file becomes obsolete. There are a few ways to handle this:
|
||||
|
||||
- Use the `--resume` of the [caddy run](/docs/command-line#caddy-run) command to use the last active config.
|
||||
- Don't mix the use of config files with changes via the API; have one source of truth.
|
||||
- [Export Caddy's new configuration](/docs/api#get-configpath) with a subsequent GET request (less recommended than the first two options).
|
||||
|
||||
|
||||
|
||||
## Using `@id` in JSON
|
||||
|
||||
Config traversal is certainly useful, but the paths are little long, don't you think?
|
||||
|
||||
We can give our handler object an [`@id` tag](/docs/api#using-id-in-json) to make it easier to access:
|
||||
|
||||
<pre><code class="cmd bash">curl \
|
||||
localhost:2019/config/apps/http/servers/example/routes/0/handle/0/@id \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '"msg"'
|
||||
</code></pre>
|
||||
|
||||
This adds a property to our handler object: `"@id": "msg"`, so it now looks like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"@id": "msg",
|
||||
"body": "Work smarter, not harder.",
|
||||
"handler": "static_response"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
**@id** tags can go in any object and can have any primitive value (usually a string). [Learn more](/docs/api#using-id-in-json)
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
We can then access it directly:
|
||||
|
||||
<pre><code class="cmd bash">curl localhost:2019/id/msg</code></pre>
|
||||
|
||||
And now we can change the message with a shorter path:
|
||||
|
||||
<pre><code class="cmd bash">curl \
|
||||
localhost:2019/id/msg/body \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '"Some shortcuts are good."'
|
||||
</code></pre>
|
||||
|
||||
And check it again:
|
||||
|
||||
<pre><code class="cmd bash">curl localhost:2019/id/msg/body</code></pre>
|
||||
|
||||
<aside class="complete">Use <code>@id</code> tags</aside>
|
||||
|
339
src/docs/markdown/api.md
Normal file
339
src/docs/markdown/api.md
Normal file
|
@ -0,0 +1,339 @@
|
|||
---
|
||||
title: "API"
|
||||
---
|
||||
|
||||
# API
|
||||
|
||||
Caddy is configured through an administration endpoint which can be accessed via HTTP using a [REST](https://en.wikipedia.org/wiki/Representational_state_transfer) API. You can [configure this endpoint](/docs/json/admin/) in your Caddy config.
|
||||
|
||||
**Default address: `localhost:2019`**
|
||||
|
||||
<aside class="tip">
|
||||
If you are running untrusted code on your server (yikes 😬), make sure you protect your admin endpoint by isolating processes, patching vulnerable programs, and configuring the endpoint to bind to a permissioned unix socket instead.
|
||||
</aside>
|
||||
|
||||
The latest configuration will be saved to disk after any changes (unless [disabled](/docs/json/admin/config/)). You can resume the last working config after a restart with [`caddy run --resume`](/docs/command-line#caddy-run), which guarantees config durability in the event of a power cycle or similar.
|
||||
|
||||
To get started with the API, try our [API tutorial](/docs/api-tutorial) or, if you only have a minute, our [API quick-start guide](/docs/quick-starts/api).
|
||||
|
||||
---
|
||||
|
||||
- **[POST /load](#post-load)**
|
||||
Sets or replaces the active configuration
|
||||
|
||||
- **[POST /stop](#post-stop)**
|
||||
Stops the active configuration and exits the process
|
||||
|
||||
- **[GET /config/[path]](#get-configpath)**
|
||||
Exports the config at the named path
|
||||
|
||||
- **[POST /config/[path]](#post-configpath)**
|
||||
Sets or replaces object; appends to array
|
||||
|
||||
- **[PUT /config/[path]](#put-configpath)**
|
||||
Creates new object; inserts into array
|
||||
|
||||
- **[PATCH /config/[path]](#patch-configpath)**
|
||||
Replaces an existing object or array element
|
||||
|
||||
- **[DELETE /config/[path]](#delete-configpath)**
|
||||
Deletes the value at the named path
|
||||
|
||||
- **[Using `@id` in JSON](#using-id-in-json)**
|
||||
Easily traverse into the config structure
|
||||
|
||||
- **[Concurrent config changes](#concurrent-config-changes)**
|
||||
Avoid collisions when making unsynchronized changes to config
|
||||
|
||||
- **[POST /adapt](#post-adapt)**
|
||||
Adapts a configuration to JSON without running it
|
||||
|
||||
- **[GET /pki/ca/<id>](#get-pkicaltidgt)**
|
||||
Returns information about a particular [PKI app](/docs/json/apps/pki/) CA
|
||||
|
||||
- **[GET /pki/ca/<id>/certificates](#get-pkicaltidgtcertificates)**
|
||||
Returns the certificate chain of a particular [PKI app](/docs/json/apps/pki/) CA
|
||||
|
||||
- **[GET /reverse_proxy/upstreams](#get-reverse-proxyupstreams)**
|
||||
Returns the current status of the configured proxy upstreams
|
||||
|
||||
|
||||
## POST /load
|
||||
|
||||
Sets Caddy's configuration, overriding any previous configuration. It blocks until the reload completes or fails. Configuration changes are lightweight, efficient, and incur zero downtime. If the new config fails for any reason, the old config is rolled back into place without downtime.
|
||||
|
||||
This endpoint supports different config formats using config adapters. The request's Content-Type header indicates the config format used in the request body. Usually, this should be `application/json` which represents Caddy's native config format. For another config format, specify the appropriate Content-Type so that the value after the forward slash / is the name of the config adapter to use. For example, when submitting a Caddyfile, use a value like `text/caddyfile`; or for JSON 5, use a value such as `application/json5`; etc.
|
||||
|
||||
If the new config is the same as the current one, no reload will occur. To force a reload, set `Cache-Control: must-revalidate` in the request headers.
|
||||
|
||||
### Examples
|
||||
|
||||
Set a new active configuration:
|
||||
|
||||
<pre><code class="cmd bash">curl "http://localhost:2019/load" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @caddy.json</code></pre>
|
||||
|
||||
Note: curl's `-d` flag removes newlines, so if your config format is sensitive to line breaks (e.g. the Caddyfile), use `--data-binary` instead:
|
||||
|
||||
<pre><code class="cmd bash">curl "http://localhost:2019/load" \
|
||||
-H "Content-Type: text/caddyfile" \
|
||||
--data-binary @Caddyfile</code></pre>
|
||||
|
||||
|
||||
## POST /stop
|
||||
|
||||
Gracefully shuts down the server and exits the process. To only stop the running configuration without exiting the process, use [DELETE /config/](#delete-configpath).
|
||||
|
||||
### Example
|
||||
|
||||
Stop the process:
|
||||
|
||||
<pre><code class="cmd bash">curl -X POST "http://localhost:2019/stop"</code></pre>
|
||||
|
||||
|
||||
## GET /config/[path]
|
||||
|
||||
Exports Caddy's current configuration at the named path. Returns a JSON body.
|
||||
|
||||
### Examples
|
||||
|
||||
Export entire config and pretty-print it:
|
||||
|
||||
<pre><code class="cmd"><span class="bash">curl "http://localhost:2019/config/" | jq</span>
|
||||
{
|
||||
"apps": {
|
||||
"http": {
|
||||
"servers": {
|
||||
"myserver": {
|
||||
"listen": [
|
||||
":443"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"match": [
|
||||
{
|
||||
"host": [
|
||||
"example.com"
|
||||
]
|
||||
}
|
||||
],
|
||||
"handle": [
|
||||
{
|
||||
"handler": "file_server"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
|
||||
Export just the listener addresses:
|
||||
|
||||
<pre><code class="cmd"><span class="bash">curl "http://localhost:2019/config/apps/http/servers/myserver/listen"</span>
|
||||
[":443"]</code></pre>
|
||||
|
||||
|
||||
|
||||
## POST /config/[path]
|
||||
|
||||
Changes Caddy's configuration at the named path to the JSON body of the request. If the destination value is an array, POST appends; if an object, it creates or replaces.
|
||||
|
||||
As a special case, many items can be added to an array if:
|
||||
|
||||
1. the path ends in `/...`
|
||||
2. the element of the path before `/...` refers to an array
|
||||
3. the payload is an array
|
||||
|
||||
In this case, the elements in the payload's array will be expanded, and each one will be appended to the destination array. In Go terms, this would have the same effect as:
|
||||
|
||||
```go
|
||||
baseSlice = append(baseSlice, newElems...)
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
Add a listener address:
|
||||
|
||||
<pre><code class="cmd bash">curl \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '":8080"' \
|
||||
"http://localhost:2019/config/apps/http/servers/myserver/listen"</code></pre>
|
||||
|
||||
Add multiple listener addresses:
|
||||
|
||||
<pre><code class="cmd bash">curl \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '[":8080", ":5133"]' \
|
||||
"http://localhost:2019/config/apps/http/servers/myserver/listen/..."</code></pre>
|
||||
|
||||
## PUT /config/[path]
|
||||
|
||||
Changes Caddy's configuration at the named path to the JSON body of the request. If the destination value is a position (index) in an array, PUT inserts; if an object, it strictly creates a new value.
|
||||
|
||||
### Example
|
||||
|
||||
Add a listener address in the first slot:
|
||||
|
||||
<pre><code class="cmd bash">curl -X PUT \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '":8080"' \
|
||||
"http://localhost:2019/config/apps/http/servers/myserver/listen/0"</code></pre>
|
||||
|
||||
|
||||
## PATCH /config/[path]
|
||||
|
||||
Changes Caddy's configuration at the named path to the JSON body of the request. PATCH strictly replaces an existing value or array element.
|
||||
|
||||
### Example
|
||||
|
||||
Replace the listener addresses:
|
||||
|
||||
<pre><code class="cmd bash">curl -X PATCH \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '[":8081", ":8082"]' \
|
||||
"http://localhost:2019/config/apps/http/servers/myserver/listen"</code></pre>
|
||||
|
||||
|
||||
|
||||
## DELETE /config/[path]
|
||||
|
||||
Removes Caddy's configuration at the named path. DELETE deletes the target value.
|
||||
|
||||
### Examples
|
||||
|
||||
To unload the entire current configuration but leave the process running:
|
||||
|
||||
<pre><code class="cmd bash">curl -X DELETE "http://localhost:2019/config/"</code></pre>
|
||||
|
||||
To stop only one of your HTTP servers:
|
||||
|
||||
<pre><code class="cmd bash">curl -X DELETE "http://localhost:2019/config/apps/http/servers/myserver"</code></pre>
|
||||
|
||||
|
||||
## Using `@id` in JSON
|
||||
|
||||
You can embed IDs in your JSON document for easier direct access to those parts of the JSON.
|
||||
|
||||
Simply add a field called `"@id"` to an object and give it a unique name. For example, if you had a reverse proxy handler that you wanted to access frequently:
|
||||
|
||||
```json
|
||||
{
|
||||
"@id": "my_proxy",
|
||||
"handler": "reverse_proxy"
|
||||
}
|
||||
```
|
||||
|
||||
To use it, simply make a request to the `/id/` API endpoint in the same way you would to the corresponding `/config/` endpoint, but without the whole path. The ID takes the request directly into that scope of the config for you.
|
||||
|
||||
For example, to access the upstreams of the reverse proxy without an ID, the path would be something like
|
||||
|
||||
```
|
||||
/config/apps/http/servers/myserver/routes/1/handle/0/upstreams
|
||||
```
|
||||
|
||||
but with an ID, the path becomes
|
||||
|
||||
```
|
||||
/id/my_proxy/upstreams
|
||||
```
|
||||
|
||||
which is much easier to remember and write by hand.
|
||||
|
||||
## Concurrent config changes
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
This section is for all `/config/` endpoints. It is experimental and subject to change.
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
Caddy's config API provides [ACID guarantees](https://en.wikipedia.org/wiki/ACID) for individual requests, but changes that involve more than a single request are subject to collisions or data loss if not properly synchronized.
|
||||
|
||||
For example, two clients may `GET /config/foo` at the same time, make an edit within that scope (config path), then call `POST|PUT|PATCH|DELETE /config/foo/...` at the same time to apply their changes, resulting in a collision: either one will overwrite the other, or the second might leave the config in an unintended state since it was applied to a different version of the config than it was prepared against. This is because the changes are not aware of each other.
|
||||
|
||||
Caddy's API does not support transactions spanning multiple requests, and HTTP is a stateless protocol. However, you can use the `Etag` trailer and `If-Match` header to detect and prevent collisions for any and all changes as a kind of optimistic concurrency control. This is useful if there is any chance that you are using Caddy's `/config/...` endpoints concurrently without synchronization. All responses to `GET /config/...` requests have an HTTP trailer called `Etag` that contains the path and a hash of the contents in that scope (e.g. `Etag: "/config/apps/http/servers 65760b8e"`). Simply set the `If-Match` header on a mutative request to that of an Etag trailer from a previous `GET` request.
|
||||
|
||||
The basic algorithm for this is as follows:
|
||||
|
||||
1. Perform a `GET` request to any scope `S` within the config. Hold onto the `Etag` trailer of the response.
|
||||
2. Make your desired change on the returned config.
|
||||
3. Perform a `POST|PUT|PATCH|DELETE` request within scope `S`, setting the `If-Match` header to the recent `Etag` value.
|
||||
4. If the response is HTTP 412 (Precondition Failed), repeat from step 1, or give up after too many attempts.
|
||||
|
||||
This algorithm safely allows multiple, overlapping changes to Caddy's configuration without explicit synchronization. It is designed so that simultaneous changes to different parts of the config don't require a retry: only changes that overlap the same scope of the config can possibly cause a collision and thus require a retry.
|
||||
|
||||
|
||||
## POST /adapt
|
||||
|
||||
Adapts a configuration to Caddy JSON without loading or running it. If successful, the resulting JSON document is returned in the response body.
|
||||
|
||||
The Content-Type header is used to specify the configuration format in the same way that [/load](#post-load) works. For example, to adapt a Caddyfile, set `Content-Type: text/caddyfile`.
|
||||
|
||||
This endpoint will adapt any configuration format as long as the associated [config adapter](/docs/config-adapters) is plugged in to your Caddy build.
|
||||
|
||||
### Examples
|
||||
|
||||
Adapt a Caddyfile to JSON:
|
||||
|
||||
<pre><code class="cmd bash">curl "http://localhost:2019/adapt" \
|
||||
-H "Content-Type: text/caddyfile" \
|
||||
--data-binary @Caddyfile</code></pre>
|
||||
|
||||
|
||||
## GET /pki/ca/<id>
|
||||
|
||||
Returns information about a particular [PKI app](/docs/json/apps/pki/) CA by its ID. If the requested CA ID is the default (`local`), then the CA will be provisioned if it has not already been. Other CA IDs will return an error if they have not been previously provisioned.
|
||||
|
||||
<pre><code class="cmd"><span class="bash">curl "http://localhost:2019/pki/ca/local" | jq</span>
|
||||
{
|
||||
"id": "local",
|
||||
"name": "Caddy Local Authority",
|
||||
"root_common_name": "Caddy Local Authority - 2022 ECC Root",
|
||||
"intermediate_common_name": "Caddy Local Authority - ECC Intermediate",
|
||||
"root_certificate": "-----BEGIN CERTIFICATE-----\nMIIB ... gRw==\n-----END CERTIFICATE-----\n",
|
||||
"intermediate_certificate": "-----BEGIN CERTIFICATE-----\nMIIB ... FzQ==\n-----END CERTIFICATE-----\n"
|
||||
}</code></pre>
|
||||
|
||||
|
||||
## GET /pki/ca/<id>/certificates
|
||||
|
||||
Returns the certificate chain of a particular [PKI app](/docs/json/apps/pki/) CA by its ID. If the requested CA ID is the default (`local`), then the CA will be provisioned if it has not already been. Other CA IDs will return an error if they have not been previously provisioned.
|
||||
|
||||
This endpoint is used internally by the [`caddy trust`](/docs/command-line#caddy-trust) command to allow installing the CA's root certificate to your system's trust store.
|
||||
|
||||
<pre><code class="cmd"><span class="bash">curl "http://localhost:2019/pki/ca/local/certificates"</span>
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIByDCCAW2gAwIBAgIQViS12trTXBS/nyxy7Zg9JDAKBggqhkjOPQQDAjAwMS4w
|
||||
...
|
||||
By75JkP6C14OfU733oElfDUMa5ctbMY53rWFzQ==
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBpDCCAUmgAwIBAgIQTS5a+3LUKNxC6qN3ZDR8bDAKBggqhkjOPQQDAjAwMS4w
|
||||
...
|
||||
9M9t0FwCIQCAlUr4ZlFzHE/3K6dARYKusR1ck4A3MtucSSyar6lgRw==
|
||||
-----END CERTIFICATE-----</code></pre>
|
||||
|
||||
|
||||
## GET /reverse_proxy/upstreams
|
||||
|
||||
Returns the current status of the configured reverse proxy upstreams (backends) as a JSON document.
|
||||
|
||||
<pre><code class="cmd"><span class="bash">curl "http://localhost:2019/reverse_proxy/upstreams" | jq</span>
|
||||
[
|
||||
{"address": "10.0.1.1:80", "num_requests": 4, "fails": 2},
|
||||
{"address": "10.0.1.2:80", "num_requests": 5, "fails": 4},
|
||||
{"address": "10.0.1.3:80", "num_requests": 3, "fails": 3}
|
||||
]</code></pre>
|
||||
|
||||
Each entry in the JSON array is a configured [upstream](/docs/json/apps/http/servers/routes/handle/reverse_proxy/upstreams/) stored in the global upstream pool.
|
||||
|
||||
- **address** is the dial address of the upstream. For SRV upstreams, this is the `lookup_srv` DNS name.
|
||||
- **num_requests** is the amount of active requests currently being handled by the upstream.
|
||||
- **fails** the current number of failed requests remembered, as configured by passive health checks.
|
||||
|
||||
If your goal is to determine a backend's availability, you will need to cross-check relevant properties of the upstream against the handler configuration you are utilizing. For example, if you've enabled [passive health checks](/docs/json/apps/http/servers/routes/handle/reverse_proxy/health_checks/passive/) for your proxies, then you need to also take into consideration the `fails` and `num_requests` values to determine if an upstream is considered available: check that the `fails` amount is less than your configured maximum amount of failures for your proxy (i.e. [`max_fails`](/docs/json/apps/http/servers/routes/handle/reverse_proxy/health_checks/passive/max_fails/)), and that `num_requests` is less than or equal to your configured amount of maximum requests per upstream (i.e. [`unhealthy_request_count`](/docs/json/apps/http/servers/routes/handle/reverse_proxy/health_checks/passive/unhealthy_request_count/) for the whole proxy, or [`max_requests`](/docs/json/apps/http/servers/routes/handle/reverse_proxy/upstreams/max_requests/) for individual upstreams).
|
157
src/docs/markdown/architecture.md
Normal file
157
src/docs/markdown/architecture.md
Normal file
|
@ -0,0 +1,157 @@
|
|||
---
|
||||
title: Architecture
|
||||
---
|
||||
|
||||
Architecture
|
||||
============
|
||||
|
||||
Caddy is a single, self-contained, static binary with zero external dependencies because it's written in Go. These values comprise important parts of the project's vision because they simplify deployment and reduce tedious troubleshooting in production environments.
|
||||
|
||||
If there's no dynamic linking, then how can it be extended? Caddy sports a novel plugin architecture that expands its capabilities far beyond that of any other web server, even those with external (dynamically-linked) dependencies.
|
||||
|
||||
Our philosophy of "fewer moving parts" ultimately results in more reliable, more manageable, less expensive sites—especially at scale. This semi-technical document describes how we achieve that goal through software engineering.
|
||||
|
||||
|
||||
## Overview
|
||||
|
||||
Caddy consists of a command, core library, and modules.
|
||||
|
||||
The **command** provides the [command line interface](/docs/command-line) you are hopefully familiar with. It's how you launch the process from your operating system. The amount of code and logic here is fairly minimal, and has only what is needed to bootstrap the core in the user's desired way. We intentionally avoid using flags and environment variables for configuration except as they pertain to bootstrapping config.
|
||||
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
Modules can add subcommands to the command line interface! For instance, that's where the [`caddy file-server`](/docs/command-line#caddy-file-server) command comes from. These added commands may have any flags or use any environment variables they want, even though the core Caddy commands minimize their use.
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
The **[core library](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc)**, or "core" of Caddy, primarily manages configuration. It can [`Run()`](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#Run) a new configuration or [`Stop()`](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#Stop) a running config. It also provides various utilities, types, and values for modules to use.
|
||||
|
||||
**Modules** do everything else. Many modules come built into Caddy, which are called the _standard modules_. These are determined to be the most useful to the most users.
|
||||
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
Sometimes the terms *module*, *plugin*, and *extension* get used interchangably, and usually that's OK. Technically, all modules are plugins, but not all plugins are modules. Modules are specifically a kind of plugin that extends Caddy's [config structure](/docs/json/).
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
|
||||
|
||||
## Caddy core
|
||||
|
||||
At its core, Caddy merely loads an initial configuration ("config") or, if there isn't one, opens a socket to accept new configuration later on.
|
||||
|
||||
A [Caddy configuration](/docs/json/) is a JSON document, with some fields at its top level:
|
||||
|
||||
```json
|
||||
{
|
||||
"admin": {},
|
||||
"logging": {},
|
||||
"apps": {•••},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The core of Caddy knows how to work with some of these fields natively:
|
||||
|
||||
- [`admin`](/docs/json/admin/) so it can set up the [admin API](/docs/api) and manage the process
|
||||
- [`logging`](/docs/json/logging/) so it can [emit logs](/docs/logging)
|
||||
|
||||
But other top-level fields (like [`apps`](/docs/json/apps/)) are opaque to the core of Caddy. In fact, all Caddy knows to do with the bytes in `apps` is deserialize them into an interface type that it can call two methods on:
|
||||
|
||||
1. `Start()`
|
||||
2. `Stop()`
|
||||
|
||||
... and that's it. It calls `Start()` on each app when a config is loaded, and `Stop()` on each app when a config is unloaded.
|
||||
|
||||
When an app module is started, it initiates the app's module lifecycle.
|
||||
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
If you are a programmer who is building Caddy modules, you can find analogous information in our [Extending Caddy](/docs/extending-caddy) guide, but with more focus on code.
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
## Module lifecycle
|
||||
|
||||
There are two kinds of modules: _host modules_ and _guest modules_.
|
||||
|
||||
**Host modules** (or "parent" modules) are those that load other modules.
|
||||
|
||||
**Guest modules** (or "child" modules) are those that get loaded. All modules are guest modules -- even app modules.
|
||||
|
||||
Modules get loaded, are provisioned and validated, get used, then are cleaned up, in this sequence:
|
||||
|
||||
1. Loaded
|
||||
2. Provisioned and validated
|
||||
3. Used
|
||||
4. Cleaned up
|
||||
|
||||
Caddy kicks off the module lifecycle when a config is loaded first by initializing all the configured app modules. From there, it's turtles all the way down as each app module takes it the rest of the way.
|
||||
|
||||
### Load phase
|
||||
|
||||
Loading a module involves deserializing its JSON bytes into a typed value in memory. That's... basically it. It's just decoding JSON into a value.
|
||||
|
||||
### Provision phase
|
||||
|
||||
This phase is where most of the setup work goes. All modules get a chance to provision themselves after being loaded.
|
||||
|
||||
Since any properties from the JSON encoding will already have been decoded, only additional setup needs to take place here. The most common task during provisioning is setting up guest modules. In other words, provisioning a host module also results in provisioning its guest modules, all the way down.
|
||||
|
||||
You can get a sense for this by [traversing Caddy's JSON structure in our docs](/docs/json/). Anywhere you see `{•••}` is where guest modules may be used; and as you click into one, you can continue exploring all the way down until there are no more guest modules.
|
||||
|
||||
Other common provisioning tasks are setting up internal values that will be used during the module's lifetime, or standardizing inputs. For example, the [`http.matchers.remote_ip`](/docs/modules/http.matchers.remote_ip) module uses the provisioning phase to parse CIDR values out of the string inputs it received from the JSON. That way, it doesn't have to do this during every HTTP request, and is more efficient as a result.
|
||||
|
||||
Validation also can take place in the provision phase. If a module's resulting config is invalid, an error can be returned here which aborts the entire config load process.
|
||||
|
||||
### Use phase
|
||||
|
||||
Once a guest module is provisioned and validated, it can be used by its host module. What exactly this means is up to each host module.
|
||||
|
||||
Each module has an ID, which consists of a namespace and a name in that namespace. For example, [`http.handlers.reverse_proxy`](/docs/modules/http.handlers.reverse_proxy) is an HTTP handler because it is in the `http.handlers` namespace, and its name is `reverse_proxy`. All modules in the `http.handlers` namespace satisfy the same interface, known to the host module. Thus, the `http` app knows how to load and use these kinds of modules.
|
||||
|
||||
### Cleanup phase
|
||||
|
||||
When it is time for a config to be stopped, all modules get unloaded. If a module allocated any resources that should be freed, it has an opportunity to do so in the cleanup phase.
|
||||
|
||||
|
||||
## Plugging in
|
||||
|
||||
A module -- or any Caddy plugin -- gets "plugged in" to Caddy by adding an `import` for the module's package. By importing the package, [the module registers itself](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#RegisterModule) with the Caddy core, so when the Caddy process starts, it knows each module by name. It can even associate between module values and names, and vice-versa.
|
||||
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
Plugins can be added without modifying the Caddy code base at all. There are instructions [in the readme](https://github.com/caddyserver/caddy/#with-version-information-andor-plugins) for doing this!
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
## Managing configuration
|
||||
|
||||
Changing a running server's active configuration (often called a "reload") can be tricky with the high levels of concurrency and thousands of parameters that servers require. Caddy solves this problem elegantly using a design that has many benefits:
|
||||
|
||||
- No interruption to running services
|
||||
- Granular config changes are possible
|
||||
- Only one lock required (in the background)
|
||||
- All reloads are atomic, consistent, isolated, and mostly durable ("ACID")
|
||||
- Minimal global state
|
||||
|
||||
You can [watch a video about the design of Caddy 2 here](https://www.youtube.com/watch?v=EhJO8giOqQs).
|
||||
|
||||
A config reload works by provisioning the new modules, and if all succeed, the old ones are cleaned up. For a brief period, two configs are operational at the same time.
|
||||
|
||||
Each configuration is associated with a [context](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#Context) which holds all the module state, so most state never escapes the scope of a config. This is good news for correctness, performance, and simplicity!
|
||||
|
||||
However, sometimes truly global state is necessary. For example, the reverse proxy may keep track of the health of its upstreams; since there is only one of each upstream globally, it would be bad if it forgot about them every time a minor config change was made. Fortunately, Caddy [provides facilities](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#UsagePool) similar to a language runtime's garbage collector to keep global state tidy.
|
||||
|
||||
One obvious approach to on-line config updates is to synchronize access to every single config parameter, even in hot paths. This is unbelievably bad in terms of performance and complexity—especially at scale—so Caddy does not use this approach.
|
||||
|
||||
Instead, configs are treated as immutable, atomic units: either the whole thing is replaced, or nothing gets changed. The [admin API endpoints](/docs/api)—which permit granular changes by traversing into the structure—mutate only an in-memory representation of the config, from which a whole new config document is generated and loaded. This approach has vast benefits in terms of simplicity, performance, and consistency. Since there is only one lock, it is easy for Caddy to process rapid reloads.
|
||||
|
282
src/docs/markdown/automatic-https.md
Normal file
282
src/docs/markdown/automatic-https.md
Normal file
|
@ -0,0 +1,282 @@
|
|||
---
|
||||
title: "Automatic HTTPS"
|
||||
---
|
||||
|
||||
# Automatic HTTPS
|
||||
|
||||
**Caddy is the first and only web server to use HTTPS automatically _and by default_.**
|
||||
|
||||
Automatic HTTPS provisions TLS certificates for all your sites and keeps them renewed. It also redirects HTTP to HTTPS for you! Caddy uses safe and modern defaults -- no downtime, extra configuration, or separate tooling is required.
|
||||
|
||||
<aside class="tip">
|
||||
Caddy innovated automatic HTTPS technology; we've been doing this since the first day it was feasible in 2015. Caddy's HTTPS automation logic is the most mature and robust in the world.
|
||||
</aside>
|
||||
|
||||
Here's a 28-second video showing how it works:
|
||||
|
||||
<iframe width="100%" height="480" src="https://www.youtube-nocookie.com/embed/nk4EWHvvZtI?rel=0" frameborder="0" allowfullscreen=""></iframe>
|
||||
|
||||
|
||||
**Menu:**
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Activation](#activation)
|
||||
- [Effects](#effects)
|
||||
- [Hostname requirements](#hostname-requirements)
|
||||
- [Local HTTPS](#local-https)
|
||||
- [Testing](#testing)
|
||||
- [ACME Challenges](#acme-challenges)
|
||||
- [On-Demand TLS](#on-demand-tls)
|
||||
- [Errors](#errors)
|
||||
- [Storage](#storage)
|
||||
- [Wildcard certificates](#wildcard-certificates)
|
||||
|
||||
|
||||
|
||||
## Overview
|
||||
|
||||
**By default, Caddy serves all sites over HTTPS.**
|
||||
|
||||
- Caddy serves IP addresses and local/internal hostnames over HTTPS using self-signed certificates that are automatically trusted locally (if permitted).
|
||||
- Examples: `localhost`, `127.0.0.1`
|
||||
- Caddy serves public DNS names over HTTPS using certificates from a public ACME CA such as [Let's Encrypt](https://letsencrypt.org) or [ZeroSSL](https://zerossl.com).
|
||||
- Examples: `example.com`, `sub.example.com`, `*.example.com`
|
||||
|
||||
Caddy keeps all managed certificates renewed and redirects HTTP (default port `80`) to HTTPS (default port `443`) automatically.
|
||||
|
||||
**For local HTTPS:**
|
||||
|
||||
- Caddy may prompt for a password to install its unique root certificate into your trust store. This happens only once per root; and you can remove it at any time.
|
||||
- Any client accessing the site without trusting Caddy's root CA certificate will show security errors.
|
||||
|
||||
**For public domain names:**
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
These are common requirements for any basic production website, not just Caddy. The main difference is to set your DNS records properly **before** running Caddy so it can provision certificates.
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
- If your domain's A/AAAA records point to your server,
|
||||
- ports `80` and `443` are open externally,
|
||||
- Caddy can bind to those ports (_or_ those ports are forwarded to Caddy),
|
||||
- your [data directory](/docs/conventions#data-directory) is writeable and persistent,
|
||||
- and your domain name appears somewhere relevant in the config,
|
||||
|
||||
then sites will be served over HTTPS automatically. You won't have to do anything else about it. It just works!
|
||||
|
||||
Because HTTPS utilizes a shared, public infrastructure, you as the server admin should understand the rest of the information on this page so that you can avoid unnecessary problems, troubleshoot them when they occur, and properly configure advanced deployments.
|
||||
|
||||
|
||||
|
||||
## Activation
|
||||
|
||||
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 [host matcher](/docs/json/apps/http/servers/routes/match/host/) in a [JSON route](/docs/modules/http#servers/routes)
|
||||
- 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
|
||||
|
||||
Any of the following will prevent automatic HTTPS from being activated, either in whole or in part:
|
||||
|
||||
- Explicitly disabling it [via JSON](/docs/json/apps/http/servers/automatic_https/) or [via Caddyfile](/docs/caddyfile/options#auto-https)
|
||||
- Not providing any hostnames or IP addresses in the config
|
||||
- Listening exclusively on the HTTP port
|
||||
- Prefixing the [site address](/docs/caddyfile/concepts#addresses) with `http://` in the Caddyfile
|
||||
- Manually loading certificates (unless [`ignore_loaded_certificates`](/docs/json/apps/http/servers/automatic_https/ignore_loaded_certificates/) is set)
|
||||
|
||||
**Special cases:**
|
||||
|
||||
- Domains ending in `.ts.net` will not be managed by Caddy. Instead, Caddy will automatically attempt to get these certificates at handshake-time from the locally-running [Tailscale](https://tailscale.com) instance. This requires that [HTTPS is enabled in your Tailscale account](https://tailscale.com/kb/1153/enabling-https/) and the Caddy process must either be running as root, or you must configure `tailscaled` to give your Caddy user [permission to fetch certificates](https://github.com/caddyserver/caddy/pull/4541#issuecomment-1021568348).
|
||||
|
||||
|
||||
## Effects
|
||||
|
||||
When automatic HTTPS is activated, the following occurs:
|
||||
|
||||
- Certificates are obtained and renewed for [all 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`)
|
||||
|
||||
Automatic HTTPS never overrides explicit configuration.
|
||||
|
||||
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)).
|
||||
|
||||
|
||||
## Hostname requirements
|
||||
|
||||
All hostnames (domain names) qualify for fully-managed certificates if they:
|
||||
|
||||
- are non-empty
|
||||
- consist only of alphanumerics, hyphens, dots, and wildcard (`*`)
|
||||
- do not start or end with a dot ([RFC 1034](https://tools.ietf.org/html/rfc1034#section-3.5))
|
||||
|
||||
In addition, hostnames qualify for publicly-trusted certificates if they:
|
||||
|
||||
- are not localhost (including `.localhost` and `.local` TLDs)
|
||||
- are not an IP address
|
||||
- have only a single wildcard `*` as the left-most label
|
||||
|
||||
|
||||
## Local HTTPS
|
||||
|
||||
Caddy uses HTTPS automatically for all sites with a host (domain, IP, or hostname) specified, including internal and local hosts. Some hosts are either not public (e.g. `127.0.0.1`, `localhost`) or do not generally qualify for publicly-trusted certificates (e.g. IP addresses -- you can get certificates for them, but only from some CAs). These are still served over HTTPS unless disabled.
|
||||
|
||||
To serve non-public sites over HTTPS, Caddy generates its own certificate authority (CA) and uses it to sign certificates. The trust chain consists of a root and intermediate certificate. Leaf certificates are signed by the intermediate. They are stored in [Caddy's data directory](/docs/conventions#data-directory) at `pki/authorities/local`.
|
||||
|
||||
Caddy's local CA is powered by [Smallstep libraries](https://smallstep.com/certificates/).
|
||||
|
||||
Local HTTPS does not use ACME nor does it perform any DNS validation. It works only on the local machine and is trusted only where the CA's root certificate is installed.
|
||||
|
||||
### CA Root
|
||||
|
||||
The root's private key is uniquely generated using a cryptographically-secure pseudorandom source and persisted to storage with limited permissions. It is loaded into memory only to perform signing tasks, after which it leaves scope to be garbage-collected.
|
||||
|
||||
Although Caddy can be configured to sign with the root directly (to support non-compliant clients), this is disabled by default, and the root key is only used to sign intermediates.
|
||||
|
||||
The first time a root key is used, Caddy will try to install it into the system's local trust store(s). If it does not have permission to do so, it will prompt for a password. This behavior can be disabled in the configuration if it is not desired. If this fails due to being run as an unprivileged user, you may run [`caddy trust`](/docs/command-line#caddy-trust) to retry installation as a privileged user.
|
||||
|
||||
<aside class="tip">
|
||||
It is safe to trust Caddy's root certificate on your own machine as long as your computer is not compromised and your unique root key is not leaked.
|
||||
</aside>
|
||||
|
||||
After Caddy's root CA is installed, you will see it in your local trust store as "Caddy Local Authority" (unless you've configured a different name). You can uninstall it any time if you wish (the [`caddy untrust`](/docs/command-line#caddy-untrust) command makes this easy).
|
||||
|
||||
Note that automatically installing the certificate into the local trust stores is for convenience only and isn't guaranteed to work, especially if containers are being used or if Caddy is being run as an unprivileged system service. Ultimately, if you are relying on internal PKI, it is the system administrator's responsibility to ensure Caddy's root CA is properly added to the necessary trust stores (this is outside the scope of the web server).
|
||||
|
||||
|
||||
### CA Intermediates
|
||||
|
||||
An intermediate certificate and key will also be generated, which will be used for signing leaf (individual site) certificates.
|
||||
|
||||
Unlike the root certificate, intermediate certificates have a much shorter lifetime and will automatically be renewed as needed.
|
||||
|
||||
|
||||
## Testing
|
||||
|
||||
To test or experiment with your Caddy configuration, make sure you [change the ACME endpoint](/docs/modules/tls.issuance.acme#ca) to a staging or development URL, otherwise you are likely to hit rate limits which can block your access to HTTPS for up to a week, depending on which rate limit you hit.
|
||||
|
||||
One of Caddy's default CAs is [Let's Encrypt](https://letsencrypt.org/), which has a [staging endpoint](https://letsencrypt.org/docs/staging-environment/) that is not subject to the same [rate limits](https://letsencrypt.org/docs/rate-limits/):
|
||||
|
||||
```
|
||||
https://acme-staging-v02.api.letsencrypt.org/directory
|
||||
```
|
||||
|
||||
## ACME challenges
|
||||
|
||||
Obtaining a publicly-trusted TLS certificate requires validation from a publicly-trusted, third-party authority. These days, this validation process is automated with the [ACME protocol](https://tools.ietf.org/html/rfc8555), and can be performed one of three ways ("challenge types"), described below.
|
||||
|
||||
The first two challenge types are enabled by default. If multiple challenges are enabled, Caddy chooses one at random to avoid accidental dependence on a particular challenge. Over time, it learns which challenge type is most successful and will begin to prefer it first, but will fall back to other available challenge types if necessary.
|
||||
|
||||
|
||||
### HTTP challenge
|
||||
|
||||
The HTTP challenge performs an authoritative DNS lookup for the candidate hostname's A/AAAA record, then requests a temporary cryptographic resource over port `80` using HTTP. If the CA sees the expected resource, a certificate is issued.
|
||||
|
||||
This challenge requires port `80` to be externally accessible. If Caddy cannot listen on port 80, packets from port `80` must be forwarded to Caddy's [HTTP port](/docs/json/apps/http/http_port/).
|
||||
|
||||
This challenge is enabled by default and does not require explicit configuration.
|
||||
|
||||
|
||||
### TLS-ALPN challenge
|
||||
|
||||
The TLS-ALPN challenge performs an authoritative DNS lookup for the candidate hostname's A/AAAA record, then requests a temporary cryptographic resource over port `443` using a TLS handshake containing special ServerName and ALPN values. If the CA sees the expected resource, a certificate is issued.
|
||||
|
||||
This challenge requires port `443` to be externally accessible. If Caddy cannot listen on port 443, packets from port `443` must be forwarded to Caddy's [HTTPS port](/docs/json/apps/http/https_port/).
|
||||
|
||||
This challenge is enabled by default and does not require explicit configuration.
|
||||
|
||||
|
||||
### DNS challenge
|
||||
|
||||
The DNS challenge performs an authoritative DNS lookup for the candidate hostname's `TXT` records, and looks for a special `TXT` record with a certain value. If the CA sees the expected value, a certificate is issued.
|
||||
|
||||
This challenge does not require any open ports, and the server requesting a certificate does not need to be externally accessible. However, the DNS challenge requires configuration. Caddy needs to know the credentials to access your domain's DNS provider so it can set (and clear) the special `TXT` records. If the DNS challenge is enabled, other challenges are disabled by default.
|
||||
|
||||
Since ACME CAs follow DNS standards when looking up `TXT` records for challenge verification, you can use CNAME records to delegate answering the challenge to other DNS zones. This can be used to delegate the `_acme-challenge` subdomain to another zone. This is particularly useful if your DNS provider doesn't provide an API, or isn't supported by one of the DNS plugins for Caddy.
|
||||
|
||||
DNS provider support is a community effort. [Learn how to enable the DNS challenge for your provider at our wiki.](https://caddy.community/t/how-to-use-dns-provider-modules-in-caddy-2/8148)
|
||||
|
||||
|
||||
## On-Demand TLS
|
||||
|
||||
Caddy pioneered a new technology we call **On-Demand TLS**, which dynamically obtains a new certificate during the first TLS handshake that requires it, rather than at config load. Crucially, this does not require specifying the domain names in your configuration ahead of time.
|
||||
|
||||
Many businesses rely on this unique feature to scale their TLS deployments at lower cost and without operational headaches when serving tens of thousands of sites.
|
||||
|
||||
On-demand TLS is useful if:
|
||||
|
||||
- you do not know all the domain names when you start or reload your server,
|
||||
- domain names might not be properly configured right away (DNS records not yet set),
|
||||
- you are not in control of the domain names (e.g. they are customer domains).
|
||||
|
||||
When on-demand TLS is enabled, you do not need to specify the domain names in your config in order to get certificates for them. Instead, when a TLS handshake is received for a server name (SNI) that Caddy does not yet have a certificate for, the handshake is held while Caddy obtains a certificate to use to complete the handshake. The delay is usually only a few seconds, and only that initial handshake is slow. All future handshakes are fast because certificates are cached and reused, and renewals happen in the background. Future handshakes may trigger maintenance for the certificate to keep it renewed, but this maintenance happens in the background if the certificate hasn't expired yet.
|
||||
|
||||
### Using On-Demand TLS
|
||||
|
||||
**In production environments, on-demand TLS must be both enabled and restricted. Enabling without restricting opens your server to attack.**
|
||||
|
||||
Enabling on-demand TLS happens in [TLS automation policies](/docs/json/apps/tls/automation/policies/) if using the JSON config, or [in site blocks with the `tls` directive](/docs/caddyfile/directives/tls) if using the Caddyfile.
|
||||
|
||||
To prevent abuse of this feature, you must configure restrictions. This is done in the [`automation` object of the JSON config](/docs/json/apps/tls/automation/on_demand/), or the [`on_demand_tls` global option](/docs/caddyfile/options#on-demand-tls) of the Caddyfile. Restrictions are "global" and aren't configurable per-site or per-domain. The primary restriction is an "ask" endpoint to which Caddy will send an HTTP request to ask if it has permission to obtain and manage a certificate for the domain in the handshake. This means you will need some internal backend that can, for example, query the accounts table of your database and see if a customer has signed up with that domain name.
|
||||
|
||||
You can also configure rate limits as restrictions, though rate limits alone are not a sufficient protection.
|
||||
|
||||
Be mindful of how quickly your CA is able to issue certificates. If it takes more than a few seconds, this will negatively impact the user experience (for the first client only).
|
||||
|
||||
Due to its deferred nature and potential for abuse (if not mitigated through proper configuration), we recommend enabling on-demand TLS only when your actual use case is described above.
|
||||
|
||||
[See our wiki article for more information about using on-demand TLS effectively.](https://caddy.community/t/serving-tens-of-thousands-of-domains-over-https-with-caddy/11179)
|
||||
|
||||
## Errors
|
||||
|
||||
Caddy does its best to continue if errors occur with certificate management.
|
||||
|
||||
By default, certificate management is performed in the background. This means it will not block startup or slow down your sites. However, it also means that the server will be running even before all certificates are available. Running in the background allows Caddy to retry with exponential backoff over a long period of time.
|
||||
|
||||
Here's what happens if there's an error obtaining or renewing a certificate:
|
||||
|
||||
1. Caddy retries once after a brief pause just in case it was a fluke
|
||||
2. Caddy pauses briefly, then switches to the next enabled challenge type
|
||||
3. After all enabled challenge types have been tried, [it tries the next configured issuer](#issuer-fallback)
|
||||
- Let's Encrypt
|
||||
- ZeroSSL
|
||||
4. After all issuers have been tried, it backs off exponentially
|
||||
- Maximum of 1 day between attempts
|
||||
- For up to 30 days
|
||||
|
||||
During retries with Let's Encrypt, Caddy switches to their [staging environment](https://letsencrypt.org/docs/staging-environment/) to avoid rate limit concerns. This isn't a perfect strategy, but in general it's helpful.
|
||||
|
||||
ACME challenges take at least a few seconds, and internal rate limiting helps mitigate accidental abuse. Caddy uses internal rate limiting in addition to what you or the CA configure so that you can hand Caddy a platter with a million domain names and it will gradually -- but as fast as it can -- obtain certificates for all of them. Caddy's internal rate limit is currently 10 attempts per ACME account per 10 seconds.
|
||||
|
||||
To avoid leaking resources, Caddy aborts in-flight tasks (including ACME transactions) when config is changed. While Caddy is capable of handling frequent config reloads, be mindful of operational considerations such as this, and consider batching config changes to reduce reloads and give Caddy a chance to actually finish obtaining certificates in the background.
|
||||
|
||||
### Issuer fallback
|
||||
|
||||
Caddy is the first (and so far only) server to support fully-redundant, automatic failover to other CAs in the event it cannot successfully get a certificate.
|
||||
|
||||
By default, Caddy enables two ACME-compatible CAs: [**Let's Encrypt**](https://letsencrypt.org) and [**ZeroSSL**](https://zerossl.com). If Caddy cannot get a certificate from Let's Encrypt, it will try with ZeroSSL; if both fail, it will backoff and retry again later. In your config, you can customize which issuers Caddy uses to obtain certificates, either universally or for specific names.
|
||||
|
||||
|
||||
## Storage
|
||||
|
||||
Caddy will store public certificates, private keys, and other assets in its [configured storage facility](/docs/json/storage/) (or the default one, if not configured -- see link for details).
|
||||
|
||||
**The main thing you need to know using the default config is that the `$HOME` folder must be writeable and persistent.** To help you troubleshoot, Caddy prints its environment variables at startup if the `--environ` flag is specified.
|
||||
|
||||
Any Caddy instances that are configured to use the same storage will automatically share those resources and coordinate certificate management as a cluster.
|
||||
|
||||
Before attempting any ACME transactions, Caddy will test the configured storage to ensure it is writeable and has sufficient capacity. This helps reduce unnecessary lock contention.
|
||||
|
||||
|
||||
## Wildcard certificates
|
||||
|
||||
Caddy can obtain and manage wildcard certificates when it is configured to serve a site with a qualifying wildcard name. A site name qualifies for a wildcard if only its left-most domain label is a wildcard. For example, `*.example.com` qualifies, but these do not: `sub.*.example.com`, `foo*.example.com`, `*bar.example.com`, and `*.*.example.com`.
|
||||
|
||||
If using the Caddyfile, Caddy takes site names literally with regards to the certificate subject names. In other words, a site defined as `sub.example.com` will cause Caddy to manage a certificate for `sub.example.com`, and a site defined as `*.example.com` will cause Caddy to manage a wildcard certificate for `*.example.com`. You can see this demonstrated on our [Common Caddyfile Patterns](/docs/caddyfile/patterns#wildcard-certificates) page. If you need different behavior, the [JSON config](/docs/json/) gives you more precise control over certificate subjects and site names ("host matchers").
|
||||
|
||||
Wildcard certificates represent a wide degree of authority and should only be used when you have so many subdomains that managing individual certificates for them would strain the PKI or cause you to hit CA-enforced rate limits.
|
||||
|
||||
**Note:** [Let's Encrypt requires](https://letsencrypt.org/docs/challenge-types/) the [DNS challenge](#dns-challenge) to obtain wildcard certificates.
|
97
src/docs/markdown/build.md
Normal file
97
src/docs/markdown/build.md
Normal file
|
@ -0,0 +1,97 @@
|
|||
---
|
||||
title: "Build from source"
|
||||
---
|
||||
|
||||
# Build from source
|
||||
|
||||
Requirements:
|
||||
|
||||
- [Go](https://golang.org/doc/install) 1.17 or newer
|
||||
|
||||
Clone the repository:
|
||||
|
||||
<pre><code class="cmd bash">git clone "https://github.com/caddyserver/caddy.git"</code></pre>
|
||||
|
||||
If you don't have git, you can download the source code as a file archive [from GitHub](https://github.com/caddyserver/caddy). Each [release](https://github.com/caddyserver/caddy/releases) also has source snapshots.
|
||||
|
||||
Build:
|
||||
|
||||
<pre><code class="cmd"><span class="bash">cd caddy/cmd/caddy/</span>
|
||||
<span class="bash">go build</span></code></pre>
|
||||
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
Due to [a bug in Go](https://github.com/golang/go/issues/29228), these basic steps do not embed version information. If you want the version (`caddy version`), you need to compile Caddy as a dependency rather than as the main module. Instructions for this are in Caddy's [main.go](https://github.com/caddyserver/caddy/blob/master/cmd/caddy/main.go) file. Or, you can use [`xcaddy`](#xcaddy) which automates this.
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
## xcaddy
|
||||
|
||||
The [`xcaddy` command](https://github.com/caddyserver/xcaddy) is the easiest way to build Caddy with version information and/or plugins.
|
||||
|
||||
Requirements:
|
||||
|
||||
- Go installed (see above)
|
||||
- Make sure [`xcaddy`](https://github.com/caddyserver/xcaddy/releases) is in your PATH
|
||||
|
||||
You do **not** need to download the Caddy source code (it will do that for you).
|
||||
|
||||
Then building Caddy (with version information) is as easy as:
|
||||
|
||||
<pre><code class="cmd bash">xcaddy build</code></pre>
|
||||
|
||||
To build with plugins, use `--with`:
|
||||
|
||||
<pre><code class="cmd bash">xcaddy build \
|
||||
--with github.com/caddyserver/nginx-adapter
|
||||
--with github.com/caddyserver/ntlm-transport@v0.1.1</code></pre>
|
||||
|
||||
As you can see, you can customize the versions of plugins with `@` syntax. Versions can be a tag name, commit SHA, or branch.
|
||||
|
||||
Cross-platform compilation with `xcaddy` works the same as with the `go` command (see below).
|
||||
|
||||
|
||||
## Cross-platform
|
||||
|
||||
Go programs are easy to compile for other platforms. Just set the `GOOS`, `GOARCH`, and/or `GOARM` environment variables that are different. ([See the go documentation for details.](https://golang.org/doc/install/source#environment))
|
||||
|
||||
For example, to compile Caddy for Windows when you're not on Windows:
|
||||
|
||||
<pre><code class="cmd bash">GOOS=windows go build</code></pre>
|
||||
|
||||
Or similarly for Linux ARMv6 when you're not on Linux or on ARMv6:
|
||||
|
||||
<pre><code class="cmd bash">GOOS=linux GOARCH=arm GOARM=6 go build</code></pre>
|
||||
|
||||
The same works for `xcaddy`. To cross-compile for macOS:
|
||||
|
||||
<pre><code class="cmd bash">GOOS=darwin xcaddy build</code></pre>
|
||||
|
||||
## Package support files for custom builds for Debian/Ubuntu/Raspbian
|
||||
|
||||
This procedure aims to simplify running custom `caddy` binaries while keeping support files from the `caddy` package.
|
||||
|
||||
This procedure allows users to take advantage of the default configuration, systemd service files and bash-completion from the official package.
|
||||
|
||||
Requirements:
|
||||
- Install `caddy` package according to these [instructions](https://caddyserver.com/docs/install#debian-ubuntu-raspbian)
|
||||
- Build your custom `caddy` binary according to the procedure listed in this document. (see above)
|
||||
- Your custom `caddy` binary should be located in the current directory.
|
||||
|
||||
Procedure:
|
||||
<pre><code class="cmd"><span class="bash">sudo dpkg-divert --divert /usr/bin/caddy.default --rename /usr/bin/caddy</span>
|
||||
<span class="bash">sudo mv ./caddy /usr/bin/caddy.custom</span>
|
||||
<span class="bash">sudo update-alternatives --install /usr/bin/caddy caddy /usr/bin/caddy.default 10</span>
|
||||
<span class="bash">sudo update-alternatives --install /usr/bin/caddy caddy /usr/bin/caddy.custom 50</span>
|
||||
</code></pre>
|
||||
|
||||
|
||||
`dpkg-divert` will move `/usr/bin/caddy` binary to `/usr/bin/caddy.default` and put a diversion in place in case any package want to install a file to this location.
|
||||
|
||||
`update-alternatives` will create a symlink from the desired caddy binary to `/usr/bin/caddy`
|
||||
|
||||
You can change between the custom and default `caddy` binaries by executing
|
||||
<pre><code class="cmd bash">update-alternatives --config caddy</code></pre>
|
||||
and following the on screen information.
|
283
src/docs/markdown/caddyfile-tutorial.md
Normal file
283
src/docs/markdown/caddyfile-tutorial.md
Normal file
|
@ -0,0 +1,283 @@
|
|||
---
|
||||
title: Caddyfile Tutorial
|
||||
---
|
||||
|
||||
# Caddyfile Tutorial
|
||||
|
||||
This tutorial will teach you the basics of the [HTTP Caddyfile](/docs/caddyfile) so that you can quickly and easily produce good-looking, functional site configs.
|
||||
|
||||
**Objectives:**
|
||||
- 🔲 First site
|
||||
- 🔲 Static file server
|
||||
- 🔲 Templates
|
||||
- 🔲 Compression
|
||||
- 🔲 Multiple sites
|
||||
- 🔲 Matchers
|
||||
- 🔲 Environment variables
|
||||
- 🔲 Comments
|
||||
|
||||
**Prerequisites:**
|
||||
- Basic terminal / command line skills
|
||||
- Basic text editor skills
|
||||
- `caddy` in your PATH
|
||||
|
||||
---
|
||||
|
||||
Create a new text file named `Caddyfile` (no extension).
|
||||
|
||||
The first thing you should type is your site's [address](/docs/caddyfile/concepts#addresses):
|
||||
|
||||
```caddy
|
||||
localhost
|
||||
```
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
If the HTTP and HTTPS ports (80 and 443, respectively) are privileged ports on your OS, you will either need to run with elevated privileges or use a higher port. To use a higher port, just change the address to something like `localhost:2015` and change the HTTP port using the [http_port](/docs/caddyfile/options) Caddyfile option.
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
Then hit enter and type what you want it to do. For this tutorial, make your Caddyfile look like this:
|
||||
|
||||
```caddy
|
||||
localhost
|
||||
|
||||
respond "Hello, world!"
|
||||
```
|
||||
|
||||
Save that and run Caddy (since this is a training tutorial, we'll use the `--watch` flag so changes to our Caddyfile are applied automatically):
|
||||
|
||||
<pre><code class="cmd bash">caddy run --watch</code></pre>
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
If you get permissions errors, try using a higher port in your address (like `localhost:2015`) and [change the HTTP port](/docs/caddyfile/options), or run with elevated privileges.
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
The first time, you'll be asked for your password. This is so Caddy can serve your site over HTTPS.
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
Caddy serves all sites over HTTPS by default as long as a host or IP is part of the site's address. [Automatic HTTPS](/docs/automatic-https) can be disabled by prefixing the address with `http://` explicitly.
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
<aside class="complete">First site</aside>
|
||||
|
||||
Open [localhost](https://localhost) in your browser and see your web server working, complete with HTTPS!
|
||||
|
||||
<aside class="tip">
|
||||
You might need to restart your browser if you get a certificate error the first time.
|
||||
</aside>
|
||||
|
||||
That's not particularly exciting, so let's change our static response to a [file server](/docs/caddyfile/directives/file_server) with directory listings enabled:
|
||||
|
||||
```caddy
|
||||
localhost
|
||||
|
||||
file_server browse
|
||||
```
|
||||
|
||||
Save your Caddyfile, then refresh your browser tab. You should either see a list of files or an HTML page if there is an index file in the current directory.
|
||||
|
||||
<aside class="complete">Static file server</aside>
|
||||
|
||||
## Adding functionality
|
||||
|
||||
Let's do something interesting with our file server: serve a templated page. Create a new file and paste this into it:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Caddy tutorial</title>
|
||||
</head>
|
||||
<body>
|
||||
Page loaded at: {{`{{`}}now | date "Mon Jan 2 15:04:05 MST 2006"{{`}}`}}
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
Save this as `caddy.html` in the current directory and load it in your browser: [https://localhost/caddy.html](https://localhost/caddy.html)
|
||||
|
||||
The output is:
|
||||
|
||||
```
|
||||
Page loaded at: {{`{{`}}now | date "Mon Jan 2 15:04:05 MST 2006"{{`}}`}}
|
||||
```
|
||||
|
||||
Wait a minute. We should see today's date. Why didn't it work? It's because the server hasn't yet been configured to evaluate templates! Easy to fix, just add a line to the Caddyfile so it looks like this:
|
||||
|
||||
```caddy
|
||||
localhost
|
||||
|
||||
templates
|
||||
file_server browse
|
||||
```
|
||||
|
||||
Save that, then reload the browser tab. You should see:
|
||||
|
||||
```
|
||||
Page loaded at: {{now | date "Mon Jan 2 15:04:05 MST 2006"}}
|
||||
```
|
||||
|
||||
With Caddy's [templates module](/docs/modules/http.handlers.templates), you can do a lot of useful things with static files, such as including other HTML files, making sub-requests, setting response headers, working with data structures, and more!
|
||||
|
||||
<aside class="complete">Templates</aside>
|
||||
|
||||
It's good practice to compress responses with a quick and modern compression algorithm. Let's enable Gzip and Zstandard support using the [`encode`](/docs/caddyfile/directives/encode) directive:
|
||||
|
||||
```caddy
|
||||
localhost
|
||||
|
||||
encode zstd gzip
|
||||
templates
|
||||
file_server browse
|
||||
```
|
||||
|
||||
<aside class="tip">
|
||||
Browsers don't support Zstandard encodings yet. Hopefully soon!
|
||||
</aside>
|
||||
|
||||
|
||||
<aside class="complete">Compression</aside>
|
||||
|
||||
That's the basic process for getting a semi-advanced, production-ready site up and running!
|
||||
|
||||
When you're ready to turn on [automatic HTTPS](/docs/automatic-https), just replace your site's address (`localhost` in our tutorial) with your domain name. See our [HTTPS quick-start guide](/docs/quick-starts/https) for more information.
|
||||
|
||||
## Multiple sites
|
||||
|
||||
With our current Caddyfile, we can only have the one site definition! Only the first line can be the address(es) of the site, and then all the rest of the file has to be directives for that site.
|
||||
|
||||
But it is easy to make it so we can add more sites!
|
||||
|
||||
Our Caddyfile so far:
|
||||
|
||||
```caddy
|
||||
localhost
|
||||
|
||||
encode zstd gzip
|
||||
templates
|
||||
file_server browse
|
||||
```
|
||||
|
||||
is equivalent to this one:
|
||||
|
||||
```caddy
|
||||
localhost {
|
||||
encode zstd gzip
|
||||
templates
|
||||
file_server browse
|
||||
}
|
||||
```
|
||||
|
||||
except the second one allows us to add more sites.
|
||||
|
||||
By wrapping our site block in curly braces `{ }` we are able to define multiple, different sites in the same Caddyfile.
|
||||
|
||||
For example:
|
||||
|
||||
```caddy
|
||||
:8080 {
|
||||
respond "I am 8080"
|
||||
}
|
||||
|
||||
:8081 {
|
||||
respond "I am 8081"
|
||||
}
|
||||
```
|
||||
|
||||
When wrapping site blocks in curly braces, only [addresses](/docs/caddyfile/concepts#addresses) appear outside the curly braces and only [directives](/docs/caddyfile/directives) appear inside them.
|
||||
|
||||
For multiple sites which share the same configuration, you can add more addresses, for example:
|
||||
|
||||
```caddy
|
||||
:8080, :8081 {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
You can then define as many different sites as you want, as long as each address is unique.
|
||||
|
||||
<aside class="complete">Multiple sites</aside>
|
||||
|
||||
|
||||
## Matchers
|
||||
|
||||
We may want to apply some directives only to certain requests. For example, let's suppose we want to have both a file server and a reverse proxy, but we obviously can't do both on every request! Either the file server will write a static file, or the reverse proxy will proxy the request to a backend.
|
||||
|
||||
This config will not work like we want:
|
||||
|
||||
```caddy
|
||||
localhost
|
||||
|
||||
file_server
|
||||
reverse_proxy 127.0.0.1:9005
|
||||
```
|
||||
|
||||
In practice, we may want to use the reverse proxy only for API requests, i.e. requests with a base path of `/api/`. This is easy to do by adding a [matcher token](/docs/caddyfile/matchers#syntax):
|
||||
|
||||
```caddy
|
||||
localhost
|
||||
|
||||
file_server
|
||||
reverse_proxy /api/* 127.0.0.1:9005
|
||||
```
|
||||
|
||||
There; now the reverse proxy will be prioritized for all requests starting with `/api/`.
|
||||
|
||||
The `/api/*` token we just added is called a **matcher token**. You can tell it's a matcher token because it starts with a forward slash `/` and it appears right after the directive (but you can always look it up in the [directive's docs](/docs/caddyfile/directives) to be sure).
|
||||
|
||||
Matchers are really powerful. You can name matchers and use them like `@name` to match on more than just the request path! Take a moment to [learn more about matchers](/docs/caddyfile/matchers) before continuing!
|
||||
|
||||
<aside class="complete">Matchers</aside>
|
||||
|
||||
## Environment variables
|
||||
|
||||
The Caddyfile adapter allows substituting [environment variables](/docs/caddyfile/concepts#environment-variables) before the Caddyfile is parsed.
|
||||
|
||||
First, set an environment variable (in the same shell that runs Caddy):
|
||||
|
||||
<pre><code class="cmd bash">export SITE_ADDRESS=localhost:9055</code></pre>
|
||||
|
||||
Then you can use it like this in the Caddyfile:
|
||||
|
||||
```caddy
|
||||
{$SITE_ADDRESS}
|
||||
|
||||
file_server
|
||||
```
|
||||
|
||||
Before the Caddyfile is parsed, it will be expanded to:
|
||||
|
||||
```caddy
|
||||
localhost:9055
|
||||
|
||||
file_server
|
||||
```
|
||||
|
||||
You can use environment variables anywhere in the Caddyfile, for any number of tokens.
|
||||
|
||||
<aside class="complete">Environment variables</aside>
|
||||
|
||||
|
||||
## Comments
|
||||
|
||||
One last thing that you will find most helpful: if you want to remark or note anything in your Caddyfile, you can use comments, starting with `#`:
|
||||
|
||||
```caddy
|
||||
# this starts a comment
|
||||
```
|
||||
|
||||
<aside class="complete">Comments</aside>
|
||||
|
||||
## Further reading
|
||||
|
||||
- [Common patterns](/docs/caddyfile/patterns)
|
||||
- [Caddyfile concepts](/docs/caddyfile/concepts)
|
||||
- [Directives](/docs/caddyfile/directives)
|
44
src/docs/markdown/caddyfile.md
Normal file
44
src/docs/markdown/caddyfile.md
Normal file
|
@ -0,0 +1,44 @@
|
|||
---
|
||||
title: The Caddyfile
|
||||
---
|
||||
|
||||
# The Caddyfile
|
||||
|
||||
The **Caddyfile** is a convenient Caddy configuration format for humans. It is most people's favorite way to use Caddy because it is easy to write, easy to understand, and expressive enough for most use cases.
|
||||
|
||||
It looks like this:
|
||||
|
||||
```caddy
|
||||
example.com
|
||||
|
||||
root * /var/www/wordpress
|
||||
php_fastcgi unix//run/php/php-version-fpm.sock
|
||||
file_server
|
||||
```
|
||||
|
||||
(That's a real, production-ready Caddyfile that serves WordPress with fully-managed HTTPS.)
|
||||
|
||||
The basic idea is that you first type the address of your site, then the features or functionality you need your site to have. [View more common patterns.](/docs/caddyfile/patterns)
|
||||
|
||||
## Menu
|
||||
|
||||
- #### [Quick start guide](/docs/quick-starts/caddyfile)
|
||||
A good place to begin getting familiar with the Caddyfile.
|
||||
- #### [Full Caddyfile tutorial](/docs/caddyfile-tutorial)
|
||||
Learn to do a variety of common things with the Caddyfile.
|
||||
- #### [Caddyfile concepts](/docs/caddyfile/concepts)
|
||||
Required reading! Structure, site addresses, matchers, placeholders, and more.
|
||||
- #### [Directives](/docs/caddyfile/directives)
|
||||
Keywords at the beginning of lines that enable features for your sites.
|
||||
- #### [Request matchers](/docs/caddyfile/matchers)
|
||||
Filter requests by using matchers with your directives.
|
||||
- #### [Global options](/docs/caddyfile/options)
|
||||
Settings that apply to the whole server rather than individual sites.
|
||||
- #### [Common patterns](/docs/caddyfile/patterns)
|
||||
Simple ways to do common things.
|
||||
<!-- - #### [Caddyfile specification](/docs/caddyfile/spec) TODO: Finish this -->
|
||||
|
||||
|
||||
## Note
|
||||
|
||||
The Caddyfile is just a [config adapter](/docs/config-adapters) for Caddy. It is usually preferred when manually crafting configurations by hand, but is not as expressive, flexible, or programmable as Caddy's [native JSON structure](/docs/json/). If you are automating your Caddy configurations/deployments, you may wish to use JSON with [Caddy's API](/docs/api). (You can actually use the Caddyfile with the API too, just to a limited extent.)
|
358
src/docs/markdown/caddyfile/concepts.md
Normal file
358
src/docs/markdown/caddyfile/concepts.md
Normal file
|
@ -0,0 +1,358 @@
|
|||
---
|
||||
title: Caddyfile Concepts
|
||||
---
|
||||
|
||||
# Caddyfile Concepts
|
||||
|
||||
This document will help you learn about the HTTP Caddyfile in detail.
|
||||
|
||||
1. [Structure](#structure)
|
||||
2. [Addresses](#addresses)
|
||||
3. [Matchers](#matchers)
|
||||
4. [Placeholders](#placeholders)
|
||||
5. [Snippets](#snippets)
|
||||
6. [Comments](#comments)
|
||||
7. [Environment variables](#environment-variables)
|
||||
8. [Global options](#global-options)
|
||||
|
||||
|
||||
## Structure
|
||||
|
||||
The Caddyfile's structure can be described visually:
|
||||
|
||||

|
||||
|
||||
Key points:
|
||||
|
||||
- An optional [**global options block**](#global-options) can be the very first thing in the file.
|
||||
- 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 inheritence across site blocks.
|
||||
- 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.
|
||||
|
||||
### Blocks
|
||||
|
||||
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 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:
|
||||
|
||||
```caddy
|
||||
localhost
|
||||
|
||||
reverse_proxy /api/* localhost:9001
|
||||
file_server
|
||||
```
|
||||
|
||||
is equivalent to:
|
||||
|
||||
```caddy
|
||||
localhost {
|
||||
reverse_proxy /api/* localhost:9001
|
||||
file_server
|
||||
}
|
||||
```
|
||||
|
||||
when you have only a single site block; it's a matter of preference.
|
||||
|
||||
To configure multiple sites with the same Caddyfile, you **must** use curly braces around each one to separate their configurations:
|
||||
|
||||
```caddy
|
||||
example1.com {
|
||||
root * /www/example.com
|
||||
file_server
|
||||
}
|
||||
|
||||
example2.com {
|
||||
reverse_proxy localhost:9000
|
||||
}
|
||||
```
|
||||
|
||||
If a request matches multiple site blocks, the site block with the most specific matching address is chosen. Requests don't cascade into to other site blocks.
|
||||
|
||||
|
||||
### Directives
|
||||
|
||||
[**Directives**](/docs/caddyfile/directives) are functional keywords which customize how the site is served. They **must** appear within site blocks. For example, a complete file server config might look like this:
|
||||
|
||||
```caddy
|
||||
localhost
|
||||
|
||||
file_server
|
||||
```
|
||||
|
||||
Or a reverse proxy:
|
||||
|
||||
```caddy
|
||||
localhost
|
||||
|
||||
reverse_proxy localhost:9000
|
||||
```
|
||||
|
||||
In these examples, [`file_server`](/docs/caddyfile/directives/file_server) and [`reverse_proxy`](/docs/caddyfile/directives/reverse_proxy) are directives. Directives are the first word on a line in a site block.
|
||||
|
||||
In the second example, `localhost:9000` is an **argument** because it appears on the same line after the directive.
|
||||
|
||||
Sometimes directives can open their own blocks. **Subdirectives** appear on the beginning of each line within directive blocks:
|
||||
|
||||
```caddy
|
||||
localhost
|
||||
|
||||
reverse_proxy localhost:9000 localhost:9001 {
|
||||
lb_policy first
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
### Tokens and quotes
|
||||
|
||||
The Caddyfile is lexed into tokens before being parsed. Whitespace is significant in the Caddyfile, because tokens are separated by whitespace.
|
||||
|
||||
Often, directives expect a certain number of arguments; if a single argument has a value with whitespace, it would be lexed as two separate tokens:
|
||||
|
||||
```caddy-d
|
||||
directive abc def
|
||||
```
|
||||
|
||||
This could be problematic and return errors or unexpected behavior.
|
||||
|
||||
If `abc def` is supposed to be the value of a single argument, it needs to be quoted:
|
||||
|
||||
```caddy-d
|
||||
directive "abc def"
|
||||
```
|
||||
|
||||
Quotes can be escaped if you need to use quotes in quoted tokens, too:
|
||||
|
||||
```caddy-d
|
||||
directive "\"abc def\""
|
||||
```
|
||||
|
||||
To avoid escaping quotes, you can instead use backticks <code>\` \`</code> to enclose tokens; for example:
|
||||
|
||||
```caddy-d
|
||||
directive `{"foo": "bar"}`
|
||||
```
|
||||
|
||||
Inside quoted tokens, all other characters are treated literally, including spaces, tabs, and newlines. Multi-line tokens are thus possible:
|
||||
|
||||
```caddy-d
|
||||
directive "first line
|
||||
second line"
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Addresses
|
||||
|
||||
An address always appears at the top of the site block, and is usually the first thing in the Caddyfile.
|
||||
|
||||
These are examples of valid addresses:
|
||||
|
||||
- `localhost`
|
||||
- `example.com`
|
||||
- `:443`
|
||||
- `http://example.com`
|
||||
- `localhost:8080`
|
||||
- `127.0.0.1`
|
||||
- `[::1]:2015`
|
||||
- `*.example.com`
|
||||
- `http://`
|
||||
|
||||
|
||||
<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://`.
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
From the address, Caddy can potentially infer the scheme, host and port of your site. If the address is without a port, the Caddyfile will choose the port matching the scheme if specified, or the default port of 443 will be assumed.
|
||||
|
||||
If you specify a hostname, only requests with a matching `Host` header will be honored. In other words, if the site address is `localhost`, then Caddy will not match requests to `127.0.0.1`.
|
||||
|
||||
Wildcards (`*`) may be used, but only to represent precisely one label of the hostname. For example, `*.example.com` matches `foo.example.com` but not `foo.bar.example.com`, and `*` matches `localhost` but not `example.com`. To catch all hosts, omit the host portion of the address.
|
||||
|
||||
If multiple sites share the same definition, you can list all of them together; notice how the commas indicate the continuation of addresses:
|
||||
|
||||
```caddy
|
||||
localhost:8080, example.com, www.example.com
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```caddy
|
||||
localhost:8080,
|
||||
example.com,
|
||||
www.example.com
|
||||
```
|
||||
|
||||
An address must be unique; you cannot specify the same address more than once.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
## Matchers
|
||||
|
||||
HTTP handler 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. This concept originates in the [underlying JSON](/docs/json/apps/http/servers/routes/match/) structure, and it's important to know how to use them in the Caddyfile. With matchers, you can specify exactly which requests a certain directive applies to.
|
||||
|
||||
For directives that support matchers, the first argument after the directive is the **matcher token**. Here are some examples:
|
||||
|
||||
```caddy-d
|
||||
root * /var/www # matcher token: *
|
||||
root /index.html /var/www # matcher token: /index.html
|
||||
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.
|
||||
|
||||
**[Read the page about request matchers](/docs/caddyfile/matchers) to learn more.**
|
||||
|
||||
|
||||
|
||||
|
||||
## Placeholders
|
||||
|
||||
You can use any [Caddy placeholders](/docs/conventions#placeholders) in the Caddyfile, but for convenience you can also use some equivalent shorthand ones:
|
||||
|
||||
| Shorthand | Replaces |
|
||||
|-----------------|-----------------------------------|
|
||||
| `{cookie.*}` | `{http.request.cookie.*}` |
|
||||
| `{dir}` | `{http.request.uri.path.dir}` |
|
||||
| `{err.*}` | `{http.error.*}` |
|
||||
| `{file}` | `{http.request.uri.path.file}` |
|
||||
| `{file.*}` | `{http.request.uri.path.file.*}` |
|
||||
| `{header.*}` | `{http.request.header.*}` |
|
||||
| `{host}` | `{http.request.host}` |
|
||||
| `{labels.*}` | `{http.request.host.labels.*}` |
|
||||
| `{hostport}` | `{http.request.hostport}` |
|
||||
| `{port}` | `{http.request.port}` |
|
||||
| `{method}` | `{http.request.method}` |
|
||||
| `{path}` | `{http.request.uri.path}` |
|
||||
| `{path.*}` | `{http.request.uri.path.*}` |
|
||||
| `{query}` | `{http.request.uri.query}` |
|
||||
| `{query.*}` | `{http.request.uri.query.*}` |
|
||||
| `{re.*.*}` | `{http.regexp.*.*}` |
|
||||
| `{remote}` | `{http.request.remote}` |
|
||||
| `{remote_host}` | `{http.request.remote.host}` |
|
||||
| `{remote_port}` | `{http.request.remote.port}` |
|
||||
| `{rp.*}` | `{http.reverse_proxy.*}` |
|
||||
| `{scheme}` | `{http.request.scheme}` |
|
||||
| `{tls_cipher}` | `{http.request.tls.cipher_suite}` |
|
||||
| `{tls_version}` | `{http.request.tls.version}` |
|
||||
| `{tls_client_fingerprint}` | `{http.request.tls.client.fingerprint}` |
|
||||
| `{tls_client_issuer}` | `{http.request.tls.client.issuer}` |
|
||||
| `{tls_client_serial}` | `{http.request.tls.client.serial}` |
|
||||
| `{tls_client_subject}` | `{http.request.tls.client.subject}` |
|
||||
| `{tls_client_certificate_pem}` | `{http.request.tls.client.certificate_pem}` |
|
||||
| `{tls_client_certificate_der_base64}` | `{http.request.tls.client.certificate_der_base64}` |
|
||||
| `{uri}` | `{http.request.uri}` |
|
||||
| `{upstream_hostport}` | `{http.reverse_proxy.upstream.hostport}` |
|
||||
| `{vars.*}` | `{http.vars.*}` |
|
||||
|
||||
|
||||
|
||||
## Snippets
|
||||
|
||||
You can define special blocks called snippets by giving them a name surrounded in parentheses:
|
||||
|
||||
```caddy
|
||||
(redirect) {
|
||||
@http {
|
||||
protocol http
|
||||
}
|
||||
redir @http https://{host}{uri}
|
||||
}
|
||||
```
|
||||
|
||||
And then you can reuse this anywhere you need:
|
||||
|
||||
```caddy-d
|
||||
import redirect
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
You can pass arguments to imported configuration and use them like so:
|
||||
|
||||
```caddy
|
||||
(snippet) {
|
||||
respond "Yahaha! You found {args.0}!"
|
||||
}
|
||||
|
||||
a.example.com {
|
||||
import snippet "Example A"
|
||||
}
|
||||
|
||||
b.example.com {
|
||||
import snippet "Example B"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Comments
|
||||
|
||||
Comments start with `#` and proceed until the end of the line:
|
||||
|
||||
```caddy-d
|
||||
# Comments can start a line
|
||||
directive # or go at the end
|
||||
```
|
||||
|
||||
The hash character `#` for a comment cannot appear in the middle of a token (i.e. it must be preceded by a space or appear at the beginning of a line). This allows the use of hashes within URIs or other values without requiring quoting.
|
||||
|
||||
|
||||
|
||||
## Environment variables
|
||||
|
||||
If your configuration relies on environment variables, you can use them in the Caddyfile:
|
||||
|
||||
```caddy
|
||||
{$SITE_ADDRESS}
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
{$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.
|
||||
|
||||
|
||||
|
||||
## Global options
|
||||
|
||||
A Caddyfile may optionally start with a special block that has no keys, called a [global options block](/docs/caddyfile/options):
|
||||
|
||||
```caddy
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
[Learn more](/docs/caddyfile/options) about the global options block.
|
156
src/docs/markdown/caddyfile/directives.md
Normal file
156
src/docs/markdown/caddyfile/directives.md
Normal file
|
@ -0,0 +1,156 @@
|
|||
---
|
||||
title: Caddyfile Directives
|
||||
---
|
||||
|
||||
<style>
|
||||
#directive-table table {
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#directive-table tr:hover {
|
||||
background: rgba(109, 226, 255, 0.11);
|
||||
}
|
||||
|
||||
#directive-table tr td:first-child {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#directive-table a:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
display: block;
|
||||
width: 100vw;
|
||||
}
|
||||
</style>
|
||||
|
||||
# Caddyfile Directives
|
||||
|
||||
Directives are functional keywords that appear within site [blocks](/docs/caddyfile/concepts#blocks). Sometimes, they may open blocks of their own which can contain _subdirectives_, but directives **cannot** be used within other directives unless noted. For example, you can't use `basicauth` inside a `file_server` block, because `file_server` does not know how to do authentication. However, you _may_ use some directives within special directive blocks like `handle` and `route` because they are specifically designed to group HTTP handler directives.
|
||||
|
||||
The following directives come standard with Caddy, and can be used in the HTTP Caddyfile:
|
||||
|
||||
<div id="directive-table">
|
||||
|
||||
Directive | Description
|
||||
----------|------------
|
||||
**[abort](/docs/caddyfile/directives/abort)** | Aborts the HTTP request
|
||||
**[acme_server](/docs/caddyfile/directives/acme_server)** | An embedded ACME server
|
||||
**[basicauth](/docs/caddyfile/directives/basicauth)** | Enforces HTTP Basic Authentication
|
||||
**[bind](/docs/caddyfile/directives/bind)** | Customize the server's socket address
|
||||
**[encode](/docs/caddyfile/directives/encode)** | Encodes (usually compresses) responses
|
||||
**[error](/docs/caddyfile/directives/error)** | Trigger an error
|
||||
**[file_server](/docs/caddyfile/directives/file_server)** | Serve files from disk
|
||||
**[forward_auth](/docs/caddyfile/directives/forward_auth)** | Delegate authentication to an external service
|
||||
**[handle](/docs/caddyfile/directives/handle)** | A mutually-exclusive group of directives
|
||||
**[handle_errors](/docs/caddyfile/directives/handle_errors)** | Defines routes for handling errors
|
||||
**[handle_path](/docs/caddyfile/directives/handle_path)** | Like handle, but strips path prefix
|
||||
**[header](/docs/caddyfile/directives/header)** | Sets or removes response headers
|
||||
**[import](/docs/caddyfile/directives/import)** | Include snippets or files
|
||||
**[log](/docs/caddyfile/directives/log)** | Enables access/request logging
|
||||
**[map](/docs/caddyfile/directives/map)** | Maps an input value to one or more outputs
|
||||
**[method](/docs/caddyfile/directives/method)** | Change the HTTP method internally
|
||||
**[metrics](/docs/caddyfile/directives/metrics)** | Configures the Prometheus metrics exposition endpoint
|
||||
**[php_fastcgi](/docs/caddyfile/directives/php_fastcgi)** | Serve PHP sites over FastCGI
|
||||
**[push](/docs/caddyfile/directives/push)** | Push content to the client using HTTP/2 server push
|
||||
**[redir](/docs/caddyfile/directives/redir)** | Issues an HTTP redirect to the client
|
||||
**[request_body](/docs/caddyfile/directives/request_body)** | Manipulates request body
|
||||
**[request_header](/docs/caddyfile/directives/request_header)** | Manipulates request headers
|
||||
**[respond](/docs/caddyfile/directives/respond)** | Writes a hard-coded response to the client
|
||||
**[reverse_proxy](/docs/caddyfile/directives/reverse_proxy)** | A powerful and extensible reverse proxy
|
||||
**[rewrite](/docs/caddyfile/directives/rewrite)** | Rewrites the request internally
|
||||
**[root](/docs/caddyfile/directives/root)** | Set the path to the site root
|
||||
**[route](/docs/caddyfile/directives/route)** | A group of directives treated literally as single unit
|
||||
**[templates](/docs/caddyfile/directives/templates)** | Execute templates on the response
|
||||
**[tls](/docs/caddyfile/directives/tls)** | Customize TLS settings
|
||||
**[tracing](/docs/caddyfile/directives/tracing)** | Integration with OpenTelemetry tracing
|
||||
**[try_files](/docs/caddyfile/directives/try_files)** | Rewrite that depends on file existence
|
||||
**[uri](/docs/caddyfile/directives/uri)** | Manipulate the URI
|
||||
**[vars](/docs/caddyfile/directives/vars)** | Set arbitrary variables
|
||||
|
||||
</div>
|
||||
|
||||
## Syntax
|
||||
|
||||
The syntax of each directive will look something like this:
|
||||
|
||||
```caddy-d
|
||||
directive [<matcher>] <args...> {
|
||||
subdirective [<args...>]
|
||||
}
|
||||
```
|
||||
|
||||
The `<carets>` indicate tokens to be substituted by actual values.
|
||||
|
||||
The`[brackets]` indicate optional parameters.
|
||||
|
||||
The ellipses `...` indicates a continuation, i.e. one or more parameters or lines.
|
||||
|
||||
Subdirectives are always optional unless documented otherwise, even though they don't appear in `[brackets]`.
|
||||
|
||||
|
||||
### Matchers
|
||||
|
||||
Most---but not all---directives accept [matcher tokens](/docs/caddyfile/matchers#syntax), which let you filter requests. Matcher tokens are usually optional. If you see this in a directive's syntax:
|
||||
|
||||
```caddy-d
|
||||
[<matcher>]
|
||||
```
|
||||
|
||||
then the directive accepts a matcher token, letting you filter which requests the directive applies to.
|
||||
|
||||
Because matcher tokens all work the same, the various possibilities for the matcher token will not be described on every page, to reduce duplication. Instead, refer to the centralized [matcher documentation](/docs/caddyfile/matchers).
|
||||
|
||||
|
||||
## Directive order
|
||||
|
||||
Many directives manipulate the HTTP handler chain. The order in which those directives are evaluated matters, so a default ordering is hard-coded into Caddy:
|
||||
|
||||
```caddy-d
|
||||
tracing
|
||||
|
||||
map
|
||||
vars
|
||||
root
|
||||
|
||||
header
|
||||
copy_response_headers # only in reverse_proxy's handle_response block
|
||||
request_body
|
||||
|
||||
redir
|
||||
|
||||
# incoming request manipulation
|
||||
method
|
||||
rewrite
|
||||
uri
|
||||
try_files
|
||||
|
||||
# middleware handlers; some wrap responses
|
||||
basicauth
|
||||
forward_auth
|
||||
request_header
|
||||
encode
|
||||
push
|
||||
templates
|
||||
|
||||
# special routing & dispatching directives
|
||||
handle
|
||||
handle_path
|
||||
route
|
||||
|
||||
# handlers that typically respond to requests
|
||||
abort
|
||||
error
|
||||
copy_response # only in reverse_proxy's handle_response block
|
||||
respond
|
||||
metrics
|
||||
reverse_proxy
|
||||
php_fastcgi
|
||||
file_server
|
||||
acme_server
|
||||
```
|
||||
|
||||
You can override/customize this ordering by using the [`order` global option](/docs/caddyfile/options) or the [`route` directive](/docs/caddyfile/directives/route).
|
32
src/docs/markdown/caddyfile/directives/abort.md
Normal file
32
src/docs/markdown/caddyfile/directives/abort.md
Normal file
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
title: abort (Caddyfile directive)
|
||||
---
|
||||
|
||||
# abort
|
||||
|
||||
Prevents any response to the client by immediately aborting the HTTP handler chain and closing the connection. Any concurrent, active HTTP streams on the same connection are interrupted.
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
abort [<matcher>]
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Forcefully close a connection received for unknown domains when using a wildcard certificate:
|
||||
|
||||
```caddy
|
||||
*.example.com {
|
||||
@foo host foo.example.com
|
||||
handle @foo {
|
||||
respond "This is foo!" 200
|
||||
}
|
||||
|
||||
# Unhandled domains fall through to here, but we don't want to accept their requests
|
||||
handle {
|
||||
abort
|
||||
}
|
||||
}
|
||||
```
|
26
src/docs/markdown/caddyfile/directives/acme_server.md
Normal file
26
src/docs/markdown/caddyfile/directives/acme_server.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
title: acme_server (Caddyfile directive)
|
||||
---
|
||||
|
||||
# acme_server
|
||||
|
||||
An embedded [ACME protocol](https://tools.ietf.org/html/rfc8555) server handler. This allows a Caddy instance to issue certificates for any other ACME-compatible software (including other Caddy instances).
|
||||
|
||||
When enabled, requests matching the path `/acme/*` will be handled by the ACME server.
|
||||
|
||||
|
||||
## Client configuration
|
||||
|
||||
Using ACME server defaults, ACME clients should simply be configured to use `https://localhost/acme/local/directory` as their ACME endpoint. (`local` is the ID of Caddy's default CA.)
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
acme_server [<matcher>] {
|
||||
ca <id>
|
||||
}
|
||||
```
|
||||
|
||||
- **ca** specifies the ID of the certificate authority with which to sign certificates. The default is `local`, which is Caddy's default CA, intended for locally-used, self-signed certificates, which is most common in dev environments. For broader use, it is recommended to specify a different CA to avoid confusion. If the CA with the given ID does not already exist, it will be created. See the [PKI app global options](/docs/caddyfile/options#pki-options) to configure alternate CAs.
|
||||
|
43
src/docs/markdown/caddyfile/directives/basicauth.md
Normal file
43
src/docs/markdown/caddyfile/directives/basicauth.md
Normal file
|
@ -0,0 +1,43 @@
|
|||
---
|
||||
title: basicauth (Caddyfile directive)
|
||||
---
|
||||
|
||||
# basicauth
|
||||
|
||||
Enables HTTP Basic Authentication, which can be used to protect directories and files with a username and hashed password.
|
||||
|
||||
**Note that basic auth is not secure over plain HTTP.** Use discretion when deciding what to protect with HTTP Basic Authentication.
|
||||
|
||||
When a user requests a resource that is protected, the browser will prompt the user for a username and password if they have not already supplied one. If the proper credentials are present in the Authorization header, the server will grant access to the resource. If the header is missing or the credentials are incorrect, the server will respond with HTTP 401 Unauthorized.
|
||||
|
||||
Caddy configuration does not accept plaintext passwords; you MUST hash them before putting them into the configuration. The [`caddy hash-password`](/docs/command-line#caddy-hash-password) command can help with this.
|
||||
|
||||
After a successful authentication, the `{http.auth.user.id}` placeholder will be available, which contains the authenticated username.
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
basicauth [<matcher>] [<hash_algorithm> [<realm>]] {
|
||||
<username> <hashed_password> [<salt_base64>]
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
- **<hash_algorithm>** is the name of the password hashing algorithm (or KDF) used for the hashes in this configuration. Default: `bcrypt`
|
||||
- **<realm>** is a custom realm name.
|
||||
- **<username>** is a username or user ID.
|
||||
- **<hashed_password>** is the password hash.
|
||||
- **<salt_base64>** is the base-64 encoding of the password salt, if an external salt is required.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Protect all resources in /secret so only Bob can access them with the password "hiccup":
|
||||
|
||||
```caddy-d
|
||||
basicauth /secret/* {
|
||||
Bob $2a$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNmpkT/5qqR7hx4IjWJPDhjvG
|
||||
}
|
||||
```
|
||||
|
41
src/docs/markdown/caddyfile/directives/bind.md
Normal file
41
src/docs/markdown/caddyfile/directives/bind.md
Normal file
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
title: bind (Caddyfile directive)
|
||||
---
|
||||
|
||||
# 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.)
|
||||
|
||||
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.)
|
||||
|
||||
`bind` accepts [network addresses](/docs/conventions#network-addresses), but may not include a port.
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
bind <hosts...>
|
||||
```
|
||||
|
||||
- **<hosts...>** is the list of host interfaces to bind which to bind the listener.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
To make a socket accessible only on the current machine, bind to the loopback interface (localhost):
|
||||
|
||||
```caddy-d
|
||||
bind 127.0.0.1
|
||||
```
|
||||
|
||||
To include IPv6:
|
||||
|
||||
```caddy-d
|
||||
bind 127.0.0.1 [::1]
|
||||
```
|
||||
|
||||
To bind to a Unix domain socket at `/run/caddy`:
|
||||
|
||||
```caddy-d
|
||||
bind unix//run/caddy
|
||||
```
|
84
src/docs/markdown/caddyfile/directives/encode.md
Normal file
84
src/docs/markdown/caddyfile/directives/encode.md
Normal file
|
@ -0,0 +1,84 @@
|
|||
---
|
||||
title: encode (Caddyfile directive)
|
||||
---
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
// We'll add links to all the subdirectives if a matching anchor tag is found on the page.
|
||||
addLinksToSubdirectives();
|
||||
});
|
||||
</script>
|
||||
|
||||
# encode
|
||||
|
||||
Encodes responses using the configured encoding(s). A typical use for encoding is compression.
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
encode [<matcher>] <formats...> {
|
||||
# encoding formats
|
||||
gzip [<level>]
|
||||
zstd
|
||||
|
||||
minimum_length <length>
|
||||
|
||||
# response matcher single line syntax
|
||||
match [header <field> [<value>]] | [status <code...>]
|
||||
# or response matcher block for multiple conditions
|
||||
match {
|
||||
status <code...>
|
||||
header <field> [<value>]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **<formats...>** is the list of encoding formats to enable. If multiple encodings are enabled, the encoding is chosen based the request's Accept-Encoding header; if the client has no strong preference (q-factor), then the first supported encoding is used.
|
||||
- **gzip** <span id="gzip"/> enables Gzip compression, optionally at the specified level.
|
||||
- **zstd** <span id="zstd"/> enables Zstandard compression.
|
||||
- **minimum_length** <span id="minimum_length"/> the minimum number of bytes a response should have to be encoded (default: 512).
|
||||
- **match** <span id="match"/> is a [response matcher](#response-matcher). Only matching responses are encoded. The default looks like this:
|
||||
|
||||
```caddy-d
|
||||
match {
|
||||
header Content-Type text/*
|
||||
header Content-Type application/json*
|
||||
header Content-Type application/javascript*
|
||||
header Content-Type application/xhtml+xml*
|
||||
header Content-Type application/atom+xml*
|
||||
header Content-Type application/rss+xml*
|
||||
header Content-Type image/svg+xml*
|
||||
}
|
||||
```
|
||||
|
||||
## Response matcher
|
||||
|
||||
**Response matchers** can be used to filter (or classify) responses by specific criteria.
|
||||
|
||||
### status
|
||||
|
||||
```caddy-d
|
||||
status <code...>
|
||||
```
|
||||
|
||||
By HTTP status code.
|
||||
|
||||
- **<code...>** 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
|
||||
|
||||
See the [header](/docs/caddyfile/matchers#header) request matcher for the supported syntax.
|
||||
|
||||
## Examples
|
||||
|
||||
Enable Gzip compression:
|
||||
|
||||
```caddy-d
|
||||
encode gzip
|
||||
```
|
||||
|
||||
Enable Zstandard and Gzip compression (with Zstandard implicitly preferred, since it is first):
|
||||
|
||||
```caddy-d
|
||||
encode zstd gzip
|
||||
```
|
46
src/docs/markdown/caddyfile/directives/error.md
Normal file
46
src/docs/markdown/caddyfile/directives/error.md
Normal file
|
@ -0,0 +1,46 @@
|
|||
---
|
||||
title: error (Caddyfile directive)
|
||||
---
|
||||
|
||||
# error
|
||||
|
||||
Triggers an error in the HTTP handler chain, with an optional message and recommended HTTP status code.
|
||||
|
||||
This handler does not write a response. Instead, it's meant to be paired with the [`handle_errors`](handle_errors) directive to invoke your custom error handling logic.
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
error [<matcher>] <status>|<message> [<status>] {
|
||||
message <text>
|
||||
}
|
||||
```
|
||||
|
||||
- **<status>** is the HTTP status code to write. Default is `500`.
|
||||
- **<message>** is the error message. Default is no error message.
|
||||
- **message** is an alternate way to provide an error message; convenient if it is multiple lines.
|
||||
|
||||
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
|
||||
|
||||
Trigger an error on certain request paths, and use [`handle_errors`](handle_errors) to write a response:
|
||||
|
||||
```caddy
|
||||
example.com {
|
||||
root * /srv
|
||||
|
||||
# Trigger errors for certain paths
|
||||
error /private* "Unauthorized" 403
|
||||
error /hidden* "Not found" 404
|
||||
|
||||
# Handle the error by serving an HTML page
|
||||
handle_errors {
|
||||
rewrite * /{err.status_code}.html
|
||||
file_server
|
||||
}
|
||||
|
||||
file_server
|
||||
}
|
||||
```
|
83
src/docs/markdown/caddyfile/directives/file_server.md
Normal file
83
src/docs/markdown/caddyfile/directives/file_server.md
Normal file
|
@ -0,0 +1,83 @@
|
|||
---
|
||||
title: file_server (Caddyfile directive)
|
||||
---
|
||||
|
||||
# file_server
|
||||
|
||||
A static file server that supports real and virtual file systems. It forms file paths by appending the request's URI path to the [site's root path](/docs/caddyfile/directives/root).
|
||||
|
||||
By default, it enforces canonical URIs; meaning HTTP redirects will be issued for requests to directories that do not end with a trailing slash (to add it) or requests to files that have a trailing slash (to remove it). Redirects are not issued, however, if an internal rewrite modifies the last element of the path (the filename).
|
||||
|
||||
Most often, the `file_server` directive is paired with the [`root`](/docs/caddyfile/directives/root) directive to set the file root for the whole site, but this directive also has a `root` subdirective (below) to set the root only for this handler if preferred. Note that a site root does not carry sandbox guarantees: the file server does prevent directory traversal from path components, but symbolic links within the root can still allow accesses outside of the root.
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
file_server [<matcher>] [browse] {
|
||||
fs <backend...>
|
||||
root <path>
|
||||
hide <files...>
|
||||
index <filenames...>
|
||||
browse [<template_file>]
|
||||
precompressed <formats...>
|
||||
status <status>
|
||||
disable_canonical_uris
|
||||
pass_thru
|
||||
}
|
||||
```
|
||||
|
||||
- **browse** enables file listings for requests to directories that do not have an index file.
|
||||
- **fs** specifies an alternate (perhaps virtual) file system to use. Any Caddy module in the `caddy.fs` namespace can be used here. Any root path/prefix will still apply to alternate file system modules. By default, the local disk is used.
|
||||
- **root** sets the path to the site root. It's similar to the [`root`](/docs/caddyfile/directives/root) directive except it applies to this file server instance only and overrides any other site root that may have been defined. Default: `{http.vars.root}` or the current working directory. Note: This subdirective only changes the root for this handler. For other directives (like [`try_files`](/docs/caddyfile/directives/try_files) or [`templates`](/docs/caddyfile/directives/templates)) to know the same site root, use the [`root`](/docs/caddyfile/directives/root) directive, not this subdirective.
|
||||
- **hide** is a list of files or folders to hide; if requested, the file server will pretend they do not exist. Accepts placeholders and glob patterns. Note that these are _file system_ paths, NOT request paths. In other words, relative paths use the current working directory as a base, NOT the site root; and all paths are transformed to their absolute form before comparisons (if possible). Specifying a file name or pattern without a path separator will hide all files with a matching name regardless of its location; otherwise, a path prefix match will be attempted, and then a globular match. Since this is a Caddyfile config, the active configuration file(s) will be added by default.
|
||||
- **index** is a list of filenames to look for as index files. Default: `index.html index.txt`
|
||||
- **<template_file>** is an optional custom template file to use for directory listings. Defaults to the template that can be found [here in the source code ](https://github.com/caddyserver/caddy/blob/master/modules/caddyhttp/fileserver/browse.html). Browse templates can use actions from [the standard templates module](/docs/modules/http.handlers.templates#docs) as well.
|
||||
- **precompressed** is the list of encoding formats to search for precompressed sidecar files. Arguments are an ordered list of encoding formats to search for precompressed [sidecar files](https://en.wikipedia.org/wiki/Sidecar_file). Supported formats are `gzip` (`.gz`), `zstd` (`.zst`) and `br` (`.br`).
|
||||
|
||||
All file lookups will look for the existence of the uncompressed file first. Once found Caddy will look for sidecar files with the file extension of each enabled format. If a precompressed sidecar file is found, Caddy will respond with the precompressed file, with the `Content-Encoding` response header set appropriately. Otherwise, Caddy will respond with the uncompressed file as normal. If the [`encode` directive](/docs/caddyfile/directives/encode) is enabled, then it may compress the response on-the-fly if not precompressed.
|
||||
- **status** is an optional status code override to be used when writing the response. Particularly useful when responding to a request with a custom error page. Can be a 3-digit status code, For example: `404`. Placeholders are supported. By default, the written status code will typically be `200`, or `206` for partial content.
|
||||
- **disable_canonical_uris** disables the default behaviour of redirecting to add a trailing slash if the request path is a directory, or remove the trailing slash if the request path is a file. Note that by default, canonicalization will not happen if the last element of the request's path (the filename) underwent an internal rewrite, to avoid clobbering an explicit rewrite with implicit behaviour.
|
||||
- **pass_thru** enables pass-thru mode, which continues to the next HTTP handler in the route if the requested file is not found, instead of returning a `404`. Practically, this is likely only be useful inside of a [`route`](/docs/caddyfile/directives/route) block, because the `file_server` directive is effectively [ordered last](/docs/caddyfile/directives#directive-order) otherwise.
|
||||
|
||||
## Examples
|
||||
|
||||
A static file server out of the current directory:
|
||||
|
||||
```caddy-d
|
||||
file_server
|
||||
```
|
||||
|
||||
With file listings enabled:
|
||||
|
||||
```caddy-d
|
||||
file_server browse
|
||||
```
|
||||
|
||||
Only serve static files within the `/static` folder:
|
||||
|
||||
```caddy-d
|
||||
file_server /static/*
|
||||
```
|
||||
|
||||
The `file_server` directive is usually paired with the [`root` directive](/docs/caddyfile/directives/root) to set the root path from which to serve files:
|
||||
|
||||
```caddy-d
|
||||
root * /home/user/public_html
|
||||
file_server
|
||||
```
|
||||
|
||||
Hide all `.git` folders and their contents:
|
||||
|
||||
```caddy-d
|
||||
file_server {
|
||||
hide .git
|
||||
}
|
||||
```
|
||||
|
||||
If supported by the client (`Accept-Encoding` header) checks the existence of precompressed files along side the requested file. So if `/path/to/file` is requested, it checks for `/path/to/file.zst`, `/path/to/file.br` and `/path/to/file.gz` in that order and serves the first available file with corresponding Content-Encoding:
|
||||
|
||||
```caddy-d
|
||||
file_server {
|
||||
precompressed zstd br gzip
|
||||
}
|
||||
```
|
129
src/docs/markdown/caddyfile/directives/forward_auth.md
Normal file
129
src/docs/markdown/caddyfile/directives/forward_auth.md
Normal file
|
@ -0,0 +1,129 @@
|
|||
---
|
||||
title: forward_auth (Caddyfile directive)
|
||||
---
|
||||
|
||||
# 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.
|
||||
|
||||
- [Syntax](#syntax)
|
||||
- [Expanded Form](#expanded-form)
|
||||
- [Examples](#examples)
|
||||
- [Authelia](#authelia)
|
||||
- [Tailscale](#tailscale)
|
||||
|
||||
Caddy's [`reverse_proxy`](/docs/caddyfile/directives/reverse_proxy) is capable of performing "pre-check requests" to an external service, but this directive is tailored specifically for the authentication usecase. This directive is actually just a convenient way to use a longer, more common configuration (below).
|
||||
|
||||
This directive makes a `GET` request to the configured upstream with the `uri` rewritten:
|
||||
- If the upstream responds with a `2xx` status code, then access is granted and the header fields in `copy_headers` are copied to the original request, and handling continues.
|
||||
- Otherwise, if the upstream responds with any other status code, then the upstream's response is copied back to the client. This response should typically involve a redirect to login page of the authentication gateway.
|
||||
|
||||
If this behaviour is not exactly what you want, you may take the [expanded form](#expanded-form) below as a basis and customize it to your needs.
|
||||
|
||||
All the subdirectives of [`reverse_proxy`](/docs/caddyfile/directives/reverse_proxy) are supported, and passed through to the underlying `reverse_proxy` handler.
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
forward_auth [<matcher>] [<upstreams...>] {
|
||||
uri <to>
|
||||
copy_headers <fields...> {
|
||||
<fields...>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **<upstreams...>** is a list of upstreams (backends) to which to send auth requests.
|
||||
|
||||
- **uri** is the URI (path and query) to set on the request sent to the upstream. This will usually be the verification endpoint of the authentication gateway.
|
||||
|
||||
- **copy_headers** is a list of HTTP header fields to copy from the response to the original request, when the request has a success status code.
|
||||
|
||||
The field can be renamed by using `>` followed by the new name, for example `Before>After`.
|
||||
|
||||
A block may be used to list all the fields, one per line, if you prefer for readability.
|
||||
|
||||
Since this directive is an opinionated wrapper over a reverse proxy, you can use any of [`reverse_proxy`](/docs/caddyfile/directives/reverse_proxy#syntax)'s subdirectives to customize it.
|
||||
|
||||
|
||||
## Expanded form
|
||||
|
||||
The `forward_auth` directive is the same as the following configuration. Auth gateways like [Authelia](https://www.authelia.com/) work well with this preset. If yours does not, feel free to borrow from this and customize it as needed instead of using the `forward_auth` shortcut.
|
||||
|
||||
```caddy-d
|
||||
reverse_proxy <upstreams...> {
|
||||
# Always GET, so that the incoming
|
||||
# request's body is not consumed
|
||||
method GET
|
||||
|
||||
# Change the URI to the auth gateway's
|
||||
# verification endpoint
|
||||
rewrite <to>
|
||||
|
||||
# Forward the original method and URI,
|
||||
# since they get rewritten above; this
|
||||
# is in addition to other X-Forwarded-*
|
||||
# headers already set by reverse_proxy
|
||||
header_up X-Forwarded-Method {method}
|
||||
header_up X-Forwarded-Uri {uri}
|
||||
|
||||
# On a successful response, copy response headers
|
||||
@good status 2xx
|
||||
handle_response @good {
|
||||
request_header {
|
||||
# for example, for each copy_headers field...
|
||||
Remote-User {rp.header.Remote-User}
|
||||
Remote-Email {rp.header.Remote-Email}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
### Authelia
|
||||
|
||||
Delegating authentication to [Authelia](https://www.authelia.com/), before serving your app via a reverse proxy:
|
||||
|
||||
```caddy
|
||||
# Serve the authentication gateway itself
|
||||
auth.example.com {
|
||||
reverse_proxy authelia:9091
|
||||
}
|
||||
|
||||
# Serve your app
|
||||
app1.example.com {
|
||||
forward_auth authelia:9091 {
|
||||
uri /api/verify?rd=https://auth.example.com
|
||||
copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
|
||||
}
|
||||
|
||||
reverse_proxy app1:8080
|
||||
}
|
||||
```
|
||||
|
||||
For more information, see [Authelia's documentation](https://www.authelia.com/integration/proxies/caddy/) for integrating with Caddy.
|
||||
|
||||
|
||||
### Tailscale
|
||||
|
||||
Delegating authentication to [Tailscale](https://tailscale.com/) (currently named [`nginx-auth`](https://tailscale.com/blog/tailscale-auth-nginx/), but it still works with Caddy), and using the alternative syntax for `copy_headers` to *rename* the copied headers (note the `>` in each header):
|
||||
|
||||
```caddy-d
|
||||
forward_auth unix//run/tailscale.nginx-auth.sock {
|
||||
uri /auth
|
||||
header_up Remote-Addr {remote_host}
|
||||
header_up Remote-Port {remote_port}
|
||||
header_up Original-URI {uri}
|
||||
copy_headers {
|
||||
Tailscale-User>X-Webauth-User
|
||||
Tailscale-Name>X-Webauth-Name
|
||||
Tailscale-Login>X-Webauth-Login
|
||||
Tailscale-Tailnet>X-Webauth-Tailnet
|
||||
Tailscale-Profile-Picture>X-Webauth-Profile-Picture
|
||||
}
|
||||
}
|
||||
```
|
57
src/docs/markdown/caddyfile/directives/handle.md
Normal file
57
src/docs/markdown/caddyfile/directives/handle.md
Normal file
|
@ -0,0 +1,57 @@
|
|||
---
|
||||
title: handle (Caddyfile directive)
|
||||
---
|
||||
|
||||
# handle
|
||||
|
||||
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.
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
handle [<matcher>] {
|
||||
<directives...>
|
||||
}
|
||||
```
|
||||
|
||||
- **<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 inheritence-based way like nginx location blocks, you may prefer the use of `handle` blocks rather than defining mutually-exclusive matchers for your directives. If inheritence is a desired characteristic of your HTTP handler configurations, then the `handle` directive may suit you well.
|
||||
|
||||
## 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:
|
||||
|
||||
- [`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.
|
||||
- [`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.
|
||||
|
||||
## Examples
|
||||
|
||||
Handle requests in `/foo/` by the static file server, and send all other requests to the reverse proxy:
|
||||
|
||||
```caddy-d
|
||||
handle /foo/* {
|
||||
file_server
|
||||
}
|
||||
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:
|
||||
|
||||
```caddy-d
|
||||
handle_path /foo/* {
|
||||
# The path has the "/foo" prefix stripped
|
||||
}
|
||||
|
||||
handle /bar/* {
|
||||
# The path still retains "/bar"
|
||||
}
|
||||
```
|
100
src/docs/markdown/caddyfile/directives/handle_errors.md
Normal file
100
src/docs/markdown/caddyfile/directives/handle_errors.md
Normal file
|
@ -0,0 +1,100 @@
|
|||
---
|
||||
title: handle_errors (Caddyfile directive)
|
||||
---
|
||||
|
||||
# handle_errors
|
||||
|
||||
Sets up error handlers.
|
||||
|
||||
When the normal HTTP request handlers return an error, normal processing stops and the error handlers are invoked. Error handlers form a route which is just like normal routes, and they can do anything that normal routes can do. This enables great control and flexibility when handling errors during HTTP requests. For example, you can serve static error pages, templated error pages, or reverse proxy to another backend to handle errors.
|
||||
|
||||
A request's context is carried into error routes, so any values set on the request context such as [site root](root) or [vars](vars) will be preserved in error handlers, too. Additionally, [new placeholders](#placeholders) are available when handling errors.
|
||||
|
||||
Note that certain directives, for example [`reverse_proxy`](reverse_proxy) which may write a response with an HTTP status which is classified as an error, will _not_ trigger the error routes.
|
||||
|
||||
You may use the [`error`](error) directive to explicitly trigger an error based on your own routing decisions.
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
handle_errors {
|
||||
<directives...>
|
||||
}
|
||||
```
|
||||
|
||||
- **<directives...>** is a list of HTTP handler [directives](/docs/caddyfile/directives) and [matchers](/docs/caddyfile/matchers), one per line.
|
||||
|
||||
|
||||
## Placeholders
|
||||
|
||||
The following placeholders are available while handling errors. They are [Caddyfile shorthands](/docs/caddyfile/concepts#placeholders) for the full placeholders which can be found in [the JSON docs for an HTTP server's error routes](/docs/json/apps/http/servers/errors/#routes).
|
||||
|
||||
| Placeholder | Description |
|
||||
|---|---|
|
||||
| `{err.status_code}` | The recommended HTTP status code |
|
||||
| `{err.status_text}` | The status text associated with the recommended status code |
|
||||
| `{err.message}` | The error message |
|
||||
| `{err.trace}` | The origin of the error |
|
||||
| `{err.id}` | An identifier for this occurrence of the error |
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Custom error pages based on the status code (i.e. a page called `404.html` for 404 errors). Note that [`file_server`](file_server) preserves the error's HTTP status code when run in `handle_errors` (assumes you set a [site root](/docs/caddyfile/directives/root) in your site beforehand):
|
||||
|
||||
```caddy-d
|
||||
handle_errors {
|
||||
rewrite * /{err.status_code}.html
|
||||
file_server
|
||||
}
|
||||
```
|
||||
|
||||
A single error page that uses [`templates`](/docs/caddyfile/directives/templates) to write a custom error message:
|
||||
|
||||
```caddy-d
|
||||
handle_errors {
|
||||
rewrite * /error.html
|
||||
templates
|
||||
file_server
|
||||
}
|
||||
```
|
||||
|
||||
Reverse proxy to a professional server that is highly qualified for handling HTTP errors and improving your day 😸:
|
||||
|
||||
```caddy-d
|
||||
handle_errors {
|
||||
rewrite * /{err.status_code}
|
||||
reverse_proxy https://http.cat {
|
||||
header_up Host {upstream_hostport}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Simply use [`respond`](/docs/caddyfile/directives/respond) to return the error code and name
|
||||
|
||||
```caddy-d
|
||||
handle_errors {
|
||||
respond "{err.status_code} {err.status_text}"
|
||||
}
|
||||
```
|
||||
|
||||
To handle specific error codes differently, use an [`expression`](/docs/caddyfile/matchers#expression) matcher, using [`handle`](/docs/caddyfile/directives/handle) for mutual exclusivity:
|
||||
|
||||
```caddy-d
|
||||
handle_errors {
|
||||
@404-410 expression `{err.status_code} in [404, 410]`
|
||||
handle @404-410 {
|
||||
respond "It's a 404 or 410 error!"
|
||||
}
|
||||
|
||||
@5xx expression `{err.status_code} >= 500 && {err.status_code} < 600`
|
||||
handle @5xx {
|
||||
respond "It's a 5xx error."
|
||||
}
|
||||
|
||||
handle {
|
||||
respond "It's another error"
|
||||
}
|
||||
}
|
||||
```
|
43
src/docs/markdown/caddyfile/directives/handle_path.md
Normal file
43
src/docs/markdown/caddyfile/directives/handle_path.md
Normal file
|
@ -0,0 +1,43 @@
|
|||
---
|
||||
title: handle_path (Caddyfile directive)
|
||||
---
|
||||
|
||||
# handle_path
|
||||
|
||||
Same as the [`handle` directive](/docs/caddyfile/directives/handle), but implicitly strips 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.
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
handle_path <path_matcher> {
|
||||
<directives...>
|
||||
}
|
||||
```
|
||||
|
||||
- **<directives...>** is a list of HTTP handler directives or directive blocks, one per line, just like would be used outside of a handle_path block.
|
||||
|
||||
Note that only a single path matcher is accepted and required; you cannot use other kinds of matchers with handle_path.
|
||||
|
||||
## Examples
|
||||
|
||||
This configuration:
|
||||
|
||||
```caddy-d
|
||||
handle_path /prefix/* {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
is effectively the same as this:
|
||||
|
||||
```caddy-d
|
||||
handle /prefix/* {
|
||||
uri strip_prefix /prefix
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
but the `handle_path` form is slightly more succinct.
|
108
src/docs/markdown/caddyfile/directives/header.md
Normal file
108
src/docs/markdown/caddyfile/directives/header.md
Normal file
|
@ -0,0 +1,108 @@
|
|||
---
|
||||
title: header (Caddyfile directive)
|
||||
---
|
||||
|
||||
# header
|
||||
|
||||
Manipulates HTTP header fields on the response. It can set, add, and delete header values, or perform replacements using regular expressions.
|
||||
|
||||
By default, header operations are performed immediately unless any of the headers are being deleted (`-` 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.
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
header [<matcher>] [[+|-|?]<field> [<value>|<find>] [<replace>]] {
|
||||
# Replace
|
||||
<field> <find> <replace>
|
||||
|
||||
# Add or Set
|
||||
[+]<field> <value>
|
||||
|
||||
# Delete
|
||||
-<field>
|
||||
|
||||
# Default
|
||||
?<field> <value>
|
||||
|
||||
[defer]
|
||||
}
|
||||
```
|
||||
|
||||
- **<field>** is the name of the header field. By default, will overwrite any existing field of the same name.
|
||||
|
||||
Prefix with `+` to add the field instead of overwriting (setting) the field if it already exists; header fields can appear more than once in a request.
|
||||
|
||||
Prefix with `-` to delete the field. The field may use prefix or suffix `*` wildcards to delete all matching fields.
|
||||
|
||||
Prefix with `?` to set a default value for the field. The field is only written if it doesn't yet exist.
|
||||
|
||||
- **<value>** is the header field value, if adding or setting a field.
|
||||
|
||||
- **<find>** is the substring or regular expression to search for.
|
||||
|
||||
- **<replace>** is the replacement value; required if performing a search-and-replace.
|
||||
|
||||
- **defer** will force the header operations to be deferred until the response is being written out to the client. This is automatically enabled if any of the header fields are being deleted with `-`, or when setting a default value with `?`.
|
||||
|
||||
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](https://caddyserver.com/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.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Set a custom header field on all requests:
|
||||
|
||||
```caddy-d
|
||||
header Custom-Header "My value"
|
||||
```
|
||||
|
||||
Strip the "Hidden" header field:
|
||||
|
||||
```caddy-d
|
||||
header -Hidden
|
||||
```
|
||||
|
||||
Replace `http://` with `https://` in any Location header:
|
||||
|
||||
```caddy-d
|
||||
header Location http:// https://
|
||||
```
|
||||
|
||||
Set security and privacy headers on all pages: (**WARNING:** only use if you understand the implications!)
|
||||
|
||||
```caddy-d
|
||||
header {
|
||||
# disable FLoC tracking
|
||||
Permissions-Policy interest-cohort=()
|
||||
|
||||
# enable HSTS
|
||||
Strict-Transport-Security max-age=31536000;
|
||||
|
||||
# disable clients from sniffing the media type
|
||||
X-Content-Type-Options nosniff
|
||||
|
||||
# clickjacking protection
|
||||
X-Frame-Options DENY
|
||||
|
||||
# keep referrer data off of HTTP connections
|
||||
Referrer-Policy no-referrer-when-downgrade
|
||||
}
|
||||
```
|
||||
|
||||
Multiple header directives that are intended to be mutually-exclusive:
|
||||
|
||||
```caddy-d
|
||||
route {
|
||||
header Cache-Control max-age=3600
|
||||
header /static/* Cache-Control max-age=31536000
|
||||
}
|
||||
```
|
||||
|
||||
Set a default cache expiration if upstream doesn't define one:
|
||||
|
||||
```caddy-d
|
||||
header ?Cache-Control "max-age=3600"
|
||||
reverse_proxy upstream:443
|
||||
```
|
41
src/docs/markdown/caddyfile/directives/import.md
Normal file
41
src/docs/markdown/caddyfile/directives/import.md
Normal file
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
title: import (Caddyfile directive)
|
||||
---
|
||||
|
||||
# import
|
||||
|
||||
Includes a [snippet](/docs/caddyfile/concepts#snippets) or file, replacing this directive with the contents of the snippet or file.
|
||||
|
||||
This directive is a special case: it is evaluated before the structure is parsed, and it can appear anywhere in the Caddyfile.
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
import <pattern> [<args...>]
|
||||
```
|
||||
|
||||
- **<pattern>** is the filename, glob pattern, or name of [snippet](/docs/caddyfile/concepts#snippets) to include. Its contents will replace this line as if that file's contents appeared here to begin with. It is an error if a specific file cannot be found, but an empty glob pattern is not an error. If the pattern is a filename or glob, it is always relative to the file the `import` appears in.
|
||||
- **<args...>** is an optional list of arguments to pass to the imported tokens. They can be used with a placeholder of the form `{args.N}` where `N` is the 0-based positional index of the parameter. This placeholder is a special case and is evaluated at parse-time, not run-time.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Import all files in an adjacent sites-enabled folder:
|
||||
|
||||
```caddy-d
|
||||
import sites-enabled/*
|
||||
```
|
||||
|
||||
Import a snippet that sets CORS headers using an import argument:
|
||||
|
||||
```caddy
|
||||
(cors) {
|
||||
@origin header Origin {args.0}
|
||||
header @origin Access-Control-Allow-Origin "{args.0}"
|
||||
header @origin Access-Control-Allow-Methods "OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE"
|
||||
}
|
||||
|
||||
example.com {
|
||||
import cors example.com
|
||||
}
|
||||
```
|
391
src/docs/markdown/caddyfile/directives/log.md
Normal file
391
src/docs/markdown/caddyfile/directives/log.md
Normal file
|
@ -0,0 +1,391 @@
|
|||
---
|
||||
title: log (Caddyfile directive)
|
||||
---
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
// We'll add links to all the subdirectives if a matching anchor tag is found on the page.
|
||||
addLinksToSubdirectives();
|
||||
});
|
||||
</script>
|
||||
|
||||
# log
|
||||
|
||||
Enables and configures HTTP request logging (also known as access logs).
|
||||
|
||||
<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.
|
||||
|
||||
</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).
|
||||
|
||||
- [Syntax](#syntax)
|
||||
- [Output modules](#output-modules)
|
||||
- [stderr](#stderr)
|
||||
- [stdout](#stdout)
|
||||
- [discard](#discard)
|
||||
- [file](#file)
|
||||
- [net](#net)
|
||||
- [Format modules](#format-modules)
|
||||
- [console](#console)
|
||||
- [json](#json)
|
||||
- [filter](#filter)
|
||||
- [delete](#delete)
|
||||
- [rename](#rename)
|
||||
- [replace](#replace)
|
||||
- [ip_mask](#ip-mask)
|
||||
- [query](#query)
|
||||
- [cookie](#cookie)
|
||||
- [regexp](#regexp)
|
||||
- [hash](#hash)
|
||||
- [Examples](#examples)
|
||||
|
||||
Since Caddy v2.5, by default, headers with potentially sensitive information (`Cookie`, `Set-Cookie`, `Authorization` and `Proxy-Authorization`) will be logged with empty values. This behaviour can be disabled with the [`log_credentials`](/docs/caddyfile/options#log-credentials) global server option.
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
log {
|
||||
output <writer_module> ...
|
||||
format <encoder_module> ...
|
||||
level <level>
|
||||
}
|
||||
```
|
||||
|
||||
- **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 `stdout` 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
|
||||
|
||||
The **output** subdirective lets you customize where logs get written. It appears within a `log` block.
|
||||
|
||||
#### stderr
|
||||
|
||||
Standard error (console, default).
|
||||
|
||||
```caddy-d
|
||||
output stderr
|
||||
```
|
||||
|
||||
#### stdout
|
||||
|
||||
Standard output (console).
|
||||
|
||||
```caddy-d
|
||||
output stdout
|
||||
```
|
||||
|
||||
#### discard
|
||||
|
||||
No output.
|
||||
|
||||
```caddy-d
|
||||
output discard
|
||||
```
|
||||
|
||||
#### file
|
||||
|
||||
A file. By default, log files are rotated ("rolled") to prevent disk space exhaustion.
|
||||
|
||||
```caddy-d
|
||||
output file <filename> {
|
||||
roll_disabled
|
||||
roll_size <size>
|
||||
roll_uncompressed
|
||||
roll_local_time
|
||||
roll_keep <num>
|
||||
roll_keep_for <days>
|
||||
}
|
||||
```
|
||||
|
||||
- **<filename>** 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_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_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)
|
||||
|
||||
|
||||
#### net
|
||||
|
||||
A network socket. If the socket goes down, it will dump logs to stderr while it attempts to reconnect.
|
||||
|
||||
```caddy-d
|
||||
output net <address> {
|
||||
dial_timeout <duration>
|
||||
}
|
||||
```
|
||||
|
||||
- **<address>** 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.
|
||||
|
||||
|
||||
|
||||
### Format modules
|
||||
|
||||
The **format** subdirective lets you customize how logs get encoded (formatted). It appears within a `log` block.
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
**A note about Common Log Format (CLF):** CLF clashes with modern structured logs. To transform your access logs into the deprecated Common Log Format, please use the [`transform-encoder` plugin](https://github.com/caddyserver/transform-encoder).
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
In addition to the syntax for each individual encoder, these common properties can be set on most encoders:
|
||||
|
||||
```caddy-d
|
||||
format <encoder_module> {
|
||||
message_key <key>
|
||||
level_key <key>
|
||||
time_key <key>
|
||||
name_key <key>
|
||||
caller_key <key>
|
||||
stacktrace_key <key>
|
||||
line_ending <char>
|
||||
time_format <format>
|
||||
duration_format <format>
|
||||
level_format <format>
|
||||
}
|
||||
```
|
||||
|
||||
- **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`
|
||||
- **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`
|
||||
- **caller_key** The key for the caller field of the log entry.
|
||||
- **stacktrace_key** The key for the stacktrace field of the log entry.
|
||||
- **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.
|
||||
- **unix_milli_float** Floating-point number of milliseconds since the Unix epoch.
|
||||
- **unix_nano** Integer number of nanoseconds since the Unix epoch.
|
||||
- **iso8601** Example: `2006-01-02T15:04:05.000Z0700`
|
||||
- **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.
|
||||
- **duration_format** The format for durations. May be one of:
|
||||
- **seconds** Floating-point number of seconds elapsed; this is the default.
|
||||
- **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. May be one of:
|
||||
- **lower** Lowercase; this is the default.
|
||||
- **upper** Uppercase.
|
||||
- **color** Uppercase, with console colors.
|
||||
|
||||
|
||||
#### console
|
||||
|
||||
The console encoder formats the log entry for human readability while preserving some structure.
|
||||
|
||||
```caddy-d
|
||||
format console
|
||||
```
|
||||
|
||||
#### json
|
||||
|
||||
Formats each log entry as a JSON object.
|
||||
|
||||
```caddy-d
|
||||
format json
|
||||
```
|
||||
|
||||
|
||||
#### filter
|
||||
|
||||
Wraps another encoder module, allowing per-field filtering.
|
||||
|
||||
```caddy-d
|
||||
format filter {
|
||||
wrap <encode_module> ...
|
||||
fields {
|
||||
<field> <filter> ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Nested fields can be referenced by representing a layer of nesting with `>`. In other words, for an object like `{"a":{"b":0}}`, the inner field can be referenced as `a>b`.
|
||||
|
||||
The following fields are fundamental to the log and cannot be filtered because they are added by the underlying logging library as special cases: `ts`, `level`, `logger`, and `msg`.
|
||||
|
||||
These are the available filters:
|
||||
|
||||
##### delete
|
||||
|
||||
Marks a field to be skipped from being encoded.
|
||||
|
||||
```caddy-d
|
||||
<field> delete
|
||||
```
|
||||
|
||||
##### rename
|
||||
|
||||
Rename the key of a log field.
|
||||
|
||||
```caddy-d
|
||||
<field> rename <key>
|
||||
```
|
||||
|
||||
##### replace
|
||||
|
||||
Marks a field to be replaced with the provided string at encoding time.
|
||||
|
||||
```caddy-d
|
||||
<field> replace <replacement>
|
||||
```
|
||||
|
||||
##### ip_mask
|
||||
|
||||
Masks IP addresses in the field using a CIDR mask, i.e. the number of bytes from the IP to retain, starting from the left side. There is separate configuration for IPv4 and IPv6 addresses. Most commonly, the field to filter would be `request>remote_ip`.
|
||||
|
||||
```caddy-d
|
||||
<field> ip_mask {
|
||||
ipv4 <cidr>
|
||||
ipv6 <cidr>
|
||||
}
|
||||
```
|
||||
|
||||
##### 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 `uri`. The available actions are:
|
||||
|
||||
```caddy-d
|
||||
<field> query {
|
||||
delete <key>
|
||||
replace <key> <replacement>
|
||||
hash <key>
|
||||
}
|
||||
```
|
||||
|
||||
- **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.
|
||||
- **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
|
||||
|
||||
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:
|
||||
|
||||
```caddy-d
|
||||
<field> cookie {
|
||||
delete <name>
|
||||
replace <name> <replacement>
|
||||
hash <name>
|
||||
}
|
||||
```
|
||||
|
||||
- **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.
|
||||
- **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.
|
||||
|
||||
##### regexp
|
||||
|
||||
Marks a field to have a regular expression replacement applied at encoding time.
|
||||
|
||||
```caddy-d
|
||||
<field> regexp <pattern> <replacement>
|
||||
```
|
||||
|
||||
The regular expression language used is RE2, included in Go. See the [RE2 syntax reference](https://github.com/google/re2/wiki/Syntax) and the [Go regexp syntax overview](https://pkg.go.dev/regexp/syntax).
|
||||
|
||||
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
|
||||
|
||||
Marks a field to be replaced with the first 4 bytes of the SHA-256 hash of the value at encoding time. Useful to obscure the value if it's sensitive, while being able to notice whether each request had a different value.
|
||||
|
||||
```caddy-d
|
||||
<field> hash
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Enable access logging (to the console):
|
||||
|
||||
```caddy-d
|
||||
log
|
||||
```
|
||||
|
||||
|
||||
Write logs to a file (with log rolling, which is enabled by default):
|
||||
|
||||
```caddy-d
|
||||
log {
|
||||
output file /var/log/access.log
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Customize log rolling:
|
||||
|
||||
```caddy-d
|
||||
log {
|
||||
output file /var/log/access.log {
|
||||
roll_size 1gb
|
||||
roll_keep 5
|
||||
roll_keep_for 720h
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Delete the Authorization request header from the logs:
|
||||
|
||||
```caddy-d
|
||||
log {
|
||||
format filter {
|
||||
wrap console
|
||||
fields {
|
||||
request>headers>Authorization delete
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Redact multiple sensitive cookies:
|
||||
|
||||
```caddy-d
|
||||
log {
|
||||
format filter {
|
||||
wrap console
|
||||
fields {
|
||||
request>headers>Cookie cookie {
|
||||
replace session REDACTED
|
||||
delete secret
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Mask the remote address from the request, keeping the first 16 bits (i.e. 255.255.0.0) for IPv4 addresses, and the first 32 bits from IPv6 addresses. (Note that prior to Caddy v2.5, the field was named `remote_addr`, but is now `remote_ip`):
|
||||
|
||||
```caddy-d
|
||||
log {
|
||||
format filter {
|
||||
wrap console
|
||||
fields {
|
||||
request>remote_ip ip_mask {
|
||||
ipv4 16
|
||||
ipv6 32
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
64
src/docs/markdown/caddyfile/directives/map.md
Normal file
64
src/docs/markdown/caddyfile/directives/map.md
Normal file
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
title: map (Caddyfile directive)
|
||||
---
|
||||
|
||||
# map
|
||||
|
||||
Sets values of custom placeholders switched on an input value.
|
||||
|
||||
It compares the source value against the input side of the map, and for one that matches, it applies the output value(s) to each destination. Destinations become placeholder names. Default output values may also be specified for each destination.
|
||||
|
||||
Mapped placeholders are not evaluated until they are used, so even for very large mappings, this directive is quite efficient.
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
map [<matcher>] <source> <destinations...> {
|
||||
[~]<input> <outputs...>
|
||||
default <defaults...>
|
||||
}
|
||||
```
|
||||
|
||||
- **<source>** is the input value to switch on. Usually a placeholder.
|
||||
|
||||
- **<destinations...>** are the placeholders to create that hold the output values.
|
||||
|
||||
- **<input>** is the input value to match. If prefixed with `~`, it is treated as a regular expression.
|
||||
|
||||
- **<outputs...>** is one or more output values to store in the associated placeholder. The first output is written to the first destination, the second output to the second destination, etc.
|
||||
|
||||
As a special case, the Caddyfile parser treats outputs that are a literal hyphen (`-`) as null/nil values. This is useful if you want to fall back to a default value for that particular output in the case of the given input, but want to use non-default values for other outputs.
|
||||
|
||||
The outputs will be type converted if possible; `true` and `false` will be converted to boolean types, and numeric values will be converted to integer or float accordingly. To avoid this conversion, you may wrap the output with [quotes](/docs/caddyfile/concepts#tokens-and-quotes) and they will stay strings.
|
||||
|
||||
The number of outputs for each mapping must not exceed the number of destinations; however, for convenience, there may be fewer outputs than destinations, and any missing outputs will be filled in implicitly.
|
||||
|
||||
If a regular expression was used as the input, then the 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.
|
||||
|
||||
- **<default>** specifies the output values to store if no inputs are matched.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
The following example demonstrates most aspects of this directive:
|
||||
|
||||
```caddy-d
|
||||
map {host} {my_placeholder} {magic_number} {
|
||||
example.com "some value" 3
|
||||
foo.example.com "another value"
|
||||
~(.*)\.example\.com$ "${1} subdomain" 5
|
||||
|
||||
~.*\.net$ - 7
|
||||
~.*\.xyz$ - 15
|
||||
|
||||
default "unknown domain" 42
|
||||
}
|
||||
```
|
||||
|
||||
This directive switches on the value of `{host}`, i.e. the domain name of the request.
|
||||
|
||||
- If the request is for `example.com`, set `{my_placeholder}` to `some value`, and `{magic_number}` to `3`.
|
||||
- Else, if the request is for `foo.example.com`, set `{my_placeholder}` to `another value`, and let `{magic_number}` default to `42`.
|
||||
- Else, if the request is for any subdomain of `example.com`, set `{my_placeholder}` to a string containing the value of the first regexp capture group, i.e the entire subdomain, and set `{magic_number}` to 5.
|
||||
- Else, if the request is for any host that ends in `.net` or `.xyz`, set only `{magic_number}` to `7` or `15`, respectively. Leave `{my_placeholder}` unset.
|
||||
- Else (for all other hosts), the default values will apply: `{my_placeholder}` will be set to `unknown domain` and `{magic_number}` will be set to `42`.
|
25
src/docs/markdown/caddyfile/directives/method.md
Normal file
25
src/docs/markdown/caddyfile/directives/method.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
title: method (Caddyfile directive)
|
||||
---
|
||||
|
||||
# method
|
||||
|
||||
Changes the HTTP method on the request.
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
method [<matcher>] <method>
|
||||
```
|
||||
|
||||
- **<method>** is the HTTP method to change the request to.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Change the method for all requests under `/api` to `POST`:
|
||||
|
||||
```caddy-d
|
||||
method /api* POST
|
||||
```
|
58
src/docs/markdown/caddyfile/directives/metrics.md
Normal file
58
src/docs/markdown/caddyfile/directives/metrics.md
Normal file
|
@ -0,0 +1,58 @@
|
|||
---
|
||||
title: metrics (Caddyfile directive)
|
||||
---
|
||||
|
||||
# metrics
|
||||
|
||||
Configures a Prometheus metrics exposition endpoint so the gathered metrics can
|
||||
be exposed for scraping.
|
||||
|
||||
Note that a `/metrics` endpoint is also attached to the [admin API](/docs/api),
|
||||
which is not configurable, and is not available when the admin API is disabled.
|
||||
|
||||
This endpoint will return metrics in the [Prometheus exposition format](https://prometheus.io/docs/instrumenting/exposition_formats/#text-based-format)
|
||||
or, if negotiated, in the [OpenMetrics exposition format](https://pkg.go.dev/github.com/prometheus/client_golang@v1.9.0/prometheus/promhttp#HandlerOpts)
|
||||
(`application/openmetrics-text`).
|
||||
|
||||
See also [Monitoring Caddy with Prometheus metrics](/docs/metrics).
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
metrics [<matcher>] {
|
||||
disable_openmetrics
|
||||
}
|
||||
```
|
||||
|
||||
- **disable_openmetrics** disables OpenMetrics negotiation. Usually not
|
||||
necessary except when needing to work around parsing bugs.
|
||||
|
||||
## Examples
|
||||
|
||||
Expose metrics at the default `/metrics` path:
|
||||
|
||||
```caddy-d
|
||||
metrics /metrics
|
||||
```
|
||||
|
||||
Expose metrics at another path:
|
||||
|
||||
```caddy-d
|
||||
metrics /foo/bar/baz
|
||||
```
|
||||
|
||||
Serve metrics at a separate subdomain:
|
||||
|
||||
```caddy
|
||||
metrics.example.com {
|
||||
metrics
|
||||
}
|
||||
```
|
||||
|
||||
Disable OpenMetrics negotiation:
|
||||
|
||||
```caddy-d
|
||||
metrics /metrics {
|
||||
disable_openmetrics
|
||||
}
|
||||
```
|
139
src/docs/markdown/caddyfile/directives/php_fastcgi.md
Normal file
139
src/docs/markdown/caddyfile/directives/php_fastcgi.md
Normal file
|
@ -0,0 +1,139 @@
|
|||
---
|
||||
title: php_fastcgi (Caddyfile directive)
|
||||
---
|
||||
|
||||
# php_fastcgi
|
||||
|
||||
An opinionated directive that proxies requests to a PHP FastCGI server such as php-fpm.
|
||||
|
||||
- [Syntax](#syntax)
|
||||
- [Expanded Form](#expanded-form)
|
||||
- [Explanation](#explanation)
|
||||
- [Examples](#examples)
|
||||
|
||||
Caddy's [`reverse_proxy`](/docs/caddyfile/directives/reverse_proxy) is capable of serving any FastCGI application, but this directive is tailored specifically for PHP apps. This directive is actually just a convenient way to use a longer, more common configuration (below).
|
||||
|
||||
It expects that any `index.php` at the site root acts as a router. If that is not desirable, either reconfigure the `try_files` option to modify the default rewrite behaviour, or take the [expanded form](#expanded-form) below as a basis and customize it to your needs.
|
||||
|
||||
It supports all the subdirectives of [`reverse_proxy`](/docs/caddyfile/directives/reverse_proxy) and passes them through to the underlying `reverse_proxy` handler, plus a few subdirectives that customize the FastCGI transport specifically.
|
||||
|
||||
**Most modern PHP apps work fine without extra subdirectives or customization.** Subdirectives are usually only used in certain edge cases or with legacy PHP apps.
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
php_fastcgi [<matcher>] <php-fpm_gateways...> {
|
||||
root <path>
|
||||
split <substrings...>
|
||||
env [<key> <value>]
|
||||
index <filename>|off
|
||||
try_files <files...>
|
||||
resolve_root_symlink
|
||||
dial_timeout <duration>
|
||||
read_timeout <duration>
|
||||
write_timeout <duration>
|
||||
|
||||
<any other reverse_proxy subdirectives...>
|
||||
}
|
||||
```
|
||||
|
||||
- **<php-fpm_gateways...>** are the [addresses](/docs/conventions#network-addresses) of the FastCGI servers.
|
||||
- **root** sets the root folder to the site. Default: [`root` directive](/docs/caddyfile/directives/root).
|
||||
- **split** sets the substrings for splitting the URI into two parts. The first matching substring will be used to split the "path info" from the path. The first piece is suffixed with the matching substring and will be assumed as the actual resource (CGI script) name. The second piece will be set to PATH_INFO for the CGI script to use. Default: `.php`
|
||||
- **env** sets an extra environment variable to the given value. Can be specified more than once for multiple environment variables.
|
||||
- **index** specifies the filename to treat as the directory index file. This affects the file matcher in the [expanded form](#expanded-form). Default: `index.php`. Can be set to `off` to disable rewriting to `index.php` when a matching file is not found.
|
||||
- **try_files** specifies an override for the default try-files rewrite. See the [`try_files` directive](/docs/caddyfile/directives/try_files) for details. Default: `{path} {path}/index.php index.php`.
|
||||
- **resolve_root_symlink** enables resolving the `root` directory to its actual value by evaluating a symbolic link, if one exists.
|
||||
- **dial_timeout** is how long to wait when connecting to the upstream socket. Accepts [duration values](/docs/conventions#durations). Default: `3s`.
|
||||
- **read_timeout** is how long to wait when reading from the FastCGI server. Accepts [duration values](/docs/conventions#durations). Default: no timeout.
|
||||
- **write_timeout** is how long to wait when sending to the FastCGI server. Accepts [duration values](/docs/conventions#durations). Default: no timeout.
|
||||
|
||||
|
||||
Since this directive is an opinionated wrapper over a reverse proxy, you can use any of [`reverse_proxy`](/docs/caddyfile/directives/reverse_proxy#syntax)'s subdirectives to customize it.
|
||||
|
||||
|
||||
## Expanded form
|
||||
|
||||
The `php_fastcgi` directive (without subdirectives) is the same as the following configuration. Most modern PHP apps work well with this preset. If yours does not, feel free to borrow from this and customize it as needed instead of using the `php_fastcgi` shortcut.
|
||||
|
||||
```caddy-d
|
||||
route {
|
||||
# Add trailing slash for directory requests
|
||||
@canonicalPath {
|
||||
file {path}/index.php
|
||||
not path */
|
||||
}
|
||||
redir @canonicalPath {path}/ 308
|
||||
|
||||
# If the requested file does not exist, try index files
|
||||
@indexFiles file {
|
||||
try_files {path} {path}/index.php index.php
|
||||
split_path .php
|
||||
}
|
||||
rewrite @indexFiles {http.matchers.file.relative}
|
||||
|
||||
# Proxy PHP files to the FastCGI responder
|
||||
@phpFiles path *.php
|
||||
reverse_proxy @phpFiles <php-fpm_gateway> {
|
||||
transport fastcgi {
|
||||
split .php
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Explanation
|
||||
|
||||
- The first section deals with canonicalizing the request path. The goal is to ensure that requests that target a directory on disk actually have the trailing slash `/` added to the request path, so that only a single URL is valid for requests to that directory.
|
||||
|
||||
This is performed by using a request matcher that matches only requests that _don't_ end in a slash, and which map to a directory on disk which contains an `index.php` file, and if it matches, performs a HTTP 308 redirect with the trailing slash appended. So, for example it would redirect the request to path `/foo` to `/foo/` (appending a `/`, to canonicalize the path to the directory), if `/foo/index.php` exists on disk.
|
||||
|
||||
- The next section deals with performing path rewrites based on whether a matching file exists on disk. This also has the side-effect of remembering the part of the path after `.php` (if the request path had `.php` in it). This is important for Caddy to correctly set the FastCGI environment variables.
|
||||
|
||||
- First, it checks if `{path}` is a file that exists on disk. If so, it rewrites to that path. This essentially short-circuits the rest, and makes sure that requests to files that _do_ exists on disk don't get otherwise rewritten (see next steps below). So if for example you have a `/js/app.js` file on disk, then the request to that path will be kept the same.
|
||||
|
||||
- Second, it checks if `{path}/index.php` is a file that exists on disk. If so, it rewrites to that path. For requests to a directory like `/foo/` it'll then look for `/foo//index.php` (which gets normalized to `/foo/index.php`), and rewrite the request to that path if it exists. This behaviour is sometimes useful if you're running a PHP app in a subdirectory of another.
|
||||
|
||||
- Lastly, it'll rewrite to `index.php` if that file exists (it almost always should for modern PHP apps). This allows your PHP app to handle any request for paths that _don't_ map to files on disk, by using the `index.php` script as its entrypoint.
|
||||
|
||||
- And finally, the last section is what actually proxies the request to your PHP FastCGI (or PHP-FPM) service to actually run your PHP code. The request matcher will only match requests which end in `.php`, so, any file that _isn't_ a PHP script and that _does_ exist on disk, will _not_ be handled by this directive, and will fall through.
|
||||
|
||||
The `php_fastcgi` directive is not usually enough on its own. It should almost always be paired with the [`root` directive](/docs/caddyfile/directives/root) to set the location of your files on disk (for modern PHP apps, this may be `/var/www/html/public`, where the `public` directory is what contains your `index.php`), and the [`file_server` directive](/docs/caddyfile/directives/file_server) to serve your static files (your JS, CSS, images, etc) which aren't otherwise handled by this directive and fell through.
|
||||
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Proxy all PHP requests to a FastCGI responder listening at 127.0.0.1:9000:
|
||||
|
||||
```caddy-d
|
||||
php_fastcgi 127.0.0.1:9000
|
||||
```
|
||||
|
||||
Same, but only for requests under `/blog/`:
|
||||
|
||||
```caddy-d
|
||||
php_fastcgi /blog/* 127.0.0.1:9000
|
||||
```
|
||||
|
||||
When using php-fpm listening via a unix socket:
|
||||
|
||||
```caddy-d
|
||||
php_fastcgi unix//run/php/php7.4-fpm.sock
|
||||
```
|
||||
|
||||
The [`root` directive](/docs/caddyfile/directives/root) is typically used to specify the directory containing the PHP scripts, and the [`file_server` directive](/docs/caddyfile/directives/file_server) to serve static files:
|
||||
|
||||
```caddy-d
|
||||
root * /var/www/html/public
|
||||
php_fastcgi 127.0.0.1:9000
|
||||
file_server
|
||||
```
|
||||
|
||||
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 handled with the [`handle_errors` directive](/docs/caddyfile/directives/handle_errors):
|
||||
|
||||
```caddy-d
|
||||
php_fastcgi localhost:9000 {
|
||||
try_files {path} {path}/index.php =404
|
||||
}
|
||||
```
|
66
src/docs/markdown/caddyfile/directives/push.md
Normal file
66
src/docs/markdown/caddyfile/directives/push.md
Normal file
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
title: push (Caddyfile directive)
|
||||
---
|
||||
|
||||
# push
|
||||
|
||||
Configures the server to pre-emptively send resources to the client using HTTP/2 server push.
|
||||
|
||||
Resources can be linked for server push by specifying the Link header(s) of the response. This directive will automatically push resources described by upstream Link headers in these formats:
|
||||
|
||||
- `<resource>; as=script`
|
||||
- `<resource>; as=script,<resource>; as=style`
|
||||
- `<resource>; nopush`
|
||||
- `<resource>;<resource2>;...`
|
||||
|
||||
where `<resource>` begins with a forward slash `/` (i.e. is a URI path with the same host). Only same-host resources can be pushed. If a linked resource is external or if it has the `nopush` attribute, it will not be pushed.
|
||||
|
||||
By default, push requests will include some headers deemed safe to copy from the original request:
|
||||
|
||||
- Accept-Encoding
|
||||
- Accept-Language
|
||||
- Accept
|
||||
- Cache-Control
|
||||
- User-Agent
|
||||
|
||||
as it is assumed many requests would fail without these headers; these do not need to be configured manually.
|
||||
|
||||
Push requests are virtualized internally, so they are very lightweight.
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
push [<matcher>] [<resource>] {
|
||||
[GET|HEAD] <resource>
|
||||
headers {
|
||||
[+]<field> [<value|regexp> [<replacement>]]
|
||||
-<field>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **<resource>** is the target URI path to push. If used within the block, may optionally be preceeded by the method (GET or POST; GET is default).
|
||||
- **<headers>** manipulates the headers of the push request using the same syntax as the [`header` directive](/docs/caddyfile/directives/header). Some headers are carried over by default and do not need to be explicitly configured (see above).
|
||||
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Push any resources described by `Link` headers in the response:
|
||||
|
||||
```caddy-d
|
||||
push
|
||||
```
|
||||
|
||||
Same, but also push `/resources/style.css` for all requests:
|
||||
|
||||
```caddy-d
|
||||
push * /resources/style.css
|
||||
```
|
||||
|
||||
Push `/foo.jpg` only when `/foo.html` is requested by the client:
|
||||
|
||||
```caddy-d
|
||||
push /foo.html /foo.jpg
|
||||
```
|
52
src/docs/markdown/caddyfile/directives/redir.md
Normal file
52
src/docs/markdown/caddyfile/directives/redir.md
Normal file
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
title: redir (Caddyfile directive)
|
||||
---
|
||||
|
||||
# redir
|
||||
|
||||
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 (before [`rewrite`](/docs/caddyfile/directives/rewrite)).
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
redir [<matcher>] <to> [<code>]
|
||||
```
|
||||
|
||||
- **<to>** is the target location. Becomes the response's Location header.
|
||||
- **<code>** 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)
|
||||
- `permanent` for a permanent redirect (301)
|
||||
- `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
|
||||
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Redirect all requests to `https://example.com`:
|
||||
|
||||
```caddy-d
|
||||
redir https://example.com
|
||||
```
|
||||
|
||||
Same, but preserve the existing URI:
|
||||
|
||||
```caddy-d
|
||||
redir https://example.com{uri}
|
||||
```
|
||||
|
||||
Same, but permanent:
|
||||
|
||||
```caddy-d
|
||||
redir https://example.com{uri} permanent
|
||||
```
|
||||
|
||||
Redirect your old `/about-us` page to your new `/about` page:
|
||||
|
||||
```caddy-d
|
||||
redir /about-us /about
|
||||
```
|
29
src/docs/markdown/caddyfile/directives/request_body.md
Normal file
29
src/docs/markdown/caddyfile/directives/request_body.md
Normal file
|
@ -0,0 +1,29 @@
|
|||
---
|
||||
title: request_body (Caddyfile directive)
|
||||
---
|
||||
|
||||
# request_body
|
||||
|
||||
Manipulates or sets restrictions on the bodies of incoming requests.
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
request_body [<matcher>] {
|
||||
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.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Limit request body sizes to 10 megabytes:
|
||||
|
||||
```caddy-d
|
||||
request_body {
|
||||
max_size 10MB
|
||||
}
|
||||
```
|
43
src/docs/markdown/caddyfile/directives/request_header.md
Normal file
43
src/docs/markdown/caddyfile/directives/request_header.md
Normal file
|
@ -0,0 +1,43 @@
|
|||
---
|
||||
title: request_header (Caddyfile directive)
|
||||
---
|
||||
|
||||
# request_header
|
||||
|
||||
Manipulates HTTP header fields on the request. It can set, add, and delete header values, or perform replacements using regular expressions.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
request_header [<matcher>] [[+|-]<field> [<value>|<find>] [<replace>]]
|
||||
```
|
||||
|
||||
- **<field>** is the name of the header field. By default, will overwrite any existing field of the same name.
|
||||
|
||||
Prefix with `+` to add the field instead of overwriting (setting) the field if it already exists; header fields can appear more than once in a request.
|
||||
|
||||
Prefix with `-` to delete the field. The field may use prefix or suffix `*` wildcards to delete all matching fields.
|
||||
|
||||
- **<value>** is the header field value, if adding or setting a field.
|
||||
|
||||
- **<find>** is the substring or regular expression to search for.
|
||||
|
||||
- **<replace>** is the replacement value; required if performing a search-and-replace.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Remove the Referer header from the request:
|
||||
|
||||
```caddy-d
|
||||
request_header -Referer
|
||||
```
|
||||
|
||||
Delete all headers containing an underscore from the request:
|
||||
|
||||
```caddy-d
|
||||
request_header -*_*
|
||||
```
|
53
src/docs/markdown/caddyfile/directives/respond.md
Normal file
53
src/docs/markdown/caddyfile/directives/respond.md
Normal file
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
title: respond (Caddyfile directive)
|
||||
---
|
||||
|
||||
# respond
|
||||
|
||||
Writes a hard-coded/static response to the client.
|
||||
|
||||
If the body is non-empty, this directive sets the `Content-Type` header if it is not already set. The default value is `text/plain; utf-8` unless the body is a valid JSON object or array, in which case it is set to `application/json`. For all other types of content, set the proper Content-Type explicitly using the [`header` directive](/docs/caddyfile/directives/header).
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
respond [<matcher>] <status>|<body> [<status>] {
|
||||
body <text>
|
||||
close
|
||||
}
|
||||
```
|
||||
|
||||
- **<status>** 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.
|
||||
- **<body>** is the response body to write.
|
||||
- **body** is an alternate way to provide a body; convenient if it is multiple lines.
|
||||
- **close** will close the client's connection to the server after writing the response.
|
||||
|
||||
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">
|
||||
Responding with an error status code is different than returning an error in the handler chain, which invokes error handlers internally.
|
||||
</aside>
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Write a 200 status with an empty body to all health checks:
|
||||
|
||||
```caddy-d
|
||||
respond /health-check 200
|
||||
```
|
||||
|
||||
Write a simple response body to all requests:
|
||||
|
||||
```caddy-d
|
||||
respond "Hello, world!"
|
||||
```
|
||||
|
||||
Write an error response and close the connection:
|
||||
|
||||
```caddy-d
|
||||
respond /secret/* "Access denied" 403 {
|
||||
close
|
||||
}
|
||||
```
|
707
src/docs/markdown/caddyfile/directives/reverse_proxy.md
Normal file
707
src/docs/markdown/caddyfile/directives/reverse_proxy.md
Normal file
|
@ -0,0 +1,707 @@
|
|||
---
|
||||
title: reverse_proxy (Caddyfile directive)
|
||||
---
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
// Fix response matchers to render with the right color,
|
||||
// and link to response matchers section
|
||||
$('pre.chroma .k:contains("@")')
|
||||
.map(function(k, item) {
|
||||
let text = item.innerText.replace(/</g,'<').replace(/>/g,'>');
|
||||
let url = '#' + item.innerText.replace(/_/g, "-");
|
||||
$(item).addClass('nd').removeClass('k')
|
||||
$(item).html('<a href="#response-matcher" style="color: inherit;" title="Response matcher">' + text + '</a>');
|
||||
});
|
||||
|
||||
// Fix matcher placeholder
|
||||
$('pre.chroma .k:contains("handle_response")').first().nextAll().slice(0, 3)
|
||||
.wrapAll('<span class="nd">').parent()
|
||||
.html('<a href="#response-matcher" style="color: inherit;" title="Response matcher">[<matcher>]</a>')
|
||||
|
||||
// We'll add links to all the subdirectives if a matching anchor tag is found on the page.
|
||||
addLinksToSubdirectives();
|
||||
});
|
||||
</script>
|
||||
|
||||
# reverse_proxy
|
||||
|
||||
Proxies requests to one or more backends with configurable transport, load balancing, health checking, request manipulation, and buffering options.
|
||||
|
||||
- [Syntax](#syntax)
|
||||
- [Upstreams](#upstreams)
|
||||
- [Upstream addresses](#upstream-addresses)
|
||||
- [Dynamic upstreams](#dynamic-upstreams)
|
||||
- [SRV](#srv)
|
||||
- [A/AAAA](#aaaaa)
|
||||
- [Multi](#multi)
|
||||
- [Load balancing](#load-balancing)
|
||||
- [Active health checks](#active-health-checks)
|
||||
- [Passive health checks](#passive-health-checks)
|
||||
- [Streaming](#streaming)
|
||||
- [Headers](#headers)
|
||||
- [Rewrites](#rewrites)
|
||||
- [Transports](#transports)
|
||||
- [The `http` transport](#the-http-transport)
|
||||
- [The `fastcgi` transport](#the-fastcgi-transport)
|
||||
- [Intercepting responses](#intercepting-responses)
|
||||
- [Examples](#examples)
|
||||
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
reverse_proxy [<matcher>] [<upstreams...>] {
|
||||
# backends
|
||||
to <upstreams...>
|
||||
dynamic <module> ...
|
||||
|
||||
# load balancing
|
||||
lb_policy <name> [<options...>]
|
||||
lb_try_duration <duration>
|
||||
lb_try_interval <interval>
|
||||
|
||||
# active health checking
|
||||
health_uri <uri>
|
||||
health_port <port>
|
||||
health_interval <interval>
|
||||
health_timeout <duration>
|
||||
health_status <status>
|
||||
health_body <regexp>
|
||||
health_headers {
|
||||
<field> [<values...>]
|
||||
}
|
||||
|
||||
# passive health checking
|
||||
fail_duration <duration>
|
||||
max_fails <num>
|
||||
unhealthy_status <status>
|
||||
unhealthy_latency <duration>
|
||||
unhealthy_request_count <num>
|
||||
|
||||
# streaming
|
||||
flush_interval <duration>
|
||||
buffer_requests
|
||||
buffer_responses
|
||||
max_buffer_size <size>
|
||||
|
||||
# request/header manipulation
|
||||
trusted_proxies [private_ranges] <ranges...>
|
||||
header_up [+|-]<field> [<value|regexp> [<replacement>]]
|
||||
header_down [+|-]<field> [<value|regexp> [<replacement>]]
|
||||
method <method>
|
||||
rewrite <to>
|
||||
|
||||
# round trip
|
||||
transport <name> {
|
||||
...
|
||||
}
|
||||
|
||||
# optionally intercept responses from upstream
|
||||
@name {
|
||||
status <code...>
|
||||
header <field> [<value>]
|
||||
}
|
||||
replace_status [<matcher>] <status_code>
|
||||
handle_response [<matcher>] {
|
||||
<directives...>
|
||||
|
||||
# special directives only available in handle_response
|
||||
copy_response [<matcher>] [<status>] {
|
||||
status <status>
|
||||
}
|
||||
copy_response_headers [<matcher>] {
|
||||
include <fields...>
|
||||
exclude <fields...>
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Upstreams
|
||||
|
||||
- **<upstreams...>** is a list of upstreams (backends) to which to proxy.
|
||||
- **to** <span id="to"/> is an alternate way to specify the list of upstreams, one (or more) per line.
|
||||
- **dynamic** <span id="dynamic"/> configures a _dynamic upstreams_ module. This allows getting the list of upstreams dynamically for every request. See [dynamic upstreams](#dynamic-upstreams) below for a description of standard dynamic upstream modules. Dynamic upstreams are retrieved at every proxy loop iteration (i.e. potentially multiple times per request if load balancing retries are enabled) and will be preferred over static upstreams. If an error occurs, the proxy will fall back to using any statically-configured upstreams.
|
||||
|
||||
|
||||
#### Upstream addresses
|
||||
|
||||
Static upstream addresses can take the form of a conventional [Caddy network address](/docs/conventions#network-addresses) or a URL that contains only scheme and host/port. Valid examples:
|
||||
|
||||
- `localhost:4000`
|
||||
- `127.0.0.1:4000`
|
||||
- `http://localhost:4000`
|
||||
- `https://example.com`
|
||||
- `h2c://127.0.0.1`
|
||||
- `example.com`
|
||||
- `unix//var/php.sock`
|
||||
- `unix+h2c//var/grpc.sock`
|
||||
|
||||
Note: Schemes cannot be mixed, since they modify the common transport configuration (a TLS-enabled transport cannot carry both HTTPS and plaintext HTTP). Any explicit transport configuration will not be overwritten, and omitting schemes or using other ports will not assume a particular transport.
|
||||
|
||||
Additionally, upstream addresses cannot contain paths or query strings, as that would imply simultaneous rewriting the request while proxying, which behavior is not defined or supported. You may use the [`rewrite`](/docs/caddyfile/directives/rewrite) directive should you need this.
|
||||
|
||||
If the address is not a URL (i.e. does not have a scheme), then placeholders can be used, but this makes the upstream _dynamically static_, meaning that potentially many different backends act as a single, static upstream in terms of health checks and load balancing.
|
||||
|
||||
When proxying over HTTPS, you may need to override the `Host` header such that it matches the TLS SNI value, which is used by servers for routing and certificate selection. See the [HTTPS](#https) section below for more details.
|
||||
|
||||
|
||||
#### Dynamic upstreams
|
||||
|
||||
Caddy's reverse proxy comes standard with some dynamic upstream modules. Note that using dynamic upstreams has implications for load balancing and health checks, depending on specific policy configuration: active health checks do not run for dynamic upstreams; and load balancing and passive health checks are best served if the list of upstreams is relatively stable and consistent (especially with round-robin). Ideally, dynamic upstream modules only return healthy, usable backends.
|
||||
|
||||
|
||||
##### SRV
|
||||
|
||||
Retrieves upstreams from SRV DNS records.
|
||||
|
||||
```caddy-d
|
||||
dynamic srv [<full_name>] {
|
||||
service <service>
|
||||
proto <proto>
|
||||
name <name>
|
||||
refresh <interval>
|
||||
resolvers <ip...>
|
||||
dial_timeout <duration>
|
||||
dial_fallback_delay <duration>
|
||||
}
|
||||
```
|
||||
|
||||
- **<full_name>** is the full domain name of the record to look up (i.e. `_service._proto.name`).
|
||||
- **service** is the service component of the full name.
|
||||
- **proto** is the protocol component of the full name. Either `tcp` or `udp`.
|
||||
- **name** is the name component. Or, if `service` and `proto` are empty, the full domain name to query.
|
||||
- **refresh** is how often to refresh cached results. Default: `1m`
|
||||
- **resolvers** is the list of DNS resolvers to override system resolvers.
|
||||
- **dial_timeout** is the timeout for dialing the query.
|
||||
- **dial_fallback_delay** is how long to wait before spawning an RFC 6555 Fast Fallback connection. Default: `300ms`
|
||||
|
||||
|
||||
|
||||
##### A/AAAA
|
||||
|
||||
Retrieves upstreams from A/AAAA DNS records.
|
||||
|
||||
```caddy-d
|
||||
dynamic a [<name> <port>] {
|
||||
name <name>
|
||||
port <port>
|
||||
refresh <interval>
|
||||
resolvers <ip...>
|
||||
dial_timeout <duration>
|
||||
dial_fallback_delay <duration>
|
||||
}
|
||||
```
|
||||
|
||||
- **name** is the domain name to query.
|
||||
- **port** is the port to use for the backend.
|
||||
- **refresh** is how often to refresh cached results. Default: `1m`
|
||||
- **resolvers** is the list of DNS resolvers to override system resolvers.
|
||||
- **dial_timeout** is the timeout for dialing the query.
|
||||
- **dial_fallback_delay** is how long to wait before spawning an RFC 6555 Fast Fallback connection. Default: `300ms`
|
||||
|
||||
|
||||
##### Multi
|
||||
|
||||
Append the results of multiple dynamic upstream modules. Useful if you want redundant sources of upstreams, for example: a primary cluster of SRVs backed up by a secondary cluster of SRVs.
|
||||
|
||||
```caddy-d
|
||||
dynamic multi {
|
||||
<source> [...]
|
||||
}
|
||||
```
|
||||
|
||||
- **<source>** is the name of the module for the dynamic upstreams, followed by its configuration. More than one may be specified.
|
||||
|
||||
### Load balancing
|
||||
|
||||
Load balancing is used whenever more than one upstream is defined.
|
||||
|
||||
- **lb_policy** <span id="lb_policy"/> is the name of the load balancing policy, along with any options. Default: `random`.
|
||||
|
||||
For policies that involve hashing, the [highest-random-weight (HRW)](https://en.wikipedia.org/wiki/Rendezvous_hashing) algorithm is used to ensure that a client or request with the same hash key is mapped to the same upstream, even if the list of upstreams change.
|
||||
|
||||
- `random` randomly chooses an upstream
|
||||
|
||||
- `random_choose <n>` selects two or more upstreams randomly, then chooses one with least load (`n` is usually 2)
|
||||
|
||||
- `first` chooses the first available upstream, from the order they are defined in the config
|
||||
|
||||
- `round_robin` iterates each upstream in turn
|
||||
|
||||
- `least_conn` choose upstream with fewest number of current requests; if more than one host has the least number of requests, then one of those hosts is chosen at random
|
||||
|
||||
- `ip_hash` maps the client IP to a sticky upstream
|
||||
|
||||
- `uri_hash` maps the request URI (path and query) to a sticky upstream
|
||||
|
||||
- `header [field]` maps a request header to a sticky upstream, by hashing the header value; if the specified header field is not present, a random upstream is selected
|
||||
|
||||
- `cookie [<name> [<secret>]]` on the first request from a client (when there's no cookie), a random upstream is selected, and a `Set-Cookie` header is added to the response (default cookie name is `lb` if not specified). The cookie value is the upstream dial address of the chosen upstream, hashed with HMAC-SHA256 (using `<secret>` as the shared secret, empty string if not specified).
|
||||
|
||||
On subsequent requests where the cookie is present, the cookie value will be mapped to the same upstream if it's available; if not available or not found, a new random upstream is selected and the cookie is added to the response.
|
||||
|
||||
If you wish to use a particular upstream for debugging purposes, you may hash the upstream address with the secret, and set the cookie in your HTTP client (browser or otherwise). For example, with PHP, you could run the following to compute the cookie value, where `10.1.0.10:8080` is the address of one of your upstreams, and `secret` is your configured secret.
|
||||
```php
|
||||
echo hash_hmac('sha256', '10.1.0.10:8080', 'secret');
|
||||
// cdd96966817dd14a99f47ee17451464f29998da170814a16b483e4c1ff4c48cf
|
||||
```
|
||||
|
||||
You can set the cookie in your browser via the Javascript console, for example to set the cookie named `lb`:
|
||||
```js
|
||||
document.cookie = "lb=cdd96966817dd14a99f47ee17451464f29998da170814a16b483e4c1ff4c48cf";
|
||||
```
|
||||
|
||||
- **lb_try_duration** <span id="lb_try_duration"/> is a [duration value](/docs/conventions#durations) that defines how long to try selecting available backends for each request if the next available host is down. By default, this retry is disabled. Clients will wait for up to this long while the load balancer tries to find an available upstream host. A reasonable starting point might be `5s` since the HTTP transport's default dial timeout is `3s`, so that should allow for at least one retry if the first selected upstream cannot be reached; but feel free to experiment to find the right balance for your usecase.
|
||||
|
||||
- **lb_try_interval** <span id="lb_try_interval"/> is a [duration value](/docs/conventions#durations) that defines how long to wait between selecting the next host from the pool. Default is `250ms`. Only relevant when a request to an upstream host fails. Be aware that setting this to 0 with a non-zero `lb_try_duration` can cause the CPU to spin if all backends are down and latency is very low.
|
||||
|
||||
|
||||
|
||||
#### Active health checks
|
||||
|
||||
Active health checks perform health checking in the background on a timer:
|
||||
|
||||
- **health_uri** <span id="health_uri"/> is the URI path (and optional query) for active health checks.
|
||||
|
||||
- **health_port** <span id="health_port"/> is the port to use for active health checks, if different from the upstream's port.
|
||||
|
||||
- **health_interval** <span id="health_interval"/> is a [duration value](/docs/conventions#durations) that defines how often to perform active health checks.
|
||||
|
||||
- **health_timeout** <span id="health_timeout"/> is a [duration value](/docs/conventions#durations) that defines how long to wait for a reply before marking the backend as down.
|
||||
|
||||
- **health_status** <span id="health_status"/> is the HTTP status code to expect from a healthy backend. Can be a 3-digit status code, or a status code class ending in `xx`. For example: `200` (which is the default), or `2xx`.
|
||||
|
||||
- **health_body** <span id="health_body"/> is a substring or regular expression to match on the response body of an active health check. If the backend does not return a matching body, it will be marked as down.
|
||||
|
||||
- **health_headers** <span id="health_headers"/> allows specifying headers to set on the active health check requests. This is useful if you need to change the `Host` header, or if you need to provide some authentication to your backend as part of your health checks.
|
||||
|
||||
|
||||
|
||||
#### Passive health checks
|
||||
|
||||
Passive health checks happen inline with actual proxied requests:
|
||||
|
||||
- **fail_duration** <span id="fail_duration"/> is a [duration value](/docs/conventions#durations) that defines how long to remember a failed request. A duration > `0` enables passive health checking; the default is `0` (off). A reasonable starting point might be `30s` to balance error rates with responsiveness when bringing an unhealthy upstream back online; but feel free to experiment to find the right balance for your usecase.
|
||||
|
||||
- **max_fails** <span id="max_fails"/> is the maximum number of failed requests within `fail_duration` that are needed before considering a backend to be down; must be >= `1`; default is `1`.
|
||||
|
||||
- **unhealthy_status** <span id="unhealthy_status"/> counts a request as failed if the response comes back with one of these status codes. Can be a 3-digit status code or a status code class ending in `xx`, for example: `404` or `5xx`.
|
||||
|
||||
- **unhealthy_latency** <span id="unhealthy_latency"/> is a [duration value](/docs/conventions#durations) that counts a request as failed if it takes this long to get a response.
|
||||
|
||||
- **unhealthy_request_count** <span id="unhealthy_request_count"/> is the permissible number of simultaneous requests to a backend before marking it as down. In other words, if a particular backend is currently handling this many requests, then it's considered "overloaded" and other backends will be preferred instead.
|
||||
|
||||
This should be a reasonably large number; configuring this means that the proxy will have a limit of `unhealthy_request_count × upstreams_count` total simultaneous requests, and any requests after that point will result in an error due to no upstreams being available.
|
||||
|
||||
|
||||
|
||||
### Streaming
|
||||
|
||||
By default, the proxy partially buffers the response for wire efficiency:
|
||||
|
||||
- **flush_interval** <span id="flush_interval"/> is a [duration value](/docs/conventions#durations) that adjusts how often Caddy should flush the response buffer to the client. By default, no periodic flushing is done. A negative value (typically -1) suggests "low-latency mode" which disables response buffering completely and flushes immediately after each write to the client, and does not cancel the request to the backend even if the client disconnects early. This option is ignored and responses are flushed immediately to the client if one of the following applies from the response:
|
||||
- `Content-Type: text/event-stream`
|
||||
- `Content-Length` is unknown
|
||||
- HTTP/2 on both sides of the proxy, `Content-Length` is unknown, and `Accept-Encoding` is either not set or is "identity"
|
||||
|
||||
- **buffer_requests** <span id="buffer_requests"/> will cause the proxy to read the entire request body into a buffer before sending it upstream. This is very inefficient and should only be done if the upstream requires reading request bodies without delay (which is something the upstream application should fix).
|
||||
|
||||
- **buffer_responses** <span id="buffer_responses"/> will cause the entire response body to be read and buffered in memory before being proxied to the client. This should be avoided if at all possible for performance reasons, but could be useful if the backend has tighter memory constraints.
|
||||
|
||||
- **max_buffer_size** <span id="max_buffer_size"/> if body buffering is enabled, this sets the maximum size of the buffers used for the requests and responses. This accepts all size formats supported by [go-humanize](https://github.com/dustin/go-humanize/blob/master/bytes.go).
|
||||
|
||||
|
||||
|
||||
### Headers
|
||||
|
||||
The proxy can **manipulate headers** between itself and the backend:
|
||||
|
||||
- **header_up** <span id="header_up"/> sets, adds (with the `+` prefix), deletes (with the `-` prefix), or performs a replacement (by using two arguments, a search and replacement) in a request header going upstream to the backend.
|
||||
|
||||
- **header_down** <span id="header_down"/> sets, adds (with the `+` prefix), deletes (with the `-` prefix), or performs a replacement (by using two arguments, a search and replacement) in a response header coming downstream from the backend.
|
||||
|
||||
For example, to set a request header, overwriting any existing values:
|
||||
|
||||
```caddy-d
|
||||
header_up Some-Header "the value"
|
||||
```
|
||||
|
||||
To add a response header; note that there can be multiple values for a header field:
|
||||
|
||||
```caddy-d
|
||||
header_down +Some-Header "first value"
|
||||
header_down +Some-Header "second value"
|
||||
```
|
||||
|
||||
To delete a request header, preventing it from reaching the backend:
|
||||
|
||||
```caddy-d
|
||||
header_up -Some-Header
|
||||
```
|
||||
|
||||
To delete all matching request, using a suffix match:
|
||||
|
||||
```caddy-d
|
||||
header_up -Some-*
|
||||
```
|
||||
|
||||
To perform a regular expression replacement on a request header:
|
||||
|
||||
```caddy-d
|
||||
header_up Some-Header "^prefix-([A-Za-z0-9]*)$" "replaced-$1-suffix"
|
||||
```
|
||||
|
||||
The regular expression language used is RE2, included in Go. See the [RE2 syntax reference](https://github.com/google/re2/wiki/Syntax) and the [Go regexp syntax overview](https://pkg.go.dev/regexp/syntax). The replacement string is [expanded](https://pkg.go.dev/regexp#Regexp.Expand), allowing use of captured values, for example `$1` being the first capture group.
|
||||
|
||||
|
||||
#### Defaults
|
||||
|
||||
By default, Caddy passes thru incoming headers—including `Host`—to the backend without modifications, with three exceptions:
|
||||
|
||||
- It sets or augments the [`X-Forwarded-For`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) header field.
|
||||
- It sets the [`X-Forwarded-Proto`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto) header field.
|
||||
- It sets the [`X-Forwarded-Host`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host) header field.
|
||||
|
||||
<span id="trusted_proxies"/> For these `X-Forwarded-*` headers, by default, Caddy will ignore their values from incoming requests, to prevent spoofing. If Caddy is not the first server being connected to by your clients (for example when a CDN is in front of Caddy), you may configure `trusted_proxies` with a list of IP ranges (CIDRs) from which incoming requests are trusted to have sent good values for these headers. As a shortcut, `private_ranges` may be configured to trust all private IP ranges.
|
||||
|
||||
```caddy-d
|
||||
trusted_proxies private_ranges
|
||||
```
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
If you're using Cloudflare in front of Caddy, be aware that you may be vulnerable to spoofing of the `X-Forwarded-For` header. Our friends at [Authelia](https://www.authelia.com) have documented a [workaround](https://www.authelia.com/integration/proxies/fowarded-headers/) to configure Cloudflare to ignore incoming values for this header.
|
||||
|
||||
</aside>
|
||||
|
||||
Additionally, when using the [`http` transport](#the-http-transport), the `Accept-Encoding: gzip` header will be set, if it is missing in the request from the client. This behavior can be disabled with [`compression off`](#compression) on the transport.
|
||||
|
||||
#### HTTPS
|
||||
|
||||
Since (most) headers retain their original value when being proxied, it is often necessary to override the `Host` header with the configured upstream address when proxying to HTTPS, such that the `Host` header matches the TLS ServerName value. For example:
|
||||
|
||||
```caddy-d
|
||||
reverse_proxy https://example.com {
|
||||
header_up Host {upstream_hostport}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Rewrites
|
||||
|
||||
By default, Caddy performs the upstream request with the same HTTP method and URI as the incoming request, unless a rewrite was performed in the middleware chain before it reaches `reverse_proxy`.
|
||||
|
||||
Before proxying it, the request is cloned; this ensures that any modifications done to the request during the handler do not leak to other handlers. This is useful in situations where the handling needs to continue after the proxy.
|
||||
|
||||
In addition to [header manipulations](#headers), the request's method and URI may be changed before it is sent to the upstream:
|
||||
|
||||
- **method** <span id="method"/> changes the HTTP method of the cloned request. If the method is changed to `GET` or `HEAD`, then the incoming request's body will _not_ be sent upstream by this handler. This is useful if you wish to allow a different handler to consume the request body.
|
||||
- **rewrite** <span id="rewrite"/> changes the URI (path and query) of the cloned request. This is similar to the [`rewrite` directive](/docs/caddyfile/directives/rewrite), except that it doesn't persist the rewrite past the scope of this handler.
|
||||
|
||||
These rewrites are often useful for a pattern like "pre-check requests", where a request is sent to another server to help make a decision on how to continue handling the current request.
|
||||
|
||||
For example, the request could be sent to an authentication gateway to decide whether the request was from an authenticated user (e.g. the request has a session cookie) and should continue, or should instead be redirected to a login page. For this pattern, Caddy provides a shortcut directive [`forward_auth`](/docs/caddyfile/directives/forward_auth) to skip most of the config boilerplate.
|
||||
|
||||
|
||||
|
||||
|
||||
### Transports
|
||||
|
||||
Caddy's proxy **transport** is pluggable:
|
||||
|
||||
- **transport** <span id="transport"/> defines how to communicate with the backend. Default is `http`.
|
||||
|
||||
|
||||
#### The `http` transport
|
||||
|
||||
```caddy-d
|
||||
transport http {
|
||||
read_buffer <size>
|
||||
write_buffer <size>
|
||||
max_response_header <size>
|
||||
dial_timeout <duration>
|
||||
dial_fallback_delay <duration>
|
||||
response_header_timeout <duration>
|
||||
expect_continue_timeout <duration>
|
||||
resolvers <ip...>
|
||||
tls
|
||||
tls_client_auth <automate_name> | <cert_file> <key_file>
|
||||
tls_insecure_skip_verify
|
||||
tls_timeout <duration>
|
||||
tls_trusted_ca_certs <pem_files...>
|
||||
tls_server_name <server_name>
|
||||
tls_renegotiation <level>
|
||||
tls_except_ports <ports...>
|
||||
keepalive [off|<duration>]
|
||||
keepalive_interval <interval>
|
||||
keepalive_idle_conns <max_count>
|
||||
keepalive_idle_conns_per_host <count>
|
||||
versions <versions...>
|
||||
compression off
|
||||
max_conns_per_host <count>
|
||||
}
|
||||
```
|
||||
|
||||
- **read_buffer** <span id="read_buffer"/> is the size of the read buffer in bytes. It accepts all formats supported by [go-humanize](https://github.com/dustin/go-humanize/blob/master/bytes.go). Default: `4KiB`.
|
||||
|
||||
- **write_buffer** <span id="write_buffer"/> is the size of the write buffer in bytes. It accepts all formats supported by [go-humanize](https://github.com/dustin/go-humanize/blob/master/bytes.go). Default: `4KiB`.
|
||||
|
||||
- **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`.
|
||||
|
||||
- **dial_timeout** <span id="dial_timeout"/> is the maximum [duration](/docs/conventions#durations) to wait when connecting to the upstream socket. Default: No timeout.
|
||||
|
||||
- **dial_fallback_delay** <span id="dial_fallback_delay"/> is the maximum [duration](/docs/conventions#durations) to wait before spawning an RFC 6555 Fast Fallback connection. A negative value disables this. Default: `300ms`.
|
||||
|
||||
- **response_header_timeout** <span id="response_header_timeout"/> is the maximum [duration](/docs/conventions#durations) to wait for reading response headers from the upstream. Default: No timeout.
|
||||
|
||||
- **expect_continue_timeout** <span id="expect_continue_timeout"/> is the maximum [duration](/docs/conventions#durations) to wait for the upstreams's first response headers after fully writing the request headers if the request has the header `Expect: 100-continue`. Default: No timeout.
|
||||
|
||||
- **read_timeout** <span id="read_timeout"/> is the maximum [duration](/docs/conventions#durations) to wait for the next read from the backend. Default: No timeout.
|
||||
|
||||
- **write_timeout** <span id="write_timeout"/> is the maximum [duration](/docs/conventions#durations) to wait for the next writes to the backend. Default: No timeout.
|
||||
|
||||
- **resolvers** <span id="resolvers"/> is a list of DNS resolvers to override system resolvers.
|
||||
|
||||
- **tls** <span id="tls"/> uses HTTPS with the backend. This will be enabled automatically if you specify backends using the `https://` scheme or port `:443`, or if any of the below `tls_*` options are configured.
|
||||
|
||||
- **tls_client_auth** <span id="tls_client_auth"/> enables TLS client authentication one of two ways: (1) by specifying a domain name for which Caddy should obtain a certificate and keep it renewed, or (2) by specifying a certificate and key file to present for TLS client authentication with the backend.
|
||||
|
||||
- **tls_insecure_skip_verify** <span id="tls_insecure_skip_verify"/> turns off TLS handshake verification, making the connection insecure and vulnerable to man-in-the-middle attacks. _Do not use in production._
|
||||
|
||||
- **tls_timeout** <span id="tls_timeout"/> is the maximum [duration](/docs/conventions#durations) to wait for the TLS handshake to complete. Default: No timeout.
|
||||
|
||||
- **tls_trusted_ca_certs** <span id="tls_trusted_ca_certs"/> is a list of PEM files that specify CA public keys to trust when connecting to the backend.
|
||||
|
||||
- **tls_server_name** <span id="tls_server_name"/> sets the server name used when verifying the certificate received in the TLS handshake. By default, this will use the upstream address' host part.
|
||||
|
||||
You only need to override this if your upstream address does not match the certificate the upstream is likely to use. For example if the upstream address is an IP address, then you would need to configure this to the hostname being served by the upstream server.
|
||||
|
||||
A request placeholder may be used, in which case a clone of the HTTP transport config will be used on every request, which may incur a performance penalty.
|
||||
|
||||
- **tls_renegotiation** <span id="tls_renegotiation"/> sets the TLS renegotiation level. TLS renegotiation is the act of performing subsequent handshakes after the first. The level may be one of:
|
||||
- `never` (the default) disables renegotiation.
|
||||
- `once` allows a remote server to request renegotiation once per connection.
|
||||
- `freely` allows a remote server to repeatedly request renegotiation.
|
||||
|
||||
- **tls_except_ports** <span id="tls_except_ports"/> when TLS is enabled, if the upstream target uses one of the given ports, TLS will be disabled for those connections. This may be useful when configuring dynamic upstreams, where some upstreams expect HTTP and others expect HTTPS requests.
|
||||
|
||||
- **keepalive** <span id="keepalive"/> is either `off` or a [duration value](/docs/conventions#durations) that specifies how long to keep connections open (timeout). Default: `2m`.
|
||||
|
||||
- **keepalive_interval** <span id="keepalive"/> is the [duration](/docs/conventions#durations) between liveness probes. Default: `30s`.
|
||||
|
||||
- **keepalive_idle_conns** <span id="keepalive_idle_conns"/> defines the maximum number of connections to keep alive. Default: No limit.
|
||||
|
||||
- **keepalive_idle_conns_per_host** <span id="keepalive_idle_conns_per_host"/> if non-zero, controls the maximum idle (keep-alive) connections to keep per-host. Default: `32`.
|
||||
|
||||
- **versions** <span id="versions"/> allows customizing which versions of HTTP to support. As a special case, "h2c" is a valid value which will enable cleartext HTTP/2 connections to the upstream (however, this is a non-standard feature that does not use Go's default HTTP transport, so it is exclusive of other features; subject to change or removal). Default: `1.1 2`, or if scheme is `h2c://`, `h2c 2`
|
||||
|
||||
- **compression** <span id="compression"/> can be used to disable compression to the backend by setting it to `off`.
|
||||
|
||||
- **max_conns_per_host** <span id="max_conns_per_host"/> optionally limits the total number of connections per host, including connections in the dialing, active, and idle states. Default: No limit.
|
||||
|
||||
|
||||
|
||||
#### The `fastcgi` transport
|
||||
|
||||
```caddy-d
|
||||
transport fastcgi {
|
||||
root <path>
|
||||
split <at>
|
||||
env <key> <value>
|
||||
resolve_root_symlink
|
||||
dial_timeout <duration>
|
||||
read_timeout <duration>
|
||||
write_timeout <duration>
|
||||
}
|
||||
```
|
||||
|
||||
- **root** <span id="root"/> is the root of the site. Default: `{http.vars.root}` or current working directory.
|
||||
|
||||
- **split** <span id="split"/> is where to split the path to get PATH_INFO at the end of the URI.
|
||||
|
||||
- **env** <span id="env"/> sets an extra environment variable to the given value. Can be specified more than once for multiple environment variables.
|
||||
|
||||
- **resolve_root_symlink** <span id="resolve_root_symlink"/> enables resolving the `root` directory to its actual value by evaluating a symbolic link, if one exists.
|
||||
|
||||
- **dial_timeout** <span id="dial_timeout"/> is how long to wait when connecting to the upstream socket. Accepts [duration values](/docs/conventions#durations). Default: `3s`.
|
||||
|
||||
- **read_timeout** <span id="read_timeout"/> is how long to wait when reading from the FastCGI server. Accepts [duration values](/docs/conventions#durations). Default: no timeout.
|
||||
|
||||
- **write_timeout** <span id="write_timeout"/> is how long to wait when sending to the FastCGI server. Accepts [duration values](/docs/conventions#durations). Default: no timeout.
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
If you're trying to serve a modern PHP application, you may be looking for the [`php_fastcgi` directive](/docs/caddyfile/directives/php_fastcgi), which is a shortcut for a proxy using the `fastcgi` directive, with the necessary rewrites for using `index.php` as the routing entrypoint.
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
|
||||
### Intercepting responses
|
||||
|
||||
The reverse proxy can be configured to intercept responses from the backend. To facilitate this, response matchers can be defined (similar to the syntax for request matchers) and the first matching `handle_response` route will be invoked.
|
||||
|
||||
When a response handler is invoked, the response from the backend is not written to the client, and the configured `handle_response` route will be executed instead, and it is up to that route to write a response. If the route does _not_ write a response, then request handling will continue with any handlers that are ordered after this `reverse_proxy`.
|
||||
|
||||
- **@name** is the name of a [response matcher](#response-matcher). As long as each response matcher has a unique name, multiple matchers can be defined. A response can be matched on the status code and presence or value of a response header.
|
||||
- **replace_status** <span id="replace_status"/> simply changes the status code of response when matched by the given matcher.
|
||||
- **handle_response** <span id="handle_response"/> defines the route to execute when matched by the given matcher (or, if a matcher is omitted, all responses). The first matching block will be applied. Inside a `handle_response` block, any other [directives](/docs/caddyfile/directives) can be used.
|
||||
|
||||
Additionally, inside `handle_response`, two special handler directives may be used:
|
||||
|
||||
- **copy_response** <span id="copy_response"/> copies the response body received from the backend back to the client. Optionally allows changing the status code of the response while doing so. This directive is [ordered before `respond`](/docs/caddyfile/directives#directive-order).
|
||||
- **copy_response_headers** <span id="copy_response_headers"/> copies the response headers from the backend to the client, optionally including _OR_ excluding a list of headers fields (cannot specify both `include` and `exclude`). This directive is [ordered after `header`](/docs/caddyfile/directives#directive-order).
|
||||
|
||||
Three placeholders will be made available within the `handle_response` routes:
|
||||
|
||||
- `{rp.status_code}` The status code from the backend's response.
|
||||
- `{rp.status_text}` The status text from the backend's response.
|
||||
- `{rp.header.*}` The headers from the backend's response.
|
||||
|
||||
|
||||
#### Response matcher
|
||||
|
||||
**Response matchers** can be used to filter (or classify) responses by specific criteria.
|
||||
|
||||
##### status
|
||||
|
||||
```caddy-d
|
||||
status <code...>
|
||||
```
|
||||
|
||||
By HTTP status code.
|
||||
|
||||
- **<code...>** 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
|
||||
|
||||
See the [`header`](/docs/caddyfile/matchers#header) request matcher for the supported syntax.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Reverse proxy all requests to a local backend:
|
||||
|
||||
```caddy-d
|
||||
reverse_proxy localhost:9005
|
||||
```
|
||||
|
||||
|
||||
Load-balance all requests between 3 backends:
|
||||
|
||||
```caddy-d
|
||||
reverse_proxy node1:80 node2:80 node3:80
|
||||
```
|
||||
|
||||
|
||||
Same, but only requests within `/api`, and with header affinity:
|
||||
|
||||
```caddy-d
|
||||
reverse_proxy /api/* node1:80 node2:80 node3:80 {
|
||||
lb_policy header X-My-Header
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Configure some transport options:
|
||||
|
||||
```caddy-d
|
||||
reverse_proxy localhost:8080 {
|
||||
transport http {
|
||||
dial_timeout 2s
|
||||
response_header_timeout 30s
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Reverse proxy to an HTTPS endpoint:
|
||||
|
||||
```caddy-d
|
||||
reverse_proxy https://example.com {
|
||||
header_up Host {upstream_hostport}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Strip a path prefix before proxying:
|
||||
|
||||
```caddy-d
|
||||
handle_path /prefix/* {
|
||||
reverse_proxy localhost:9000
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Replace a path prefix before proxying:
|
||||
|
||||
```caddy-d
|
||||
handle_path /old-prefix/* {
|
||||
rewrite * /new-prefix{path}
|
||||
reverse_proxy localhost:9000
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
When Caddy is behind another proxy or load balancer whose IP is `123.123.123.123`, which may set `X-Forwarded-*` headers to identify details about the original client request, that downstream proxy must be listed as trusted, otherwise Caddy will ignore those incoming headers:
|
||||
|
||||
```caddy-d
|
||||
reverse_proxy localhost:8080 {
|
||||
trusted_proxies 123.123.123.123
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
X-Accel-Redirect support, i.e. serving static files as requested by the proxy upstream:
|
||||
|
||||
```caddy-d
|
||||
reverse_proxy localhost:8080 {
|
||||
@accel header X-Accel-Redirect *
|
||||
handle_response @accel {
|
||||
root * /path/to/private/files
|
||||
rewrite * {rp.header.X-Accel-Redirect}
|
||||
file_server
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Custom error page for errors from upstream:
|
||||
|
||||
```caddy-d
|
||||
reverse_proxy localhost:8080 {
|
||||
@error status 500 503
|
||||
handle_response @error {
|
||||
root * /path/to/error/pages
|
||||
rewrite * /{rp.status_code}.html
|
||||
file_server
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Get backends dynamically from A/AAAA record DNS queries:
|
||||
|
||||
```caddy-d
|
||||
reverse_proxy {
|
||||
dynamic a example.com 9000
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Get backends dynamically from SRV record DNS queries:
|
||||
|
||||
```caddy-d
|
||||
reverse_proxy {
|
||||
dynamic srv _api._tcp.example.com
|
||||
}
|
||||
```
|
55
src/docs/markdown/caddyfile/directives/rewrite.md
Normal file
55
src/docs/markdown/caddyfile/directives/rewrite.md
Normal file
|
@ -0,0 +1,55 @@
|
|||
---
|
||||
title: rewrite (Caddyfile directive)
|
||||
---
|
||||
|
||||
# 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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
rewrite [<matcher>] <to>
|
||||
```
|
||||
|
||||
- **<to>** 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
|
||||
|
||||
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).
|
||||
- [`try_files`](try_files) rewrites the request based on the existence of files.
|
53
src/docs/markdown/caddyfile/directives/root.md
Normal file
53
src/docs/markdown/caddyfile/directives/root.md
Normal file
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
title: root (Caddyfile directive)
|
||||
---
|
||||
|
||||
# root
|
||||
|
||||
Sets the root path of the site, used by various matchers and directives that access the file system. If unset, the default site root is the current working directory.
|
||||
|
||||
Specifically, this directive sets the `{http.vars.root}` placeholder. 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).
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
root [<matcher>] <path>
|
||||
```
|
||||
|
||||
- **<path>** is the path to use for the site root.
|
||||
|
||||
Note that the `<path>` argument could be confused by the parser as a [matcher token](/docs/caddyfile/matchers#syntax) if the it begins with `/`. To disambiguate, specify a wildcard matcher token (`*`). See examples below.
|
||||
|
||||
## Examples
|
||||
|
||||
Set the site root to `/home/user/public_html` for all requests:
|
||||
|
||||
(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
|
||||
root * /home/user/public_html
|
||||
```
|
||||
|
||||
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.)
|
||||
|
||||
```caddy-d
|
||||
root public_html
|
||||
```
|
||||
|
||||
Change the site root only for requests in `/foo/*`:
|
||||
|
||||
```caddy-d
|
||||
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:
|
||||
|
||||
```caddy-d
|
||||
root * /home/user/public_html
|
||||
file_server
|
||||
```
|
86
src/docs/markdown/caddyfile/directives/route.md
Normal file
86
src/docs/markdown/caddyfile/directives/route.md
Normal file
|
@ -0,0 +1,86 @@
|
|||
---
|
||||
title: route (Caddyfile directive)
|
||||
---
|
||||
|
||||
# route
|
||||
|
||||
Evaluates a group of directives literally and as a single unit.
|
||||
|
||||
Directives contained in a route block will not be reordered internally. Only HTTP handler directives (directives which add handlers or middleware to the chain) can be used in a route block.
|
||||
|
||||
This directive is a special case in that its subdirectives are also regular directives.
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
route [<matcher>] {
|
||||
<directives...>
|
||||
}
|
||||
```
|
||||
|
||||
- **<directives...>** is a list of directives or directive blocks, one per line, just like outside of a route block; except these directives will not be reordered. Only HTTP handler directives can be used.
|
||||
|
||||
|
||||
|
||||
## Utility
|
||||
|
||||
The `route` directive is helpful in certain advanced use cases or edge cases to take absolute control over parts of the HTTP handler chain.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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!):
|
||||
|
||||
```caddy
|
||||
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
|
||||
redir https://anothersite.com{uri}
|
||||
}
|
||||
```
|
||||
|
||||
<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.
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
And now `file_server` will be chained in before `redir` because the order is taken literally.
|
||||
|
||||
## 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:
|
||||
|
||||
- [`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_errors`](handle_errors) is like `handle`, but is only invoked when Caddy encounters an error during request handling.
|
||||
|
||||
## Examples
|
||||
|
||||
Strip `/api` prefix from request path just before proxying all API requests to a backend:
|
||||
|
||||
```caddy-d
|
||||
route /api/* {
|
||||
uri strip_prefix /api
|
||||
reverse_proxy localhost:9000
|
||||
}
|
||||
```
|
33
src/docs/markdown/caddyfile/directives/templates.md
Normal file
33
src/docs/markdown/caddyfile/directives/templates.md
Normal file
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
title: templates (Caddyfile directive)
|
||||
---
|
||||
|
||||
# templates
|
||||
|
||||
Executes the response body as a [template](/docs/modules/http.handlers.templates) document. Templates provide functional primitives for making simple dynamic pages. Features include HTTP subrequests, HTML file includes, Markdown rendering, JSON parsing, basic data structures, randomness, time, and more.
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
templates [<matcher>] {
|
||||
mime <types...>
|
||||
between <open_delim> <close_delim>
|
||||
root <path>
|
||||
}
|
||||
```
|
||||
|
||||
- **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`.
|
||||
- **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.
|
||||
- **root** is the site root, when using functions that access the file system.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Enable templates on all requests:
|
||||
|
||||
```caddy-d
|
||||
templates
|
||||
```
|
||||
|
||||
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).
|
291
src/docs/markdown/caddyfile/directives/tls.md
Normal file
291
src/docs/markdown/caddyfile/directives/tls.md
Normal file
|
@ -0,0 +1,291 @@
|
|||
---
|
||||
title: tls (Caddyfile directive)
|
||||
---
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
// We'll add links to all the subdirectives if a matching anchor tag is found on the page.
|
||||
addLinksToSubdirectives();
|
||||
});
|
||||
</script>
|
||||
|
||||
# tls
|
||||
|
||||
Configures TLS for the site.
|
||||
|
||||
**Caddy's default TLS settings are secure. Only change these settings if you have a good reason and understand the implications.** The most common use of this directive will be to specify an ACME account email address, change the ACME CA endpoint, or to provide your own certificates.
|
||||
|
||||
Compatibility note: Due to its sensitive nature as a security protocol, deliberate adjustments to TLS defaults may be made in new minor or patch releases. Old or broken TLS versions, ciphers, features, etc. may be removed at any time. If your deployment is extremely sensitive to changes, you should explicitly specify those values which must remain constant, and be vigilant about upgrades. In almost every case, we recommend using the default settings.
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
tls [internal|<email>] | [<cert_file> <key_file>] {
|
||||
protocols <min> [<max>]
|
||||
ciphers <cipher_suites...>
|
||||
curves <curves...>
|
||||
alpn <values...>
|
||||
load <paths...>
|
||||
ca <ca_dir_url>
|
||||
ca_root <pem_file>
|
||||
key_type ed25519|p256|p384|rsa2048|rsa4096
|
||||
dns <provider_name> [<params...>]
|
||||
dns_challenge_override_domain <domain>
|
||||
resolvers <dns_servers...>
|
||||
eab <key_id> <mac_key>
|
||||
on_demand
|
||||
client_auth {
|
||||
mode [request|require|verify_if_given|require_and_verify]
|
||||
trusted_ca_cert <base64_der>
|
||||
trusted_ca_cert_file <filename>
|
||||
trusted_leaf_cert <base64_der>
|
||||
trusted_leaf_cert_file <filename>
|
||||
}
|
||||
issuer <issuer_name> [<params...>]
|
||||
get_certificate <manager_name> [<params...>]
|
||||
}
|
||||
```
|
||||
|
||||
- **internal** means to use Caddy's internal, locally-trusted CA to produce certificates for this site. To further configure the [`internal`](#internal) issuer, use the [`issuer`](#issuer) subdirective.
|
||||
- **<email>** is the email address to use for the ACME account managing the site's certificates.
|
||||
- **<cert_file>** and **<key_file>** are the paths to the certificate and private key PEM files. Specifying just one is invalid.
|
||||
- **protocols** <span id="protocols"/> specifies the minimum and maximum protocol versions. Default min: `tls1.2`. Default max: `tls1.3`
|
||||
- **ciphers** <span id="ciphers"/> specifies the list of cipher suite names in descending preference order. It is recommended to not change these unless you know what you're doing. Note that cipher suites are not customizable for TLS 1.3; and not all TLS 1.2 ciphers are enabled by default. The supported names are (in no particular order here):
|
||||
- TLS_RSA_WITH_3DES_EDE_CBC_SHA
|
||||
- TLS_RSA_WITH_AES_128_CBC_SHA
|
||||
- TLS_RSA_WITH_AES_256_CBC_SHA
|
||||
- TLS_RSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||
- TLS_AES_128_GCM_SHA256
|
||||
- TLS_AES_256_GCM_SHA384
|
||||
- TLS_CHACHA20_POLY1305_SHA256
|
||||
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
|
||||
- TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
|
||||
- TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
|
||||
- TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
|
||||
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
||||
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
|
||||
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
|
||||
- **curves** <span id="curves"/> specifies the list of EC curves to support. It is recommended to not change these. Supported values are:
|
||||
- x25519
|
||||
- secp256r1
|
||||
- secp384r1
|
||||
- secp521r1
|
||||
- **alpn** <span id="alpn"/> is the list of values to advertise in the ALPN extension of the TLS handshake.
|
||||
- **load** <span id="load"/> specifies a list of folders from which to load PEM files that are certificate+key bundles.
|
||||
- **ca** <span id="ca"/> changes the ACME CA endpoint. This is most often used to set [Let's Encrypt's staging endpoint](https://letsencrypt.org/docs/staging-environment/) when testing, or an internal ACME server. (To change this value for the whole Caddyfile, use the `acme_ca` [global option](/docs/caddyfile/options) instead.)
|
||||
- **ca_root** <span id="ca_root"/> specifies a PEM file that contains a trusted root certificate for the ACME CA endpoint, if not in the system trust store.
|
||||
- **key_type** <span id="key_type"/> is the type of key to use when generating CSRs. Only set this if you have a specific requirement.
|
||||
- **dns** <span id="dns"/> enables the [DNS challenge](/docs/automatic-https#dns-challenge) using the specified provider plugin, which must be plugged in from one of the [`caddy-dns`](https://github.com/caddy-dns) repositories. Each provider plugin may have their own syntax following their name; refer to their docs for details. Maintaining support for each DNS provider is a community effort. [Learn how to enable the DNS challenge for your provider at our wiki.](https://caddy.community/t/how-to-use-dns-provider-modules-in-caddy-2/8148)
|
||||
- **dns_challenge_override_domain** <span id="dns_challenge_override_domain"/> overrides the domain to use for the DNS challenge. This is to delegate the challenge to a different domain, e.g. one whose DNS provider has a [`caddy-dns`](https://github.com/caddy-dns) plugin.
|
||||
- **resolvers** <span id="resolvers"/> customizes the DNS resolvers used when performing the DNS challenge; these take precedence over system resolvers or any default ones. If set here, the resolvers will propagate to all configured certificate issuers.
|
||||
- **eab** <span id="eab"/> configures ACME external account binding (EAB) for this site, using the key ID and MAC key provided by your CA.
|
||||
- **on_demand** <span id="on_demand"/> enables [on-demand TLS](/docs/automatic-https#on-demand-tls) for the hostnames given in the site block's address(es). **Security warning:** Doing so in production is insecure unless you also configure the [`on_demand_tls` global option](https://caddyserver.com/docs/caddyfile/options#on-demand-tls) to mitigate abuse.
|
||||
- **client_auth** <span id="client_auth"/> enables and configures TLS client authentication:
|
||||
- **mode** <span id="mode"/> is the mode for authenticating the client. Allowed values are:
|
||||
|
||||
| Mode | Description |
|
||||
|--------------------|------------------------------------------------------------------------------------------|
|
||||
| request | Ask clients for a certificate, but allow even if there isn't one; do not verify it |
|
||||
| require | Require clients to present a certificate, but do not verify it |
|
||||
| verify_if_given | Ask clients for a certificate; allow even if there isn't one, but verify it if there is |
|
||||
| require_and_verify | Require clients to present a valid certificate that is verified |
|
||||
|
||||
Default: `require_and_verify` if any `trusted_ca_cert` or `trusted_leaf_cert` are provided; otherwise, `require`.
|
||||
|
||||
- **trusted_ca_cert** <span id="trusted_ca_cert"/> is a base64 DER-encoded CA certificate against which to validate client certificates.
|
||||
- **trusted_ca_cert_file** <span id="trusted_ca_cert_file"/> is a path to a PEM CA certificate file against which to validate client certificates.
|
||||
- **trusted_leaf_cert** <span id="trusted_leaf_cert"/> is a base64 DER-encoded client leaf certificate to accept.
|
||||
- **trusted_leaf_cert_file** <span id="trusted_leaf_cert_file"/> is a path to a PEM CA certificate file against which to validate client certificates.
|
||||
|
||||
Multiple `trusted_*` directives may be used to specify multiple CA or leaf certificates. Client certificates which are not listed as one of the leaf certificates or signed by any of the specified CAs will be rejected according to the **mode**.
|
||||
|
||||
- **issuer** <span id="issuer"/> configures a custom certificate issuer, or a source from which to obtain certificates. Which issuer is used and the options that follow in this segment depend on the issuer modules that are available (see below for the standard issuers; plugins may add others). Some of the other subdirectives such as `ca` and `dns` are actually shortcuts for configuring the `acme` issuer (and this subdirective was added later), so specifying this directive and some of the others is confusing and thus prohibited. This subdirective can be specified multiple times to configure multiple, redundant issuers; if one fails to issue a cert, the next one will be tried.
|
||||
- **get_certificate** <span id="get_certificate"/> enables getting certificates from a _manager module_ at handshake-time. [See below for standard certificate manager modules.](#certificate-managers)
|
||||
|
||||
### Issuers
|
||||
|
||||
These issuers come standard with the `tls` directive:
|
||||
|
||||
#### acme
|
||||
|
||||
Obtains certificates using the ACME protocol.
|
||||
|
||||
```caddy
|
||||
... acme [<directory_url>] {
|
||||
dir <directory_url>
|
||||
test_dir <test_directory_url>
|
||||
email <email>
|
||||
timeout <duration>
|
||||
disable_http_challenge
|
||||
disable_tlsalpn_challenge
|
||||
alt_http_port <port>
|
||||
alt_tlsalpn_port <port>
|
||||
eab <key_id> <mac_key>
|
||||
trusted_roots <pem_files...>
|
||||
dns <provider_name> [<options>]
|
||||
propagation_timeout <duration>
|
||||
propagation_delay <duration>
|
||||
resolvers <dns_servers...>
|
||||
preferred_chains [smallest] {
|
||||
root_common_name <common_names...>
|
||||
any_common_name <common_names...>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **dir** <span id="dir"/> is the URL to the ACME CA's directory. Default: `https://acme-v02.api.letsencrypt.org/directory`
|
||||
- **test_dir** <span id="test_dir"/> is an optional fallback directory to use when retrying challenges; if all challenges fail, this endpoint will be used during retries; useful if a CA has a staging endpoint where you want to avoid rate limits on their production endpoint. Default: `https://acme-staging-v02.api.letsencrypt.org/directory`
|
||||
- **email** <span id="email"/> is the ACME account contact email address.
|
||||
- **timeout** <span id="timeout"/> is a [duration value](/docs/conventions#durations) that sets how long to wait before timing out an ACME operation.
|
||||
- **disable_http_challenge** <span id="disable_http_challenge"/> will disable the HTTP challenge.
|
||||
- **disable_tlsalpn_challenge** <span id="disable_tlsalpn_challenge"/> will disable the TLS-ALPN challenge.
|
||||
- **alt_http_port** <span id="alt_http_port"/> is an alternate port on which to serve the HTTP challenge; it has to happen on port 80 so you must forward packets to this alternate port.
|
||||
- **alt_tlsalpn_port** <span id="alt_tlsalpn_port"/> is an alternate port on which to serve the TLS-ALPN challenge; it has to happen on port 443 so you must forward packets to this alternate port.
|
||||
- **eab** <span id="eab"/> specifies an External Account Binding which may be required with some ACME CAs.
|
||||
- **trusted_roots** <span id="trusted_roots"/> is one or more root certificates (as PEM filenames) to trust when connecting to the ACME CA server.
|
||||
- **dns** <span id="dns"/> configures the DNS challenge.
|
||||
- **propagation_timeout** <span id="propagation_timeout"/> is a [duration value](/docs/conventions#durations) that sets the maximum time to wait for the DNS TXT records to appear when using the DNS challenge. Set to `-1` to disable propagation checks. Default 2 minutes.
|
||||
- **propagation_delay** <span id="propagation_delay"/> is a [duration value](/docs/conventions#durations) that sets how long to wait before starting DNS TXT records propagation checks when using the DNS challenge. Default 0 (no wait).
|
||||
- **resolvers** <span id="resolvers"/> customizes the DNS resolvers used when performing the DNS challenge; these take precedence over system resolvers or any default ones.
|
||||
- **preferred_chains** <span id="preferred_chains"/> specifies which certificate chains Caddy should prefer; useful if your CA provides multiple chains. Use one of the following options:
|
||||
- **smallest** <span id="smallest"/> will tell Caddy to prefer chains with the fewest amount of bytes.
|
||||
- **root_common_name** <span id="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** <span id="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.
|
||||
|
||||
|
||||
#### zerossl
|
||||
|
||||
Obtains certificates using the ACME protocol, specifically with ZeroSSL.
|
||||
|
||||
```caddy
|
||||
... zerossl [<api_key>] {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The syntax for `zerossl` is exactly the same as for `acme`, except that its name is `zerossl` and it can optionally take your ZeroSSL API key.
|
||||
|
||||
The functionality of the `zerossl` issuer is the same as the `acme` issuer, except that it will use ZeroSSL's directory by default and it can automatically negotiate EAB credentials (whereas with the `acme` issuer, you have to manually provide EAB credentials and set the directory endpoint).
|
||||
|
||||
When explicitly configuring `zerossl`, an email address is required so that your certificates can appear in your ZeroSSL dashboard.
|
||||
|
||||
Note that ZeroSSL is a default issuer, so configuring it explicitly is usually unnecessary.
|
||||
|
||||
#### internal
|
||||
|
||||
Obtains certificates from an internal certificate authority.
|
||||
|
||||
```caddy
|
||||
... internal {
|
||||
ca <name>
|
||||
lifetime <duration>
|
||||
sign_with_root
|
||||
}
|
||||
```
|
||||
|
||||
- **ca** <span id="ca"/> is the name of the internal CA to use. Default: `local`. See the [PKI app global options](/docs/caddyfile/options#pki-options) to configure alternate CAs.
|
||||
- **lifetime** <span id="lifetime"/> is a [duration value](/docs/conventions#durations) that sets the validity period for interally issued leaf certificates. Default: 12h. It is NOT recommended to not change this, unless absolutely necessary.
|
||||
- **sign_with_root** <span id="sign_with_root"/> forces the root to be the issuer instead of the intermediate. This is NOT recommended and should only be used when devices/clients do not properly validate certificate chains (very uncommon).
|
||||
|
||||
|
||||
|
||||
### Certificate Managers
|
||||
|
||||
Certificate manager modules are distinct from issuer modules in that use of manager modules implies that an external tool or service is keeping the certificate renewed, whereas an issuer module implies that Caddy itself is managing the certificate. (Issuer modules take a Certificate Signing Request (CSR) as input, but certificate manager modules take a TLS ClientHello as input.)
|
||||
|
||||
These manager modules come standard with the `tls` directive:
|
||||
|
||||
#### tailscale
|
||||
|
||||
Get certificates from a locally-running [Tailscale](https://tailscale.com) instance. [HTTPS must be enabled in your Tailscale account](https://tailscale.com/kb/1153/enabling-https/) (or your open source [Headscale server](https://github.com/juanfont/headscale)); and the Caddy process must either be running as root, or you must configure `tailscaled` to give your Caddy user [permission to fetch certificates](https://github.com/caddyserver/caddy/pull/4541#issuecomment-1021568348).
|
||||
|
||||
_**NOTE: This is usually unnecessary!** Caddy automatically uses Tailscale for all `*.ts.net` domains without any extra configuration._
|
||||
|
||||
```caddy-d
|
||||
get_certificate tailscale # often unnecessary!
|
||||
```
|
||||
|
||||
|
||||
#### http
|
||||
|
||||
Get certificates by making an HTTP(S) request. The response must have a 200 status code and the body must contain a PEM chain including the full certificate (with intermediates) as well as the private key.
|
||||
|
||||
```caddy-d
|
||||
get_certificate http <url>
|
||||
```
|
||||
|
||||
- **url** <span id="url"/> is the fully-qualified URL to which to make the request. It is strongly advised that this be a local endpoint for performance reasons. The URL will be augmented with the following query string parameters: `server_name` = SNI value, `signature_schemes` = comma-separated list of hex IDs of signature algorithms, and `cipher_suites` = comma-separated list of hex IDS of cipher suites.
|
||||
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Use a custom certificate and key:
|
||||
|
||||
```caddy-d
|
||||
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):
|
||||
|
||||
```caddy-d
|
||||
tls internal
|
||||
```
|
||||
|
||||
Use locally-trusted certificates, but managed on-demand intead of in the background:
|
||||
|
||||
```caddy-d
|
||||
tls internal {
|
||||
on_demand
|
||||
}
|
||||
```
|
||||
|
||||
Use custom options for the internal CA (cannot use the `tls internal` shortcut):
|
||||
|
||||
```caddy-d
|
||||
tls {
|
||||
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):
|
||||
|
||||
```caddy-d
|
||||
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:
|
||||
|
||||
```caddy-d
|
||||
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`
|
||||
|
||||
```caddy-d
|
||||
tls {
|
||||
client_auth {
|
||||
mode require_and_verify
|
||||
trusted_ca_cert_file ../caddy.ca.cer
|
||||
trusted_ca_cert_file ../root.ca.cer
|
||||
}
|
||||
}
|
||||
```
|
53
src/docs/markdown/caddyfile/directives/tracing.md
Normal file
53
src/docs/markdown/caddyfile/directives/tracing.md
Normal file
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
title: tracing (Caddyfile directive)
|
||||
---
|
||||
|
||||
# tracing
|
||||
|
||||
It provides integration with OpenTelemetry tracing facilities.
|
||||
|
||||
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.
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
tracing {
|
||||
[span <span_name>]
|
||||
}
|
||||
```
|
||||
|
||||
- **<span_name>** - is a span name. Please see span naming [guidelines](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/specification/trace/api.md).
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment variables
|
||||
|
||||
It can be configured using the environment variables defined
|
||||
by the [OpenTelemetry Environment Variable Specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md).
|
||||
|
||||
For the exporter configuration details, please
|
||||
see [spec](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/specification/protocol/exporter.md).
|
||||
|
||||
For example:
|
||||
|
||||
```bash
|
||||
export OTEL_EXPORTER_OTLP_HEADERS="myAuthHeader=myToken,anotherHeader=value"
|
||||
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://my-otlp-endpoint:55680
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Here is a **Caddyfile** example:
|
||||
|
||||
```
|
||||
handle /myHandler {
|
||||
tracing {
|
||||
span my-span
|
||||
}
|
||||
reverse_proxy 127.0.0.1:8081
|
||||
}
|
||||
```
|
68
src/docs/markdown/caddyfile/directives/try_files.md
Normal file
68
src/docs/markdown/caddyfile/directives/try_files.md
Normal file
|
@ -0,0 +1,68 @@
|
|||
---
|
||||
title: try_files (Caddyfile directive)
|
||||
---
|
||||
|
||||
# try_files
|
||||
|
||||
Rewrites the request URI path to the first of the listed files which exists in the site root. If no files match, no rewrite is performed.
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
try_files <files...> {
|
||||
policy first_exist|smallest_size|largest_size|most_recently_modified
|
||||
}
|
||||
```
|
||||
|
||||
- **<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. Each argument may also contain a query string, in which case the query string will also be changed if it matches that particular file. 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).
|
||||
- **policy** is the policy for choosing the file among the list of files. Default: `first_exist`
|
||||
|
||||
|
||||
## Expanded form
|
||||
|
||||
The `try_files` directive is basically a shortcut for:
|
||||
|
||||
```caddy-d
|
||||
@try_files file <files...>
|
||||
rewrite @try_files {http.matchers.file.relative}
|
||||
```
|
||||
|
||||
Note that this directive does not accept a matcher token. If you need more complex matching logic, then use the expanded form above as a basis.
|
||||
|
||||
See the [`file` matcher](/docs/caddyfile/matchers#file) for more details.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
If the request does not match any static files, rewrite to an index/router file:
|
||||
|
||||
```caddy-d
|
||||
try_files {path} /index.php
|
||||
```
|
||||
|
||||
Same, but adding the original path to the query string:
|
||||
|
||||
```caddy-d
|
||||
try_files {path} /index.php?{query}&p={path}
|
||||
```
|
||||
|
||||
Same, but also match directories:
|
||||
|
||||
```caddy-d
|
||||
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)):
|
||||
|
||||
```caddy-d
|
||||
try_files {path} {path}/ =404
|
||||
```
|
||||
|
||||
Choose the most recently deployed version of a static file (e.g. serve `index.be331df.html` when `index.html` is requested):
|
||||
|
||||
```caddy-d
|
||||
try_files {file.base}.*.{file.ext} {
|
||||
policy most_recently_modified
|
||||
}
|
||||
```
|
68
src/docs/markdown/caddyfile/directives/uri.md
Normal file
68
src/docs/markdown/caddyfile/directives/uri.md
Normal file
|
@ -0,0 +1,68 @@
|
|||
---
|
||||
title: uri (Caddyfile directive)
|
||||
---
|
||||
|
||||
# uri
|
||||
|
||||
Manipulates a request's URI. It can strip path prefix/suffix or replace substrings on the whole URI.
|
||||
|
||||
This directive is distinct from [`rewrite`](rewrite) in that `uri` _differentiably_ changes the URI, rather than resetting it to something completely different as `rewrite` does. While `rewrite` is treated specially as an internal redirect, `uri` is just another middleware.
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
Multiple different operations are supported:
|
||||
|
||||
```caddy-d
|
||||
uri [<matcher>] strip_prefix <target>
|
||||
uri [<matcher>] strip_suffix <target>
|
||||
uri [<matcher>] replace <target> <replacement> [<limit>]
|
||||
uri [<matcher>] path_regexp <target> <replacement>
|
||||
```
|
||||
|
||||
- The first (non-matcher) argument specifies the operation:
|
||||
- **strip_prefix** strips the prefix from the path.
|
||||
- **strip_suffix** strips the suffix from the path.
|
||||
- **replace** performs a substring replacement across the whole URI.
|
||||
- **path_regexp** performs a regular expression replacement on the path portion of the URI.
|
||||
- **<target>** is the prefix, suffix, or search string/regular expression. If a prefix, the leading forward slash may be omitted, since paths always start with a forward slash.
|
||||
- **<replacement>** is the replacement string (only valid with `replace` and `path_regexp`). Supports using capture groups with `$name` or `${name}` syntax, or with a number for the index, such as `$1`. See the [Go documentation](https://golang.org/pkg/regexp/#Regexp.Expand) for details.
|
||||
- **<limit>** is an optional limit to the maximum number of replacements (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`.
|
||||
|
||||
The URI path is cleaned of directory traversal dots before modifications. Additionally, multiple slashes (such as `//`) are merged unless the `<target>` contains multiple slashes too.
|
||||
|
||||
## Similar directives
|
||||
|
||||
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.
|
||||
- [`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.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Strip `/api` from the beginning of all request paths:
|
||||
|
||||
```caddy-d
|
||||
uri strip_prefix /api
|
||||
```
|
||||
|
||||
Strip `.php` from the end of all request paths:
|
||||
|
||||
```caddy-d
|
||||
uri strip_suffix .php
|
||||
```
|
||||
|
||||
Replace "/docs/" with "/v1/docs/" in any request URI:
|
||||
|
||||
```caddy-d
|
||||
uri replace /docs/ /v1/docs/
|
||||
```
|
||||
|
||||
Collapse all repeated slashes in the request path (but not the request query) to a single slash:
|
||||
|
||||
```caddy-d
|
||||
uri path_regexp /{2,} /
|
||||
```
|
53
src/docs/markdown/caddyfile/directives/vars.md
Normal file
53
src/docs/markdown/caddyfile/directives/vars.md
Normal file
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
title: vars (Caddyfile directive)
|
||||
---
|
||||
|
||||
# vars
|
||||
|
||||
Sets one or more variables to a particular value, to be used later in the request handling chain.
|
||||
|
||||
The primary way to access variables is with placeholders, which have the form `{vars.variable_name}`, or with the [`vars`](/docs/caddyfile/matchers#vars) and [`vars_regexp`](/docs/caddyfile/matchers#vars_regexp) request matchers.
|
||||
|
||||
## Syntax
|
||||
|
||||
```caddy-d
|
||||
vars [<matcher>] [<name> <value>] {
|
||||
<name> <value>
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
- **<name>** is the variable name to set.
|
||||
|
||||
- **<value>** is the value of the variable.
|
||||
|
||||
The value will be type converted if possible; `true` and `false` will be converted to boolean types, and numeric values will be converted to integer or float accordingly. To avoid this conversion, you may wrap the output with [quotes](/docs/caddyfile/concepts#tokens-and-quotes) and they will stay strings.
|
||||
|
||||
## Examples
|
||||
|
||||
To set a single variable, the value being conditional based on the request path, then responding with the value:
|
||||
|
||||
```caddy-d
|
||||
vars /foo* isFoo "yep"
|
||||
vars isFoo "nope"
|
||||
|
||||
respond {vars.isFoo}
|
||||
```
|
||||
|
||||
To set multiple variables, each converted to the appropriate scalar type:
|
||||
|
||||
```caddy-d
|
||||
vars {
|
||||
# boolean
|
||||
abc true
|
||||
|
||||
# integer
|
||||
def 1
|
||||
|
||||
# float
|
||||
ghi 2.3
|
||||
|
||||
# string
|
||||
jkl "example"
|
||||
}
|
||||
```
|
648
src/docs/markdown/caddyfile/matchers.md
Normal file
648
src/docs/markdown/caddyfile/matchers.md
Normal file
|
@ -0,0 +1,648 @@
|
|||
---
|
||||
title: Request matchers (Caddyfile)
|
||||
---
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
// We'll add links on the matchers in the code blocks
|
||||
// to their associated anchor tags.
|
||||
let headers = $('article h3').map((i, el) => el.id.replace(/-/g, "_")).toArray();
|
||||
$('pre.chroma .k')
|
||||
.filter((k, item) => headers.includes(item.innerText))
|
||||
.map(function(k, item) {
|
||||
let text = item.innerText.replace(/</g,'<').replace(/>/g,'>');
|
||||
let url = '#' + item.innerText.replace(/_/g, "-");
|
||||
$(item).html('<a href="' + url + '" style="color: inherit;" title="' + text + '">' + text + '</a>');
|
||||
});
|
||||
|
||||
// Link matcher tokens based on their contents to the syntax section
|
||||
$('pre.chroma .nd')
|
||||
.map(function(k, item) {
|
||||
let text = item.innerText.replace(/</g,'<').replace(/>/g,'>');
|
||||
let anchor = "named-matchers"
|
||||
if (text == "*") anchor = "wildcard-matchers"
|
||||
if (text.startsWith('/')) anchor = "path-matchers"
|
||||
$(item).html('<a href="#' + anchor + '" style="color: inherit;" title="Matcher token">' + text + '</a>');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
# Request Matchers
|
||||
|
||||
**Request matchers** can be used to filter (or classify) requests by various criteria.
|
||||
|
||||
### Menu
|
||||
|
||||
- [Syntax](#syntax)
|
||||
- [Examples](#examples)
|
||||
- [Wildcard matchers](#wildcard-matchers)
|
||||
- [Path matchers](#path-matchers)
|
||||
- [Named matchers](#named-matchers)
|
||||
- [Standard matchers](#standard-matchers)
|
||||
- [expression](#expression)
|
||||
- [file](#file)
|
||||
- [header](#header)
|
||||
- [header_regexp](#header-regexp)
|
||||
- [host](#host)
|
||||
- [method](#method)
|
||||
- [not](#not)
|
||||
- [path](#path)
|
||||
- [path_regexp](#path-regexp)
|
||||
- [protocol](#protocol)
|
||||
- [query](#query)
|
||||
- [remote_ip](#remote-ip)
|
||||
- [vars](#vars)
|
||||
- [vars_regexp](#vars-regexp)
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
In the Caddyfile, a **matcher token** immediately following the directive can limit that directive's scope. The matcher token can be one of these forms:
|
||||
|
||||
1. **`*`** to match all requests (wildcard; default).
|
||||
2. **`/path`** start with a forward slash to match a request path.
|
||||
3. **`@name`** to specify a _named matcher_.
|
||||
|
||||
Matcher tokens are [usually optional](/docs/caddyfile/directives#matchers). If a matcher token is omitted, it is the same as a wildcard matcher (`*`).
|
||||
|
||||
|
||||
#### Examples
|
||||
|
||||
This directive applies to [all](#wildcard-matchers) HTTP requests:
|
||||
|
||||
```caddy-d
|
||||
reverse_proxy localhost:9000
|
||||
```
|
||||
|
||||
And this is the same (`*` is unnecessary here):
|
||||
|
||||
```caddy-d
|
||||
reverse_proxy * localhost:9000
|
||||
```
|
||||
|
||||
But this directive applies only to requests having a [path](#path-matchers) starting with `/api/`:
|
||||
|
||||
```caddy-d
|
||||
reverse_proxy /api/* localhost:9000
|
||||
```
|
||||
|
||||
To match on anything other than a path, define a [named matcher](#named-matchers) and refer to it using `@name`:
|
||||
|
||||
```caddy-d
|
||||
@postfoo {
|
||||
method POST
|
||||
path /foo/*
|
||||
}
|
||||
reverse_proxy @postfoo localhost:9000
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### Wildcard matchers
|
||||
|
||||
The wildcard (or "catch-all") matcher `*` matches all requests, and is only needed if a matcher token is required. For example, if the first argument you want to give a directive also happens to be a path, it would look exactly like a path matcher! So you can use a wildcard matcher to disambiguate, for example:
|
||||
|
||||
```caddy-d
|
||||
root * /home/www/mysite
|
||||
```
|
||||
|
||||
Otherwise, this matcher is not often used. We generally recommend omitting it if syntax doesn't require it.
|
||||
|
||||
|
||||
### Path matchers
|
||||
|
||||
Matching by URI path is the most common way to match requests, so the matcher can be inlined, like this:
|
||||
|
||||
```caddy-d
|
||||
redir /old.html /new.html
|
||||
```
|
||||
|
||||
Path matcher tokens must start with a forward slash `/`.
|
||||
|
||||
**[Path matching](#path) is an exact match by default, not a prefix match.** You must append a `*` for a fast prefix match. Note that `/foo*` will match `/foo` and `/foo/` as well as `/foobar`; you might actually want `/foo/*` instead.
|
||||
|
||||
|
||||
### Named matchers
|
||||
|
||||
All matchers that are not path or wildcard matchers must be named matchers. This is a matcher that is defined outside of any particular directive, and can be reused.
|
||||
|
||||
Defining a matcher with a unique name gives you more flexibility, allowing you to combine [any available matchers](#standard-matchers) into a set:
|
||||
|
||||
```caddy-d
|
||||
@name {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
or, if there is only one matcher in the set, you can put it on the same line:
|
||||
|
||||
```caddy-d
|
||||
@name ...
|
||||
```
|
||||
|
||||
Then you can use the matcher like so: `@name`
|
||||
|
||||
For example:
|
||||
|
||||
```caddy-d
|
||||
@websockets {
|
||||
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".
|
||||
|
||||
If the matcher set consists of only one matcher, a one-liner syntax also works:
|
||||
|
||||
```caddy-d
|
||||
@post method POST
|
||||
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:
|
||||
|
||||
```caddy-d
|
||||
@notFound `{err.status_code} == 404`
|
||||
```
|
||||
|
||||
Like directives, named matcher definitions must go inside the site blocks 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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Standard matchers
|
||||
|
||||
Full matcher documentation can be found [in each respective matcher module's docs](/docs/json/apps/http/servers/routes/match/).
|
||||
|
||||
Requests can be matched the following ways:
|
||||
|
||||
### expression
|
||||
|
||||
```caddy-d
|
||||
expression <cel...>
|
||||
```
|
||||
|
||||
By any [CEL (Common Expression Language)](https://github.com/google/cel-spec) expression that returns `true` or `false`.
|
||||
|
||||
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.
|
||||
|
||||
For convenience, the matcher name may be omitted if defining a named matcher that consists solely of a CEL expression. This reads quite nicely:
|
||||
|
||||
```caddy-d
|
||||
@mutable `{method}.startsWith("P")`
|
||||
```
|
||||
|
||||
In this case the CEL matcher is assumed.
|
||||
|
||||
#### Examples:
|
||||
|
||||
Match requests whose methods start with `P`, e.g. `PUT` or `POST`:
|
||||
|
||||
```caddy-d
|
||||
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):
|
||||
|
||||
```caddy-d
|
||||
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:
|
||||
|
||||
```caddy-d
|
||||
expression path_regexp('^/user/(\w*)') || path_regexp('^/(\w*)')
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
### file
|
||||
|
||||
```caddy-d
|
||||
file {
|
||||
root <path>
|
||||
try_files <files...>
|
||||
try_policy first_exist|smallest_size|largest_size|most_recent_modified
|
||||
split_path <delims...>
|
||||
}
|
||||
file <files...>
|
||||
|
||||
expression `file({
|
||||
'root': '<path>',
|
||||
'try_files': ['<files...>'],
|
||||
'try_policy': 'first_exist|smallest_size|largest_size|most_recent_modified',
|
||||
'split_path': ['<delims...>']
|
||||
})`
|
||||
expression file('<files...>')
|
||||
```
|
||||
|
||||
By files.
|
||||
|
||||
- `root` defines the directory in which to look for files. Default is the current working directory, or the `root` [variable](/docs/modules/http.handlers.vars) (`{http.vars.root}`) if set (can be set via the [`root` directive](/docs/caddyfile/directives/root)).
|
||||
- `try_files` checks files in its list that match the try_policy. If the `try_policy` is `first_exist`, 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).
|
||||
- `try_policy` specifies how to choose a file. Default is `first_exist`.
|
||||
- `first_exist` checks for file existence. The first file that exists is selected.
|
||||
- `smallest_size` chooses the file with the smallest size.
|
||||
- `largest_size` chooses the file with the largest size.
|
||||
- `most_recent_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.
|
||||
|
||||
Because `try_files` with a policy of `first_exist` is so common, there is a one-line shortcut for that:
|
||||
|
||||
```caddy-d
|
||||
file <files...>
|
||||
```
|
||||
|
||||
An empty `file` matcher (one with no files listed after it) will see if the requested file—verbatim from the URI, relative to the [site root](/docs/caddyfile/directives/root)—exists. This is effectively the same as `file {path}`.
|
||||
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
Since rewriting based on the existence of a file on disk is so common, there is also a [`try_files` directive](/docs/caddyfile/directives/try_files) which is a shortcut of the `file` matcher and a [`rewrite` handler](/docs/caddyfile/directives/rewrite).
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
Upon matching, two new placeholders will be made available:
|
||||
|
||||
- `{http.matchers.file.relative}` The root-relative path of the file. This is often useful when rewriting requests.
|
||||
- `{http.matchers.file.absolute}` The absolute path of the matched file.
|
||||
|
||||
#### Examples:
|
||||
|
||||
Match requests where the path is a file that exists:
|
||||
|
||||
```caddy-d
|
||||
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:
|
||||
|
||||
```caddy-d
|
||||
file {
|
||||
try_files {path}.html {path}
|
||||
}
|
||||
```
|
||||
|
||||
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
|
||||
file {path}.html {path} =404
|
||||
```
|
||||
|
||||
|
||||
|
||||
---
|
||||
### header
|
||||
|
||||
```caddy-d
|
||||
header <field> [<value>]
|
||||
|
||||
expression header({'<field>': '<value>'})
|
||||
```
|
||||
|
||||
By request header fields.
|
||||
|
||||
- `<field>` is the name of the HTTP header field to check.
|
||||
- If prefixed with `!`, the field must not exist to match (omit value arg).
|
||||
- `<value>` is the value the field must have to match.
|
||||
- If prefixed with `*`, it performs a fast suffix match.
|
||||
- If suffixed with `*`, it performs a fast prefix match.
|
||||
- If enclosed by `*`, it performs a fast substring match.
|
||||
- Otherwise, it is a fast exact match.
|
||||
|
||||
Different header fields within the same set are AND-ed. Multiple values per field are OR'ed.
|
||||
|
||||
#### Example:
|
||||
|
||||
Match requests with the `Connection` header containing `Upgrade`:
|
||||
|
||||
```caddy-d
|
||||
header Connection *Upgrade*
|
||||
```
|
||||
|
||||
Match requests with the `Foo` header containing `bar` OR `baz`:
|
||||
```caddy-d
|
||||
@foo {
|
||||
header Foo bar
|
||||
header Foo baz
|
||||
}
|
||||
```
|
||||
|
||||
Match requests that do not have the `Foo` header field at all:
|
||||
```caddy-d
|
||||
@not_foo header !Foo
|
||||
```
|
||||
|
||||
|
||||
|
||||
---
|
||||
### header_regexp
|
||||
|
||||
```caddy-d
|
||||
header_regexp [<name>] <field> <regexp>
|
||||
|
||||
expression header_regexp('<name>', '<field>', '<regexp>')
|
||||
expression header_regexp('<field>', '<regexp>')
|
||||
```
|
||||
|
||||
Like [`header`](#header), but supports regular expressions. Capture groups can be accessed via [placeholder](/docs/caddyfile/concepts#placeholders) like `{re.name.capture_group}` where `name` is the name of the regular expression (optional, but recommended) and `capture_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.
|
||||
|
||||
The regular expression language used is RE2, included in Go. See the [RE2 syntax reference](https://github.com/google/re2/wiki/Syntax) and the [Go regexp syntax overview](https://pkg.go.dev/regexp/syntax).
|
||||
|
||||
Only one regular expression is supported per header field. Multiple different fields will be AND'ed.
|
||||
|
||||
#### Example:
|
||||
|
||||
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
|
||||
header_regexp login Cookie login_([a-f0-9]+)
|
||||
```
|
||||
|
||||
|
||||
|
||||
---
|
||||
### host
|
||||
|
||||
```caddy-d
|
||||
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.
|
||||
|
||||
Multiple `host` matchers will be OR'ed together.
|
||||
|
||||
#### Example:
|
||||
|
||||
```caddy-d
|
||||
host sub.example.com
|
||||
```
|
||||
|
||||
|
||||
|
||||
---
|
||||
### method
|
||||
|
||||
```caddy-d
|
||||
method <verbs...>
|
||||
|
||||
expression method('<verbs...>')
|
||||
```
|
||||
|
||||
By the method (verb) of the HTTP request. Verbs should be uppercase, like `POST`. Can match one or many methods.
|
||||
|
||||
Multiple `method` matchers will be OR'ed together.
|
||||
|
||||
#### Examples:
|
||||
|
||||
Match requests with the `GET` method:
|
||||
|
||||
```caddy-d
|
||||
method GET
|
||||
```
|
||||
|
||||
Match requests with the `PUT` or `DELETE` methods:
|
||||
|
||||
```caddy-d
|
||||
method PUT DELETE
|
||||
```
|
||||
|
||||
|
||||
|
||||
---
|
||||
### not
|
||||
|
||||
```caddy-d
|
||||
not <any other matcher>
|
||||
```
|
||||
|
||||
or, to negate multiple matchers which get AND'ed, open a block:
|
||||
|
||||
```caddy-d
|
||||
not {
|
||||
<any other matchers...>
|
||||
}
|
||||
```
|
||||
|
||||
The results of the enclosed matchers will be negated.
|
||||
|
||||
#### Examples:
|
||||
|
||||
Match requests with paths that do NOT begin with `/css/` OR `/js/`.
|
||||
|
||||
```caddy-d
|
||||
not path /css/* /js/*
|
||||
```
|
||||
|
||||
Match requests WITH NEITHER:
|
||||
- an `/api/` path prefix, NOR
|
||||
- the `POST` request method
|
||||
|
||||
i.e. must have none of these to match:
|
||||
|
||||
```caddy-d
|
||||
not path /api/*
|
||||
not method POST
|
||||
```
|
||||
|
||||
Match requests WITHOUT BOTH:
|
||||
- an `/api/` path prefix, AND
|
||||
- the `POST` request method
|
||||
|
||||
i.e. must have neither or either of these to match:
|
||||
|
||||
```caddy-d
|
||||
not {
|
||||
path /api/*
|
||||
method POST
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
---
|
||||
### path
|
||||
|
||||
```caddy-d
|
||||
path <paths...>
|
||||
|
||||
expression path('<paths...>')
|
||||
```
|
||||
|
||||
By request path (the path component of the request URI). Path matches are exact but case-insensitive. Wildcards `*` may be used:
|
||||
|
||||
- At the end only, for a prefix match (`/prefix/*`)
|
||||
- At the beginning only, for a suffix match (`*.suffix`)
|
||||
- On both sides only, for a substring match (`*/contains/*`)
|
||||
- In the middle only, for a globular match (`/accounts/*/info`)
|
||||
|
||||
Slashes are significant. For example, `/foo*` will match `/foo`, `/foobar`, `/foo/`, and `/foo/bar`, but `/foo/*` will _not_ match `/foo` or `/foobar`.
|
||||
|
||||
Request paths are cleaned to resolve directory traversal dots before matching. Additionally, multiple slashes are merged unless the match pattern has multiple slashes. In other words, `/foo` will match `/foo` and `//foo`, but `//foo` will only match `//foo`.
|
||||
|
||||
Because there are multiple escaped forms of any given URI, the request path is normalized (URL-decoded, unescaped) except for those escape sequences at positions where escape sequences are also present in the match pattern. For example, `/foo/bar` matches both `/foo/bar` and `/foo%2Fbar`, but `/foo%2Fbar` will match only `/foo%2Fbar`, because the escape sequence is explicitly given in the configuration.
|
||||
|
||||
The special wildcard escape `%*` can also be used instead of `*` to leave its matching span escaped. For example, `/bands/*/*` will not match `/bands/AC%2FDC/T.N.T` because the path will be compared in normalized space where it looks like `/bands/AC/DC/T.N.T`, which does not match the pattern; however, `/bands/%*/*` will match `/bands/AC%2FDC/T.N.T` because the span represented by `%*` will be compared without decoding escape sequences.
|
||||
|
||||
Multiple paths will be OR'ed together.
|
||||
|
||||
|
||||
|
||||
---
|
||||
### path_regexp
|
||||
|
||||
```caddy-d
|
||||
path_regexp [<name>] <regexp>
|
||||
|
||||
expression path_regexp('<name>', '<regexp>')
|
||||
expression path_regexp('<regexp>')
|
||||
```
|
||||
|
||||
Like [`path`](#path), but supports regular expressions. Write the pattern on the URI-decoded/unescaped form of the path.
|
||||
|
||||
The regular expression language used is RE2, included in Go. See the [RE2 syntax reference](https://github.com/google/re2/wiki/Syntax) and the [Go regexp syntax overview](https://pkg.go.dev/regexp/syntax).
|
||||
|
||||
Capture groups can be accessed via [placeholder](/docs/caddyfile/concepts#placeholders) like `{re.name.capture_group}` where `name` is the name of the regular expression (optional, but recommended) and `capture_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.
|
||||
|
||||
There can only be one `path_regexp` pattern per named matcher.
|
||||
|
||||
#### Example:
|
||||
|
||||
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
|
||||
path_regexp static \.([a-f0-9]{6})\.(css|js)$
|
||||
```
|
||||
|
||||
|
||||
|
||||
---
|
||||
### protocol
|
||||
|
||||
```caddy-d
|
||||
protocol http|https|grpc|http/<version>[+]
|
||||
|
||||
expression protocol('http|https|grpc')
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
---
|
||||
### query
|
||||
|
||||
```caddy-d
|
||||
query <key>=<val>...
|
||||
|
||||
expression query({'<key>': '<val>'})
|
||||
expression query({'<key>': ['<vals...>']})
|
||||
```
|
||||
|
||||
By query string parameters. Should be a sequence of `key=value` pairs. Keys are matched exactly, case-sensitively. Values can contain placeholders. Values are matched exactly, but also support `*` to match any value.
|
||||
|
||||
There can be multiple `query` matchers per named matcher, and pairs with the same keys will be OR'ed together.
|
||||
|
||||
Illegal query strings (bad syntax, unescaped semicolons, etc.) will fail to parse and thus will not match.
|
||||
|
||||
#### Example:
|
||||
|
||||
Match requests with a `sort` query parameter with the value `asc`:
|
||||
|
||||
```caddy-d
|
||||
query sort=asc
|
||||
```
|
||||
|
||||
|
||||
|
||||
---
|
||||
### remote_ip
|
||||
|
||||
```caddy-d
|
||||
remote_ip [forwarded] <ranges...>
|
||||
|
||||
expression remote_ip('<ranges...>')
|
||||
expression remote_ip('forwarded', '<ranges...>')
|
||||
```
|
||||
|
||||
By remote (client) IP address. Accepts exact IPs or CIDR ranges. If the first argument is `forwarded`, then the first IP in the `X-Forwarded-For` request header, if present, will be preferred as the reference IP, rather than the immediate peer's IP, which is the default. IPv6 zones are supported.
|
||||
|
||||
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`
|
||||
|
||||
There can be multiple `remote_ip` matchers per named matcher, and their ranges will be merged and OR'ed together.
|
||||
|
||||
#### Example:
|
||||
|
||||
Match requests from private IPv4 addresses:
|
||||
|
||||
```caddy-d
|
||||
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):
|
||||
|
||||
```caddy-d
|
||||
@denied not remote_ip private_ranges
|
||||
abort @denied
|
||||
```
|
||||
|
||||
|
||||
|
||||
---
|
||||
### vars
|
||||
|
||||
```caddy-d
|
||||
vars <variable> <values...>
|
||||
```
|
||||
|
||||
By the value of a variable in the request context, or the value of a placeholder. Multiple values may be specified to match any of those possible values (OR'ed).
|
||||
|
||||
The **<variable>** argument may be either a variable name or a placeholder in curly braces `{ }`. (Placeholders are not expanded in the first parameter.)
|
||||
|
||||
This matcher is most useful when paired with the [`map` directive](/docs/caddyfile/directives/map) which sets outputs, or with plugins which set some information in the request context.
|
||||
|
||||
#### Example:
|
||||
|
||||
Match an output of the [`map` directive](/docs/caddyfile/directives/map) named `magic_number` for the values `3` or `5`:
|
||||
|
||||
```caddy-d
|
||||
vars {magic_number} 3 5
|
||||
```
|
||||
|
||||
|
||||
|
||||
---
|
||||
### vars_regexp
|
||||
|
||||
```caddy-d
|
||||
vars_regexp [<name>] <variable> <regexp>
|
||||
```
|
||||
|
||||
Like [`vars`](#vars), but supports regular expressions. Capture groups can be accessed via [placeholder](/docs/caddyfile/concepts#placeholders) like `{re.name.capture_group}` where `name` is the name of the regular expression (optional, but recommended) and `capture_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.
|
||||
|
||||
The regular expression language used is RE2, included in Go. See the [RE2 syntax reference](https://github.com/google/re2/wiki/Syntax) and the [Go regexp syntax overview](https://pkg.go.dev/regexp/syntax).
|
||||
|
||||
There can only be one `vars_regexp` matcher per named matcher.
|
||||
|
||||
#### Example:
|
||||
|
||||
Match an output of the [`map` directive](/docs/caddyfile/directives/map) named `magic_number` for a value starting with `4`, capturing the value in a capture group:
|
||||
|
||||
```caddy-d
|
||||
vars_regexp magic {magic_number} ^(4.*)
|
||||
```
|
458
src/docs/markdown/caddyfile/options.md
Normal file
458
src/docs/markdown/caddyfile/options.md
Normal file
|
@ -0,0 +1,458 @@
|
|||
---
|
||||
title: Global options (Caddyfile)
|
||||
---
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
// We'll add links on the options in the code block at the top
|
||||
// to their associated anchor tags.
|
||||
let headers = $('article h5').map((i, el) => el.id.replace(/-/g, "_")).toArray();
|
||||
$('pre.chroma .k')
|
||||
.filter((k, item) => headers.includes(item.innerText))
|
||||
.map(function(k, item) {
|
||||
let text = item.innerText.replace(/</g,'<').replace(/>/g,'>');
|
||||
let url = '#' + item.innerText.replace(/_/g, "-");
|
||||
$(item).html('<a href="' + url + '" style="color: inherit;" title="' + text + '">' + text + '</a>');
|
||||
});
|
||||
// Add links on comments to their respective sections
|
||||
$('pre.chroma .c1')
|
||||
.filter((k, item) => item.innerText.includes('#'))
|
||||
.map(function(k, item) {
|
||||
let text = item.innerText;
|
||||
let before = text.slice(0, text.indexOf('#'));
|
||||
text = text.slice(text.indexOf('#'));
|
||||
let url = '#' + text.replace(/#/g, '').trim().toLowerCase().replace(/ /g, "-");
|
||||
$(item).html(before + '<a href="' + url + '" style="color: inherit;" title="' + text + '">' + text + '</a>');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
# 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 very top of your Caddyfile can be a **global options block**. This is a block that has no keys:
|
||||
|
||||
```caddy
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
There can only be one at most, and it must be the first block of the Caddyfile.
|
||||
|
||||
Possible options are:
|
||||
|
||||
```caddy
|
||||
{
|
||||
# General Options
|
||||
debug
|
||||
http_port <port>
|
||||
https_port <port>
|
||||
default_bind <hosts...>
|
||||
order <dir1> first|last|[before|after <dir2>]
|
||||
storage <module_name> {
|
||||
<options...>
|
||||
}
|
||||
storage_clean_interval <duration>
|
||||
renew_interval <duration>
|
||||
ocsp_interval <duration>
|
||||
admin off|<addr> {
|
||||
origins <origins...>
|
||||
enforce_origin
|
||||
}
|
||||
log [name] {
|
||||
output <writer_module> ...
|
||||
format <encoder_module> ...
|
||||
level <level>
|
||||
include <namespaces...>
|
||||
exclude <namespaces...>
|
||||
}
|
||||
grace_period <duration>
|
||||
shutdown_delay <duration>
|
||||
|
||||
# TLS Options
|
||||
auto_https off|disable_redirects|ignore_loaded_certs|disable_certs
|
||||
email <yours>
|
||||
default_sni <name>
|
||||
local_certs
|
||||
skip_install_trust
|
||||
acme_ca <directory_url>
|
||||
acme_ca_root <pem_file>
|
||||
acme_eab <key_id> <mac_key>
|
||||
acme_dns <provider> ...
|
||||
on_demand_tls {
|
||||
ask <endpoint>
|
||||
interval <duration>
|
||||
burst <n>
|
||||
}
|
||||
key_type ed25519|p256|p384|rsa2048|rsa4096
|
||||
cert_issuer <name> ...
|
||||
ocsp_stapling off
|
||||
preferred_chains [smallest] {
|
||||
root_common_name <common_names...>
|
||||
any_common_name <common_names...>
|
||||
}
|
||||
|
||||
# Server Options
|
||||
servers [<listener_address>] {
|
||||
listener_wrappers {
|
||||
<listener_wrappers...>
|
||||
}
|
||||
timeouts {
|
||||
read_body <duration>
|
||||
read_header <duration>
|
||||
write <duration>
|
||||
idle <duration>
|
||||
}
|
||||
max_header_size <size>
|
||||
log_credentials
|
||||
protocols [h1|h2|h2c|h3]
|
||||
strict_sni_host [on|insecure_off]
|
||||
metrics # experimental!
|
||||
}
|
||||
|
||||
# PKI Options
|
||||
pki {
|
||||
ca [<id>] {
|
||||
name <name>
|
||||
root_cn <name>
|
||||
intermediate_cn <name>
|
||||
root {
|
||||
format <format>
|
||||
cert <path>
|
||||
key <path>
|
||||
}
|
||||
intermediate {
|
||||
format <format>
|
||||
cert <path>
|
||||
key <path>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Event options
|
||||
events {
|
||||
on <event> <handler...>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## General Options
|
||||
|
||||
##### `debug`
|
||||
Enables debug mode, which sets the log level to `DEBUG` for the [default logger](#log). This reveals more details that can be useful when troubleshooting (and is very verbose in production). We ask that you enable this before asking for help on the [community forums](https://caddy.community). For example, at the top of your Caddyfile, if you have no other global options:
|
||||
|
||||
```caddy
|
||||
{
|
||||
debug
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
##### `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`
|
||||
|
||||
|
||||
##### `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`
|
||||
|
||||
|
||||
##### `default_bind`
|
||||
The default bind address(es) to be used for all sites, if the [`bind` directive](/docs/caddyfile/directives/bind) is not used in the site. Default: empty, which binds to all interfaces.
|
||||
|
||||
|
||||
##### `order`
|
||||
Assigns an order to HTTP handler directive(s). As HTTP handlers execute in a sequential chain, it is necessary for the handlers to be executed in the right order. Standard directives have [a pre-defined order](/docs/caddyfile/directives#directive-order), but if using third-party HTTP handler modules, you'll need to define the order explicitly by either using this option or placing the directive in a [`route` block](/docs/caddyfile/directives/route). Ordering can be described absolutely (`first` or `last`), or relatively (`before` or `after`) to another directive.
|
||||
|
||||
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
|
||||
order replace after encode
|
||||
```
|
||||
|
||||
|
||||
##### `storage`
|
||||
Configures Caddy's storage mechanism. The default is [`file_system`](/docs/json/storage/file_system/). There are many other available [storage modules](/docs/json/storage/) provided as plugins.
|
||||
|
||||
For example, to change the file system's storage location:
|
||||
|
||||
```caddy-d
|
||||
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.
|
||||
|
||||
|
||||
##### `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. The value is a [duration value](/docs/conventions#durations). Default: `24h`.
|
||||
|
||||
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).
|
||||
|
||||
|
||||
##### `renew_interval`
|
||||
How often to scan all loaded, managed certificates for expiration, and trigger renewal if expired. Default: `10m`.
|
||||
|
||||
|
||||
##### `ocsp_interval`
|
||||
How often to check if OCSP staples need updating. Default: `1h`.
|
||||
|
||||
|
||||
##### `admin`
|
||||
Customizes the [admin API endpoint](/docs/api). If `off`, then the admin endpoint will be disabled. If disabled, config changes will be impossible without stopping and starting the server.
|
||||
|
||||
- **origins** configures the list of remotes/origins that are allowed to connect to the endpoint.
|
||||
|
||||
- **enforce_origin** enables enforcement of the Origin header. (This is different from enforcing origins generally, which is always done.)
|
||||
|
||||
|
||||
##### `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).
|
||||
|
||||
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.
|
||||
- **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`.
|
||||
- **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, 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, no logs are excluded.
|
||||
|
||||
|
||||
##### `grace_period`
|
||||
Defines the grace period for shutting down HTTP servers during config changes. 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. By default, no grace period is set.
|
||||
|
||||
|
||||
##### `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:
|
||||
|
||||
```caddy-d
|
||||
handle /health-check {
|
||||
@goingDown vars {http.shutting_down} true
|
||||
respond @goingDown "Bye-bye in {http.time_until_shutdown}" 503
|
||||
respond 200
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## TLS Options
|
||||
|
||||
##### `auto_https`
|
||||
Configure automatic HTTPS. There are a few modes to choose from:
|
||||
|
||||
- `off`: Disabled entirely. No certificate management or redirects.
|
||||
- `disable_redirects`: Disable only HTTP-to-HTTPS redirects.
|
||||
- `disable_certs`: Disable only certificate automation.
|
||||
- `ignore_loaded_certs`: Automate certificates even for names which appear on manually-loaded certificates
|
||||
|
||||
See the [Automatic HTTPS](/docs/automatic-https) page for more details.
|
||||
|
||||
|
||||
##### `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.
|
||||
|
||||
|
||||
##### `default_sni`
|
||||
Sets a default TLS ServerName for when clients do not use SNI in their ClientHello.
|
||||
|
||||
|
||||
##### `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.
|
||||
|
||||
|
||||
##### `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.
|
||||
|
||||
|
||||
##### `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](https://letsencrypt.org/docs/staging-environment/) for testing or development. Default: ZeroSSL and Let's Encrypt's production endpoints.
|
||||
|
||||
|
||||
##### `acme_ca_root`
|
||||
Specifies a PEM file that contains a trusted root certificate for ACME CA endpoints, if not in the system trust store.
|
||||
|
||||
|
||||
##### `acme_eab`
|
||||
Specifies an External Account Binding to use for all ACME transactions.
|
||||
|
||||
|
||||
##### `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).
|
||||
|
||||
|
||||
##### `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 `tls` subdirective](/docs/caddyfile/directives/tls#syntax)). Highly recommended if using 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.
|
||||
|
||||
- **interval** and **burst** allows `<n>` certificate operations within `<duration>` interval.
|
||||
|
||||
|
||||
##### `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`.
|
||||
|
||||
|
||||
##### `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.
|
||||
|
||||
|
||||
##### `ocsp_stapling`
|
||||
Can be set to `off` to disable OCSP stapling. Useful in environments where responders are not reachable due to firewalls.
|
||||
|
||||
|
||||
##### `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:
|
||||
|
||||
- **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.
|
||||
- **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).
|
||||
|
||||
|
||||
|
||||
## 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.
|
||||
|
||||
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.
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
Use the [`caddy adapt`](/docs/command-line#caddy-adapt) command to find the listen address for the servers in your Caddyfile.
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
For example, to configure different options for the servers on ports `:80` and `:443`, you would specify two `servers` blocks:
|
||||
|
||||
```caddy
|
||||
{
|
||||
servers :443 {
|
||||
listener_wrappers {
|
||||
http_redirect
|
||||
tls
|
||||
}
|
||||
}
|
||||
|
||||
servers :80 {
|
||||
protocols {
|
||||
allow_h2c
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
##### `listener_wrappers`
|
||||
|
||||
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.
|
||||
|
||||
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->HTTPS redirect on the same port but using the `https://` scheme. It must be placed _before_ the `tls` listener wrapper. For example:
|
||||
|
||||
```caddy-d
|
||||
listener_wrappers {
|
||||
http_redirect
|
||||
tls
|
||||
}
|
||||
```
|
||||
|
||||
Another example, assuming you have the [`proxy_protocol`](/docs/json/apps/http/servers/listener_wrappers/proxy_protocol/) plugin installed, which must be used _before_ the `tls` listener wrapper:
|
||||
|
||||
```caddy-d
|
||||
listener_wrappers {
|
||||
proxy_protocol {
|
||||
timeout 2s
|
||||
allow 192.168.86.1/24 192.168.86.1/24
|
||||
}
|
||||
tls
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
##### `timeouts`
|
||||
|
||||
- **read_body** is a [duration value](/docs/conventions#durations) that sets how long to allow a read from a client's upload. Setting this to a short, non-zero value can mitigate slowloris attacks, but may also affect legitimately slow clients. Defaults to no timeout.
|
||||
|
||||
- **read_header** is a [duration value](/docs/conventions#durations) that sets how long to allow a read from a client's request headers. Defaults to no timeout.
|
||||
|
||||
- **write** is a [duration value](/docs/conventions#durations) that sets how long to allow a write to a client. Note that setting this to a small value when serving large files may negatively affect legitimately slow clients. Defaults to no timeout.
|
||||
|
||||
- **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.
|
||||
|
||||
|
||||
##### `max_header_size`
|
||||
|
||||
The maximum size to parse from a client's HTTP request headers. It accepts all formats supported by [go-humanize](https://github.com/dustin/go-humanize/blob/master/bytes.go).
|
||||
|
||||
|
||||
##### `log_credentials`
|
||||
|
||||
Since Caddy v2.5, by default, headers with potentially sensitive information (`Cookie`, `Set-Cookie`, `Authorization` and `Proxy-Authorization`) will be logged with empty values in access logs (see the [`log` directive](/docs/caddyfile/directives/log)).
|
||||
|
||||
If you wish to _not_ have these headers redacted, you may enable the `log_credentials` option.
|
||||
|
||||
|
||||
##### `protocols`
|
||||
|
||||
The space-separated list of HTTP protocols to support. Accepted values are: `h1 h2 h2c h3` for HTTP/1.1, HTTP/2, HTTP/2 over cleartext, and HTTP/3, respectively. Default: `h1 h2 h3`.
|
||||
|
||||
Currently, enabling HTTP/2 (including H2C) necessarily implies enabling HTTP/1.1 because the Go standard library does not let us disable HTTP/1.1 when using its HTTP server. However, either HTTP/1.1 or HTTP/3 can be enabled independently.
|
||||
|
||||
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.
|
||||
|
||||
##### `strict_sni_host`
|
||||
|
||||
Enabling this requires that a request's `Host` header matches the value of the `ServerName` sent by the client's TLS ClientHello, a necessary safeguard when using TLS client authentication. If there's a mismatch, HTTP status `421 Misdirected Request` response is written to the client.
|
||||
|
||||
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.
|
||||
|
||||
##### `metrics`
|
||||
|
||||
(EXPERIMENTAL: This option may change or be removed in the future.)
|
||||
|
||||
Enables [Prometheus metrics](/docs/metrics) for the server.
|
||||
|
||||
## PKI Options
|
||||
|
||||
The PKI (Public Key Infrastructure) app is the foundation for Caddy's [Local HTTPS](/docs/automatic-https#local-https) and [ACME server](/docs/caddyfile/directives/acme_server) features. The app defines certificate authorities (CAs) which are capable of signing certificates.
|
||||
|
||||
The default CA ID is `local`. If the ID is omitted when configuring the `ca`, then `local` is assumed.
|
||||
|
||||
##### `name`
|
||||
The user-facing name of the certificate authority. Default: `Caddy Local Authority`
|
||||
|
||||
##### `root_cn`
|
||||
The name to put in the CommonName field of the root certificate. Default: `{pki.ca.name} - {time.now.year} ECC Root`
|
||||
|
||||
##### `intermediate_cn`
|
||||
The name to put in the CommonName field of the intermediate certificates. Default: `{pki.ca.name} - ECC Intermediate`
|
||||
|
||||
##### `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.
|
||||
|
||||
- **format** is the format in which the certificate and private key are provided. Currently, only `pem_file` is supported, which is the default, so this field is optional.
|
||||
- **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.
|
||||
|
||||
##### `intermediate`
|
||||
A key pair (certificate and private key) to use as the intermediate for the CA. If not specified, one will be generated and managed automatically.
|
||||
|
||||
- **format** is the format in which the certificate and private key are provided. Currently, only `pem_file` is supported, which is the default, so this field is optional.
|
||||
- **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.
|
||||
|
||||
|
||||
## Event Options
|
||||
|
||||
Caddy modules emit events when interesting things happen (or are about to happen).
|
||||
|
||||
##### `on`
|
||||
Binds an event handler to the named event. Specify the name of the event handler module, followed by its configuration.
|
||||
|
||||
For example, to run a command after a certificate is obtained ([third-party plugin <img src="/resources/images/external-link.svg" class="external-link">](https://github.com/mholt/caddy-events-exec) required):
|
||||
|
||||
```caddy-d
|
||||
on cert_obtained exec systemctl reload mydaemon
|
||||
```
|
210
src/docs/markdown/caddyfile/patterns.md
Normal file
210
src/docs/markdown/caddyfile/patterns.md
Normal file
|
@ -0,0 +1,210 @@
|
|||
---
|
||||
title: Common Caddyfile Patterns
|
||||
---
|
||||
|
||||
# Common Caddyfile Patterns
|
||||
|
||||
This page demonstrates a few complete and minimal Caddyfile configurations for common use cases. These can be helpful starting points for your own Caddyfile documents.
|
||||
|
||||
These are not drop-in solutions; you will have to customize your domain name, ports/sockets, directory paths, etc. They are intended to illustrate some of the most common configuration patterns.
|
||||
|
||||
#### Menu
|
||||
|
||||
- [Static file server](#static-file-server)
|
||||
- [Reverse proxy](#reverse-proxy)
|
||||
- [PHP](#php)
|
||||
- [Redirect `www.` subdomain](#redirect-www-subdomain)
|
||||
- [Trailing slashes](#trailing-slashes)
|
||||
- [Wildcard certificates](#wildcard-certificates)
|
||||
- [Single-page apps (SPAs)](#single-page-apps-spas)
|
||||
|
||||
|
||||
## Static file server
|
||||
|
||||
```caddy
|
||||
example.com {
|
||||
root * /var/www
|
||||
file_server
|
||||
}
|
||||
```
|
||||
|
||||
As usual, the first line is the site address. The [`root` directive](/docs/caddyfile/directives/root) specifies the path to the root of the site (the `*` means to match all requests, so as to disambiguate from a [path matcher](/docs/caddyfile/matchers#path-matchers))—change the path to your site if it isn't the current working directory. Finally, we enable the [static file server](/docs/caddyfile/directives/file_server).
|
||||
|
||||
|
||||
## Reverse proxy
|
||||
|
||||
Proxy all requests:
|
||||
|
||||
```caddy
|
||||
example.com {
|
||||
reverse_proxy localhost:5000
|
||||
}
|
||||
```
|
||||
|
||||
Only proxy requests having a path starting with `/api/` and serve static files for everything else:
|
||||
|
||||
```caddy
|
||||
example.com {
|
||||
root * /var/www
|
||||
reverse_proxy /api/* localhost:5000
|
||||
file_server
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## PHP
|
||||
|
||||
With a PHP FastCGI service running, something like this works for most modern PHP apps:
|
||||
|
||||
```caddy
|
||||
example.com {
|
||||
root * /srv/public
|
||||
encode gzip
|
||||
php_fastcgi localhost:9000
|
||||
file_server
|
||||
}
|
||||
```
|
||||
|
||||
Customize the site root accordingly; this example assumes that your PHP app's webroot is within a `public` directory—requests for files that exist on disk will be served with `file_server`, and anything else will be routed to `index.php` for handling by the PHP app.
|
||||
|
||||
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).
|
||||
|
||||
|
||||
## Redirect `www.` subdomain
|
||||
|
||||
To **add** the `www.` subdomain with an HTTP redirect:
|
||||
|
||||
```caddy
|
||||
example.com {
|
||||
redir https://www.{host}{uri}
|
||||
}
|
||||
|
||||
www.example.com {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
To **remove** it:
|
||||
|
||||
```caddy
|
||||
www.example.com {
|
||||
redir https://example.com{uri}
|
||||
}
|
||||
|
||||
example.com {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
To remove it for **multiple domains** at once; this uses the `{labels.*}` placeholders which are the parts of the hostname, 0-indexed from the right (e.g. 0=com, 1=example-one, 2=www):
|
||||
|
||||
```caddy
|
||||
www.example-one.com, www.example-two.com {
|
||||
redir https://{labels.1}.{labels.0}{uri}
|
||||
}
|
||||
|
||||
example-one.com, example-two.com {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Trailing slashes
|
||||
|
||||
You will not usually need to configure this yourself; the [`file_server` directive](/docs/caddyfile/directives/file_server) will automatically add or remove trailing slashes from requests by way of HTTP redirects, depending on whether the requested resource is a directory or file, respectively.
|
||||
|
||||
However, if you need to, you can still enforce trailing slashes with your config. There are two ways to do it: internally or externally.
|
||||
|
||||
### Internal enforcement
|
||||
|
||||
This uses the [`rewrite`](/docs/caddyfile/directives/rewrite) directive. Caddy will rewrite the URI internally to add or remove the trailing slash:
|
||||
|
||||
```caddy
|
||||
example.com {
|
||||
rewrite /add /add/
|
||||
rewrite /remove/ /remove
|
||||
}
|
||||
```
|
||||
|
||||
Using a rewrite, requests with and without the trailing slash will be the same.
|
||||
|
||||
|
||||
### External enforcement
|
||||
|
||||
This uses the [`redir`](/docs/caddyfile/directives/redir) directive. Caddy will ask the browser to change the URI to add or remove the trailing slash:
|
||||
|
||||
```caddy
|
||||
example.com {
|
||||
redir /add /add/
|
||||
redir /remove/ /remove
|
||||
}
|
||||
```
|
||||
|
||||
Using a redirect, the client will have to re-issue the request, enforcing a single acceptable URI for a resource.
|
||||
|
||||
|
||||
|
||||
## Wildcard certificates
|
||||
|
||||
If you need to serve multiple subdomains with the same wildcard certificate, the best way to handle them is with a Caddyfile like this, making use of the [`handle`](/docs/caddyfile/directives/handle) directive and [`host`](/docs/caddyfile/matchers#host) matchers:
|
||||
|
||||
```caddy
|
||||
*.example.com {
|
||||
tls {
|
||||
dns <provider_name> [<params...>]
|
||||
}
|
||||
|
||||
@foo host foo.example.com
|
||||
handle @foo {
|
||||
respond "Foo!"
|
||||
}
|
||||
|
||||
@bar host bar.example.com
|
||||
handle @bar {
|
||||
respond "Bar!"
|
||||
}
|
||||
|
||||
# Fallback for otherwise unhandled domains
|
||||
handle {
|
||||
abort
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note that you must enable the [ACME DNS challenge](/docs/automatic-https#dns-challenge) to have Caddy automatically manage wildcard certificates.
|
||||
|
||||
|
||||
|
||||
## Single-page apps (SPAs)
|
||||
|
||||
When a web page does its own routing, servers may receive lots of requests for pages that don't exist server-side, but which are renderable client-side as long as the singular index file is served instead. Web applications architected like this are known as SPAs, or single-page apps.
|
||||
|
||||
The main idea is to have the server "try files" to see if the requested file exists server-side, and if not, fall back to an index file where the client does the routing (usually with client-side JavaScript): `try_files {path} /index.html`
|
||||
|
||||
A typical SPA config usually looks something like this:
|
||||
|
||||
```caddy
|
||||
example.com {
|
||||
root * /path/to/site
|
||||
encode gzip
|
||||
try_files {path} /index.html
|
||||
file_server
|
||||
}
|
||||
```
|
||||
|
||||
If your SPA is coupled with an API or other server-side-only endpoints, you will want to use `handle` blocks to treat them exclusively:
|
||||
|
||||
```caddy
|
||||
example.com {
|
||||
encode gzip
|
||||
|
||||
handle /api/* {
|
||||
reverse_proxy backend:8000
|
||||
}
|
||||
|
||||
handle {
|
||||
root * /path/to/site
|
||||
try_files {path} /index.html
|
||||
file_server
|
||||
}
|
||||
}
|
||||
```
|
203
src/docs/markdown/caddyfile/spec.md
Normal file
203
src/docs/markdown/caddyfile/spec.md
Normal file
|
@ -0,0 +1,203 @@
|
|||
---
|
||||
title: Caddyfile Spec
|
||||
---
|
||||
|
||||
TODO: this page is unfinished
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
||||
# Caddyfile Specification
|
||||
|
||||
This page describes the syntax of the Caddyfile. If it is your first time writing a Caddyfile, try the <a href="/v1/tutorial/caddyfile">Caddyfile primer</a> tutorial instead. This page is not beginner-friendly; it is technical and kind of boring.
|
||||
|
||||
Although this article is verbose, the Caddyfile is designed to be easily readable and writable by humans. You will find that it is easy to remember, not cumbersome, and flows off the fingers.
|
||||
|
||||
The term "Caddyfile" often refers to a file, but more generally means a blob of Caddy configuration text. A Caddyfile can be used to configure any Caddy server type: HTTP, DNS, etc. The basic structure and syntax of the Caddyfile is the same for all server types, but semantics change. Because of this variability, this document treats the Caddyfile only as the generic configuration syntax as it applies to all server types. Caddyfile documentation for specific types may be found within their respective docs. For instance, the HTTP server <a href="/v1/docs/http-caddyfile">documents the semantics of its Caddyfile</a>.
|
||||
|
||||
#### Topics
|
||||
|
||||
1. [File format & encoding](#)
|
||||
2. [Lexical syntax](#)
|
||||
3. [Structure](#)
|
||||
4. [Labels](#)
|
||||
5. [Directives](#)
|
||||
6. [Environment variables](#)
|
||||
7. [Import](#)
|
||||
8. [Reusable snippets](#)
|
||||
9. [Examples](#)
|
||||
|
||||
|
||||
## File Format & Encoding
|
||||
|
||||
The Caddyfile is plain Unicode text encoded with UTF-8. Each code point is distinct; specifically, lowercase and uppercase characters are different. A leading byte order mark (0xFEFF), if present, will be ignored.
|
||||
|
||||
|
||||
|
||||
## Lexical Syntax
|
||||
|
||||
A <b>token</b> is a sequence of whitespace-delimited characters in the Caddyfile. A token that starts with quotes <code>"</code> is read literally (including whitespace) until the next instance of quotes <code>"</code> that is not escaped. Quote literals may be escaped with a backslash like so: <code>\"</code>. Only quotes are escapable. <!-- Those stupid --> “Smart quotes” are not valid as quotes.
|
||||
|
||||
<b>Lines</b> are delimited with the <code>\n</code> (newline) character only. Carriage return <code>\r</code> is discarded unless quoted. Blank, unquoted lines are allowed and ignored.
|
||||
|
||||
<b>Comments</b> are discarded by the lexer. Comments begin with an unquoted hash <code>#</code> and continue to the end of the line. Comments may start a line or appear in the middle of a line as part of an unquoted token. For the purposes of this document, commented and blank lines are no longer considered.
|
||||
|
||||
Tokens are then evaluated by the parser for structure.
|
||||
|
||||
## Structure
|
||||
|
||||
A Caddyfile has no global scope or inheritence between separate blocks. The most global unit of the Caddyfile is an <b>entry</b>. An entry consists of a list of labels and a definition associated with those labels. A <b>label</b> is a string identifier, and a <b>definition</b> is a body (one or more lines) of tokens grouped together in a <i>block</i>:
|
||||
|
||||
<code class="block"><span class="cf-label-bg">list of labels</span>
|
||||
<span class="cf-block-bg">definition (block)</span></code>
|
||||
|
||||
A Caddyfile with <i>only one</i> entry may consist simply of the label line(s) followed by the definition on the next line(s), as shown above. However, a Caddyfile with <i>more than one</i> entry <b>must</b> enclose each definition in curly braces <code>{ }</code>. The opening curly brace <code>{</code> must be at the end of the label line, and the closing curly brace <code>}</code> must be the only token on its line:
|
||||
|
||||
<code class="block"><span class="cf-label-bg">list of labels</span> <span class="cf-bigbrace">{</span>
|
||||
<span class="cf-block-bg indent">definition (block)</span>
|
||||
<span class="cf-bigbrace">}</span>
|
||||
<span class="cf-label-bg">list of labels</span> <span class="cf-bigbrace">{</span>
|
||||
<span class="cf-block-bg indent">definition (block)</span>
|
||||
<span class="cf-bigbrace">}</span></code>
|
||||
<p>
|
||||
Consistent tab indentation is encouraged within blocks enclosed by curly braces.
|
||||
</p>
|
||||
<p>
|
||||
<b>The first line of a Caddyfile is always a label line.</b> Comment lines, empty lines, and <a href="/v1/docs/import">import</a> lines are the exceptions.
|
||||
</p>
|
||||
|
||||
<h3 id="labels">Labels</h3>
|
||||
<p>
|
||||
Labels are the only tokens that appear outside of blocks (with one exception being the <a href="/v1/docs/import">import</a> directive). A label line may have just one label:
|
||||
</p>
|
||||
<code class="block"><span class="cf-addr">label</span></code>
|
||||
<p>
|
||||
or several labels, separated by spaces:
|
||||
</p>
|
||||
<code class="block"><span class="cf-addr">label1 label2</span> ...</code>
|
||||
<p>
|
||||
If many labels are to head a block, the labels may be suffixed with a comma. A comma-suffixed label may be followed by a newline, in which case the next line will be considered part of the same line:
|
||||
</p>
|
||||
<code class="block"><span class="cf-addr">label1</span>,
|
||||
<span class="cf-addr">label2</span></code>
|
||||
<p>
|
||||
Mixing of these patterns is valid (but discouraged), as long as the last label of the line has a comma if the next line is to continue the list of labels:
|
||||
</p>
|
||||
<code class="block"><span class="cf-addr">label1 label2</span>,
|
||||
<span class="cf-addr">label3</span>, <span class="cf-addr">label4</span>,
|
||||
<span class="cf-addr">label5</span></code>
|
||||
<p>
|
||||
A definition with multiple labels is replicated across each label as if they had been defined separately but with the same definition.
|
||||
</p>
|
||||
|
||||
<h3 id="directives">Directives</h3>
|
||||
<p>
|
||||
The body of the definition follows label lines. The first token of each line in a definition body is a <b>directive</b>. Every token <i>after</i> the directive on the same line is an <b>argument</b>. Arguments are optional:
|
||||
</p>
|
||||
<code class="block"><span class="cf-dir">directive1</span>
|
||||
<span class="cf-dir">directive2</span> <span class="cf-arg">arg1 arg2</span>
|
||||
<span class="cf-dir">directive3</span> <span class="cf-arg">arg3</span></code>
|
||||
<p>
|
||||
Commas are not acceptable delimiters for arguments; they will be treated as part of the argument value. Arguments are delimited solely by same-line whitespace.
|
||||
</p>
|
||||
<p>
|
||||
Directives may span multiple lines by opening a block. Blocks are enclosed by curly braces <code>{ }</code>. The opening curly brace <code>{</code> must be at the end of the directive's first line, and the closing curly brace <code>}</code> must be the only token on its line:
|
||||
</p>
|
||||
<code class="block"><span class="cf-dir">directive</span> {
|
||||
...
|
||||
}</code>
|
||||
<p>
|
||||
Within a directive block, the first token of each line may be considered a <b>subdirective</b> or <b>property</b>, depending on how it is used (other terms may be applied). And as before, they can have arguments:
|
||||
</p>
|
||||
<code class="block"><span class="cf-dir">directive</span> <span class="cf-arg">arg1</span> {
|
||||
<span class="cf-subdir">subdir</span> arg2 arg3
|
||||
...
|
||||
}</code>
|
||||
<p>
|
||||
Subdirectives cannot open new blocks. In other words, nested directive blocks are not supported. If a directive block is empty, the curly braces should be omitted entirely.
|
||||
</p>
|
||||
|
||||
<h3 id="env">Environment Variables</h3>
|
||||
<p>
|
||||
Any token (label, directive, argument, etc.) may contain or consist solely of an environment variable, which takes the Unix form or Windows form, enclosed in curly braces <code>{ }</code> without extra whitespace:
|
||||
</p>
|
||||
<code class="block"><span class="cf-addr">label_{$ENV_VAR_1}</span>
|
||||
<span class="cf-dir">directive</span> <span class="cf-arg">{%ENV_VAR_2%}</span></code>
|
||||
<p>
|
||||
Either form works on any OS. A single environment variable does not expand out into multiple tokens, arguments, or values.
|
||||
</p>
|
||||
|
||||
<h3 id="import">Import</h3>
|
||||
<p>
|
||||
The <a href="/v1/docs/import">import</a> directive is a special case, because it can appear outside a definition block. The consequence of this is that no label can take on the value of "import".
|
||||
</p>
|
||||
<p>
|
||||
Where an import line is, that line will be replaced with the contents of the imported file, unmodified. See the <a href="/v1/docs/import">import docs</a> for more information.
|
||||
</p>
|
||||
|
||||
<h3 id="snippets">Reusable Snippets</h3>
|
||||
<p>
|
||||
You can define snippets to be reused later in your Caddyfile by defining a block with a single-token label surrounded by parentheses:
|
||||
</p>
|
||||
<code class="block"><span class="cf-addr">(mysnippet)</span> {
|
||||
...
|
||||
}</code>
|
||||
<p>
|
||||
Then you can invoke the snippet with the <code>import</code> directive:
|
||||
</p>
|
||||
<p>
|
||||
<code class="block"><span class="cf-dir">import</span> <span class="cf-arg">mysnippet</span></code>
|
||||
|
||||
<h3 id="examples">Examples</h3>
|
||||
<p>
|
||||
A very simple Caddyfile with only one entry:
|
||||
<code class="block"><span class="cf-addr">label1</span>
|
||||
|
||||
<span class="cf-dir">directive1</span> <span class="cf-arg">argument1</span>
|
||||
<span class="cf-dir">directive2</span></code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Appending the prior example with another entry introduces the need for curly braces:
|
||||
<code class="block"><span class="cf-addr">label1</span> {
|
||||
<span class="cf-dir">directive1</span> <span class="cf-arg">arg1</span>
|
||||
<span class="cf-dir">directive2</span>
|
||||
}
|
||||
<span class="cf-addr">label2</span>, <span class="cf-addr">label3</span> {
|
||||
<span class="cf-dir">directive3</span> <span class="cf-arg">arg2</span>
|
||||
<span class="cf-dir">directive4</span> <span class="cf-arg">arg3</span> <span class="cf-arg">arg4</span>
|
||||
}
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Some people prefer to always use braces even if there's just one entry; this is fine, but unnecessary:
|
||||
<code class="block"><span class="cf-addr">label1</span> {
|
||||
<span class="cf-dir">directive1</span> <span class="cf-arg">arg1</span>
|
||||
<span class="cf-dir">directive2</span>
|
||||
}</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Example in which a directive opens a block:
|
||||
<code class="block"><span class="cf-addr">label1</span>
|
||||
|
||||
<span class="cf-dir">directive</span> <span class="cf-arg">arg1</span> {
|
||||
<span class="cf-subdir">subdir</span> arg2 arg3
|
||||
}
|
||||
<span class="cf-dir">directive</span> <span class="cf-arg">arg4</span></code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Similarly, but in an indented definition body, and with a comment:
|
||||
<code class="block"><span class="cf-addr">label1</span> {
|
||||
<span class="cf-dir">directive1</span> <span class="cf-arg">arg1</span>
|
||||
<span class="cf-dir">directive2</span> <span class="cf-arg">arg2</span> {
|
||||
<span class="cf-subdir">subdir1</span> arg3 arg4
|
||||
<span class="cf-subdir">subdir2</span>
|
||||
<span class="cf-comment"># nested blocks not supported</span>
|
||||
}
|
||||
<span class="cf-dir">directive3</span>
|
||||
}</code>
|
||||
</p>
|
594
src/docs/markdown/command-line.md
Normal file
594
src/docs/markdown/command-line.md
Normal file
|
@ -0,0 +1,594 @@
|
|||
---
|
||||
title: "Command Line"
|
||||
---
|
||||
|
||||
# Command Line
|
||||
|
||||
Caddy has a standard unix-like command line interface. Basic usage is:
|
||||
|
||||
```
|
||||
caddy <command> [<args...>]
|
||||
```
|
||||
|
||||
The `<carets>` indicate parameters that get replaced by your input.
|
||||
|
||||
The`[brackets]` indicate optional parameters.
|
||||
|
||||
The ellipses `...` indicates a continuation, i.e. one or more parameters.
|
||||
|
||||
**Quick start: `caddy`, `caddy help`, or `man caddy` (if installed)**
|
||||
|
||||
---
|
||||
|
||||
- **[caddy adapt](#caddy-adapt)**
|
||||
Adapts a config document to native JSON
|
||||
|
||||
- **[caddy build-info](#caddy-build-info)**
|
||||
Prints build information
|
||||
|
||||
- **[caddy completion](#caddy-completion)**
|
||||
Generate shell completion script
|
||||
|
||||
- **[caddy environ](#caddy-environ)**
|
||||
Prints the environment
|
||||
|
||||
- **[caddy file-server](#caddy-file-server)**
|
||||
A simple but production-ready file server
|
||||
|
||||
- **[caddy fmt](#caddy-fmt)**
|
||||
Formats a Caddyfile
|
||||
|
||||
- **[caddy hash-password](#caddy-hash-password)**
|
||||
Hashes a password and outputs base64
|
||||
|
||||
- **[caddy help](#caddy-help)**
|
||||
View help for caddy commands
|
||||
|
||||
- **[caddy list-modules](#caddy-list-modules)**
|
||||
Lists the installed Caddy modules
|
||||
|
||||
- **[caddy manpage](#caddy-manpage)**
|
||||
Generate manpages
|
||||
|
||||
- **[caddy reload](#caddy-reload)**
|
||||
Changes the config of the running Caddy process
|
||||
|
||||
- **[caddy respond](#caddy-respond)**
|
||||
A quick-and-clean, hard-coded HTTP server for development and testing
|
||||
|
||||
- **[caddy reverse-proxy](#caddy-reverse-proxy)**
|
||||
A simple but production-ready HTTP(S) reverse proxy
|
||||
|
||||
- **[caddy run](#caddy-run)**
|
||||
Starts the Caddy process in the foreground
|
||||
|
||||
- **[caddy start](#caddy-start)**
|
||||
Starts the Caddy process in the background
|
||||
|
||||
- **[caddy stop](#caddy-stop)**
|
||||
Stops the running Caddy process
|
||||
|
||||
- **[caddy trust](#caddy-trust)**
|
||||
Installs a certificate into local trust store(s)
|
||||
|
||||
- **[caddy untrust](#caddy-untrust)**
|
||||
Untrusts a certificate from local trust store(s)
|
||||
|
||||
- **[caddy upgrade](#caddy-upgrade)**
|
||||
Upgrades Caddy to the latest release
|
||||
|
||||
- **[caddy add-package](#caddy-add-package)**
|
||||
Upgrades Caddy to the latest release, with additional plugins added
|
||||
|
||||
- **[caddy remove-package](#caddy-remove-package)**
|
||||
Upgrades Caddy to the latest release, with some plugins removed
|
||||
|
||||
- **[caddy validate](#caddy-validate)**
|
||||
Tests whether a config file is valid
|
||||
|
||||
- **[caddy version](#caddy-version)**
|
||||
Prints the version
|
||||
|
||||
- **[Signals](#signals)**
|
||||
How Caddy handles signals
|
||||
|
||||
- **[Exit codes](#exit-codes)**
|
||||
Emitted when the Caddy process exits
|
||||
|
||||
## Subcommands
|
||||
|
||||
|
||||
### `caddy adapt`
|
||||
|
||||
<pre><code class="cmd bash">caddy adapt
|
||||
[--config <path>]
|
||||
[--adapter <name>]
|
||||
[--pretty]
|
||||
[--validate]</code></pre>
|
||||
|
||||
Adapts a configuration to Caddy's native JSON config structure and writes the output to stdout, along with any warnings to stderr, then exits.
|
||||
|
||||
`--config` is the path to the config file. If omitted, assumes `Caddyfile` in current directory if it exists; otherwise, this flag is required.
|
||||
|
||||
`--adapter` specifies the config adapter to use; default is `caddyfile`.
|
||||
|
||||
`--pretty` will format the output with indentation for human readability.
|
||||
|
||||
`--validate` will load and provision the adapted configuration to check for validity (but it will not actually start running the config).
|
||||
|
||||
Note that a config which is successfully adapted may still fail validation. For an example of this, use this Caddyfile:
|
||||
|
||||
```caddy
|
||||
localhost
|
||||
|
||||
tls cert_notexist.pem key_notexist.pem
|
||||
```
|
||||
|
||||
Try adapting it:
|
||||
|
||||
<pre><code class="cmd bash">caddy adapt --config Caddyfile</code></pre>
|
||||
|
||||
It succeeds without error. Then try:
|
||||
|
||||
<pre><code class="cmd"><span class="bash">caddy adapt --config Caddyfile --validate</span>
|
||||
adapt: validation: loading app modules: module name 'tls': provision tls: loading certificates: open cert_notexist.pem: no such file or directory
|
||||
</code></pre>
|
||||
|
||||
Even though that Caddyfile can be adapted to JSON without errors, the actual certificate and/or key files do not exist, so validation fails because that error arises during the provisioning phase. Thus, validation is a stronger error check than adaptation is.
|
||||
|
||||
#### Example
|
||||
|
||||
To adapt a Caddyfile to JSON that you can easily read and tweak manually:
|
||||
|
||||
<pre><code class="cmd bash">caddy adapt --config /path/to/Caddyfile --pretty</code></pre>
|
||||
|
||||
|
||||
|
||||
### `caddy build-info`
|
||||
|
||||
<pre><code class="cmd bash">caddy build-info</code></pre>
|
||||
|
||||
Prints information provided by Go about the build (main module path, package versions, module replacements).
|
||||
|
||||
|
||||
|
||||
|
||||
### `caddy completion`
|
||||
|
||||
<pre><code class="cmd bash">caddy completion [bash|zsh|fish|powershell]</code></pre>
|
||||
|
||||
Generates shell completion scripts. This allows you to get tab-complete or auto-complete (or similar, depending on your shell) when typing `caddy` commands.
|
||||
|
||||
To get instructions for installing this script into your specific shell, run `caddy help completion` or `caddy completion -h`.
|
||||
|
||||
|
||||
|
||||
### `caddy environ`
|
||||
|
||||
<pre><code class="cmd bash">caddy environ</code></pre>
|
||||
|
||||
Prints the environment as seen by caddy, then exits. Can be useful when debugging init systems or process manager units like systemd.
|
||||
|
||||
|
||||
|
||||
|
||||
### `caddy file-server`
|
||||
|
||||
<pre><code class="cmd bash">caddy file-server
|
||||
[--root <path>]
|
||||
[--listen <addr>]
|
||||
[--domain <example.com>]
|
||||
[--browse]
|
||||
[--templates]
|
||||
[--access-log]
|
||||
[--debug]</code></pre>
|
||||
|
||||
Spins up a simple but production-ready static file server.
|
||||
|
||||
`--root` specifies the root file path. Default is the current working directory.
|
||||
|
||||
`--listen` accepts a listener address. Default is `:80`, unless `--domain` is used, then `:443` will be the default.
|
||||
|
||||
`--domain` will only serve files through that hostname, and Caddy will attempt to serve it over HTTPS, so make sure any public DNS is configured properly first if it's a public domain name. The default port will be changed to 443.
|
||||
|
||||
`--browse` will enable directory listings if a directory without an index file is requested.
|
||||
|
||||
`--templates` will enable template rendering.
|
||||
|
||||
`--access-log` enables the request/access log.
|
||||
|
||||
`--debug` enables verbose logging.
|
||||
|
||||
This command disables the admin API, making it easier to run multiple instances on a local development machine.
|
||||
|
||||
|
||||
|
||||
|
||||
### `caddy fmt`
|
||||
|
||||
<pre><code class="cmd bash">caddy fmt [--overwrite] [--diff] [<path>]</code></pre>
|
||||
|
||||
Formats or prettifies a Caddyfile, then exits. The result is printed to stdout unless `--overwrite` is used.
|
||||
|
||||
`<path>` specifies the path to the Caddyfile. If `-`, the input is read from stdin. If omitted, a file named Caddyfile in the current directory is assumed instead.
|
||||
|
||||
`--overwrite` causes the result to be written to the input file instead of being printed to the terminal. If the input is not a regular file, this flag has no effect.
|
||||
|
||||
`--diff` causes the output to be compared against the input, and lines will be prefixed with `-` and `+` where they differ. Note that unchanges lines are prefixed with two spaces for alignment, and that this is not a valid patch format; it's just meant as a visual tool.
|
||||
|
||||
|
||||
|
||||
|
||||
### `caddy hash-password`
|
||||
|
||||
<pre><code class="cmd bash">caddy hash-password
|
||||
[--plaintext <password>]
|
||||
[--algorithm <name>]
|
||||
[--salt <string>]</code></pre>
|
||||
|
||||
Hashes a password and writes the output to stdout, then exits.
|
||||
|
||||
`--plaintext` is the plaintext form of the password. If omitted, interactive mode will be assumed and the user will be shown a prompt to enter the password manually.
|
||||
|
||||
`--algorithm` may be bcrypt or any installed hash algorithm. Default is bcrypt.
|
||||
|
||||
`--salt` is used only if the algorithm requires an external salt (like scrypt).
|
||||
|
||||
|
||||
|
||||
|
||||
### `caddy help`
|
||||
|
||||
<pre><code class="cmd bash">caddy help [<command>]</code></pre>
|
||||
|
||||
Prints CLI help text, optionally for a specific subcommand, then exits.
|
||||
|
||||
|
||||
|
||||
### `caddy list-modules`
|
||||
|
||||
<pre><code class="cmd bash">caddy list-modules
|
||||
[--packages]
|
||||
[--versions]
|
||||
[--skip-standard]</code></pre>
|
||||
|
||||
Prints the Caddy modules that are installed, optionally with package and/or version information from their associated Go modules, then exits.
|
||||
|
||||
In some scripted situations, it may be redundant to print all of the standard modules as well, so you may use `--skip-standard` to omit those from the output.
|
||||
|
||||
NOTE: Due to [a bug in Go](https://github.com/golang/go/issues/29228), version information is only available if Caddy is built as a dependency and not as the main module. Use [xcaddy](/docs/build#xcaddy) to make this easier.
|
||||
|
||||
|
||||
|
||||
### `caddy manpage`
|
||||
|
||||
<pre><code class="cmd bash">caddy manpage
|
||||
--directory <path></code></pre>
|
||||
|
||||
Generates manual/documentation pages for Caddy commands and writes them to the directory at the specified path. The output of this command can be read by the `man` command.
|
||||
|
||||
`--directory` (required) is the path to the directory into which to write the man pages. It will be created if it does not exist.
|
||||
|
||||
Once generated, the manual pages generally need to be installed. This procedure varies by platform, but on typical Linux systems, it's something like this:
|
||||
|
||||
<pre><code class="cmd"><b>$ caddy manpage --directory man
|
||||
$ gzip -r man/
|
||||
$ sudo cp man/* /usr/share/man/man8/
|
||||
$ sudo mandb
|
||||
</b></code></pre>
|
||||
|
||||
Then you can run `man caddy` (or `man caddy-*` for subcommands) to read documentation in your terminal.
|
||||
|
||||
Manual pages are separate documentation from what is on our website. Our website has more comprehensive documentation that is updated often.
|
||||
|
||||
|
||||
|
||||
### `caddy reload`
|
||||
|
||||
<pre><code class="cmd bash">caddy reload
|
||||
[--config <path>]
|
||||
[--adapter <name>]
|
||||
[--address <interface>]
|
||||
[--force]</code></pre>
|
||||
|
||||
Gives the running Caddy instance a new configuration. This has the same effect as POSTing a document to the [/load endpoint](/docs/api#post-load), but this command is convenient for simple workflows revolving around config files. Compared to the `stop`, `start`, and `run` commands, this single command is the correct, semantic way to change/reload the running configuration.
|
||||
|
||||
Because this command uses the API, the admin endpoint must not be disabled.
|
||||
|
||||
`--config` is the config file to apply. If `-`, the config is read from stdin. If not specified, it will try a file called `Caddyfile` in the current working directory and, if it exists, it will adapt it using the `caddyfile` config adapter; otherwise, it is an error if there is no config file to load.
|
||||
|
||||
`--adapter` specifies a config adapter to use, if any.
|
||||
|
||||
`--address` needs to be used if the admin endpoint is not listening on the default address and if it is different from the address in the provided config file. Note that only TCP addresses are supported at this time.
|
||||
|
||||
`--force` will cause a reload to happen even if the specified config is the same as what Caddy is already running. Can be useful to force Caddy to reprovision its modules, which can have side-effects, for example: reloading manually-loaded TLS certificates.
|
||||
|
||||
|
||||
### `caddy respond`
|
||||
|
||||
<pre><code class="cmd bash">caddy respond
|
||||
[--status <code>]
|
||||
[--header "<Field>: <value>"]
|
||||
[--body <content>]
|
||||
[--listen <addr>]
|
||||
[--access-log]
|
||||
[--debug]
|
||||
[<status|body>]</code></pre>
|
||||
|
||||
|
||||
Starts one or more simple, hard-coded HTTP servers that are useful for development, staging, and some production use cases. It can be useful for verifying or debugging HTTP clients, scripts, or even load balancers.
|
||||
|
||||
`--status` is the HTTP status code to return.
|
||||
|
||||
`--header` adds an HTTP header; `Field: value` format is expected. This flag can be used multiple times.
|
||||
|
||||
`--body` specifies the response body. Alternatively, the body can be piped from stdin.
|
||||
|
||||
`--listen` is the listener address, which can be any [network address](/docs/conventions#network-addresses) recognized by Caddy, and may include a port range to start multiple servers.
|
||||
|
||||
`--access-log` enables access/request logging.
|
||||
|
||||
`--debug` enables more verbose debug logging.
|
||||
|
||||
With no options specified, this command listens on a random available port and answers HTTP requests with an empty 200 response. The listen address can be customized with the `--listen` flag and will always be printed to stdout. If the listen address includes a port range, multiple servers will be started.
|
||||
|
||||
If a final, unnamed argument is given, it will be treated as a status code (same as the `--status` flag) if it is a 3-digit number. Otherwise, it is used as the response body (same as the `--body` flag). The `--status` and `--body` flags will always override this argument.
|
||||
|
||||
A body may be given in 3 ways: a flag, a final (and unnamed) argument to the command, or piped to stdin (if flag and argument are unset). Limited [template evaluation](https://pkg.go.dev/text/template) is supported on the body, with the following variables:
|
||||
|
||||
Variable | Description
|
||||
---------|-------------
|
||||
`.N` | Server number
|
||||
`.Port` | Listener port
|
||||
`.Address` | Listener address
|
||||
|
||||
|
||||
#### Examples
|
||||
|
||||
Empty 200 response on a random port:
|
||||
<pre><code class="cmd bash">caddy respond</code></pre>
|
||||
|
||||
HTTP response with a body:
|
||||
<pre><code class="cmd bash">caddy respond "Hello, world!"</code></pre>
|
||||
|
||||
Multiple servers and templates:
|
||||
<pre><code class="cmd"><b>$ caddy respond --listen :2000-2004 "{{printf "I'm server {{.N}} on port {{.Port}}"}}"</b>
|
||||
|
||||
Server address: [::]:2000
|
||||
Server address: [::]:2001
|
||||
Server address: [::]:2002
|
||||
Server address: [::]:2003
|
||||
Server address: [::]:2004
|
||||
|
||||
<b>$ curl 127.0.0.1:2002</b>
|
||||
I'm server 2 on port 2002</code></pre>
|
||||
|
||||
Pipe in a maintenance page:
|
||||
<pre><code class="cmd bash">cat maintenance.html | caddy respond \
|
||||
--listen :80 \
|
||||
--status 503 \
|
||||
--header "Content-Type: text/html"</code></pre>
|
||||
|
||||
|
||||
### `caddy reverse-proxy`
|
||||
|
||||
<pre><code class="cmd bash">caddy reverse-proxy
|
||||
[--from <addr>]
|
||||
--to <addr>
|
||||
[--change-host-header]
|
||||
[--internal-certs]
|
||||
[--debug]</code></pre>
|
||||
|
||||
Spins up a simple but production-ready HTTP(S) reverse proxy.
|
||||
|
||||
`--from` is the address to proxy from.
|
||||
|
||||
`--to` is the address to proxy to.
|
||||
|
||||
`--change-host-header` will cause Caddy to change the Host header from the incoming value to the address of the upstream.
|
||||
|
||||
`--internal-certs` will cause Caddy to issue certificates using its internal issuer (effectively self-signed) for the domain specified in the `--from` address.
|
||||
|
||||
`--debug` enables verbose logging.
|
||||
|
||||
Both `--from` and `--to` parameters can be URLs, as scheme and domain name will be inferred from the provided URL (paths and query strings ignored). Or they can be a simple network address and not a complete URL.
|
||||
|
||||
This command disables the admin API so it is easier to run multiple instances on a local development machine.
|
||||
|
||||
|
||||
### `caddy run`
|
||||
|
||||
<pre><code class="cmd bash">caddy run
|
||||
[--config <path>]
|
||||
[--adapter <name>]
|
||||
[--pidfile <file>]
|
||||
[--environ]
|
||||
[--envfile <file>]
|
||||
[--resume]
|
||||
[--watch]</code></pre>
|
||||
|
||||
Runs Caddy and blocks indefinitely; i.e. "daemon" mode.
|
||||
|
||||
`--config` specifies an initial config file to immediately load and use. If `-`, the config is read from stdin. If no config is specified, Caddy will run with a blank configuration and use default settings for the [admin API endpoints](/docs/api), which can be used to feed it new configuration. As a special case, if the current working directory has a file called "Caddyfile" and the `caddyfile` config adapter is plugged in (default), then that file will be loaded and used to configure Caddy, even without any command line flags.
|
||||
|
||||
`--adapter` is the name of the config adapter to use when loading the initial config, if any. This flag is not necessary if the `--config` filename starts with "Caddyfile" which assumes the `caddyfile` adapter. Otherwise, this flag is required if the provided config file is not in Caddy's native JSON format. Any warnings will be printed to the log, but beware that any adaptation without errors will immediately be used, even if there are warnings. If you want to review the results of the adaptation first, use the [`caddy adapt`](#caddy-adapt) subcommand.
|
||||
|
||||
`--pidfile` writes the PID to the specified file.
|
||||
|
||||
`--environ` prints out the environment before starting. This is the same as the `caddy environ` command, but does not exit after printing.
|
||||
|
||||
`--envfile` loads environment variables from the specified file, in `KEY=VALUE` format. Comments starting with `#` are supported; keys may be prefixed with `export`; values may be double-quoted (double-quotes within can be escaped); multi-line values are supported.
|
||||
|
||||
`--resume` uses the last loaded configuration that was autosaved, overriding the `--config` flag (if present). Using this flag guarantees config durability through machine reboots or process restarts. It is most useful in [API](/docs/api)-centric deployments.
|
||||
|
||||
`--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">
|
||||
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.
|
||||
</aside>
|
||||
|
||||
|
||||
|
||||
### `caddy start`
|
||||
|
||||
<pre><code class="cmd bash">caddy start
|
||||
[--config <path>]
|
||||
[--adapter <name>]
|
||||
[--envfile <file>]
|
||||
[--pidfile <file>]
|
||||
[--watch]</code></code></pre>
|
||||
|
||||
Same as [`caddy run`](#caddy-run), but in the background. This command only blocks until the background process is running successfully (or fails to run), then returns.
|
||||
|
||||
Note: the flag `--config` doesn't support `-` to read the config from stdin.
|
||||
|
||||
Use of this command is discouraged with system services or on Windows. On Windows, the child process will remain attached to the terminal, so closing the window will forcefully stop Caddy, which is not obvious. Consider running Caddy [as a service](/docs/running) instead.
|
||||
|
||||
Once started, you can use [`caddy stop`](#caddy-stop) or the [`POST /stop`](/docs/api#post-stop) API endpoint to exit the background process.
|
||||
|
||||
|
||||
|
||||
### `caddy stop`
|
||||
|
||||
<pre><code class="cmd bash">caddy stop
|
||||
[--address <interface>]
|
||||
[--config <path> [--adapter <name>]]</code></pre>
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
Stopping (and restarting) the server is orthogonal to config changes. **Do not use the stop command to change configuration in production, unless you want downtime.** Use the [`caddy reload`](#caddy-reload) command instead.
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
Gracefully stops the running Caddy process (other than the process of the stop command) and causes it to exit. It uses the [`POST /stop`](/docs/api#post-stop) endpoint of the admin API to perform a graceful shutdown.
|
||||
|
||||
The address of this request can be customized using the `--address` flag, or from the given `--config`, if the running instance's admin API is not using the default listen address.
|
||||
|
||||
If you want to stop the current configuration but do not want to exit the process, use [`caddy reload`](#caddy-reload) with a blank config, or the [`DELETE /config/`](/docs/api#delete-configpath) endpoint.
|
||||
|
||||
|
||||
### `caddy trust`
|
||||
|
||||
<pre><code class="cmd bash">caddy trust
|
||||
[--ca <id>]
|
||||
[--address <interface>]
|
||||
[--config <path> [--adapter <name>]]</code></pre>
|
||||
|
||||
Installs a root certificate for a CA managed by Caddy's [PKI app](/docs/json/apps/pki/) into local trust stores.
|
||||
|
||||
Caddy will attempt to install its root certificates into the local trust stores automatically when they are first generated, but it might fail if Caddy doesn't have the appropriate permissions to write to the trust store. This command is necessary to pre-install the certificates before using them, if the server process runs as an unprivileged user (such as via systemd). You may need to run this command with `sudo` to unix systems.
|
||||
|
||||
By default, this command installs the root certificate for Caddy's default CA (i.e. "local"). You may specify the ID of another CA with the `--ca` flag.
|
||||
|
||||
This command will attempt to connect to Caddy's [admin API](/docs/api) to fetch the root certificate, using the [`GET /pki/ca/<id>/certificates`](/docs/api#get-pkicaltidgtcertificates) endpoint. You may explicitly specify the `--address`, or use the `--config` flag to load the admin address from your config, if the running instance's admin API is not using the default listen address.
|
||||
|
||||
You may also use the `caddy` binary with this command to install certificates on other machines in your network, if the admin API is made accessible to other machines -- be careful if doing this, to not expose the admin API to untrusted clients.
|
||||
|
||||
|
||||
### `caddy untrust`
|
||||
|
||||
<pre><code class="cmd bash">caddy untrust
|
||||
[--cert <path>]
|
||||
[--ca <id>]
|
||||
[--address <interface>]
|
||||
[--config <path> [--adapter <name>]]</code></pre>
|
||||
|
||||
Untrusts a root certificate from the local trust store(s).
|
||||
|
||||
This command uninstalls trust; it does not necessarily delete the root certificate from trust stores entirely. Thus, repeatedly trusting and untrusting new certificates can fill up trust databases.
|
||||
|
||||
This command does not delete or modify certificate files from Caddy's configured storage.
|
||||
|
||||
This command can be used in one of two ways:
|
||||
- By specifying a direct path to the root certificate to untrust with the `--cert` flag.
|
||||
- By fetching the root certificate from the [admin API](/docs/api) using the [`GET /pki/ca/<id>/certificates`](/docs/api#get-pkicaidcertificates) endpoint. This is the default behaviour if no flags are given.
|
||||
|
||||
If the admin API is used, then the CA ID defaults to "local". You may specify the ID of another CA with the `--ca` flag. You may explicitly specify the `--address`, or use the `--config` flag to load the admin address from your config, if the running instance's admin API is not using the default listen address.
|
||||
|
||||
|
||||
### `caddy upgrade`
|
||||
|
||||
<pre><code class="cmd bash">caddy upgrade
|
||||
[--keep-backup]</code></pre>
|
||||
|
||||
Replaces the current Caddy binary with the latest version from [our download page](https://caddyserver.com/download) with the same modules installed, including all third-party plugins that are registered on the Caddy website.
|
||||
|
||||
Upgrades do not interrupt running servers; currently, the command only replaces the binary on disk. This might change in the future if we can figure out a good way to do it.
|
||||
|
||||
The upgrade process is fault tolerant; the current binary is backed up first (copied beside the current one) and automatically restored if anything goes wrong. If you wish to keep the backup after the upgrade process is complete, you may use the `--keep-backup` option.
|
||||
|
||||
This command may require elevated privileges if your user does not have permission to write to the executable file.
|
||||
|
||||
|
||||
|
||||
### `caddy add-package`
|
||||
|
||||
<pre><code class="cmd bash">caddy add-package <packages...>
|
||||
[--keep-backup]</code></pre>
|
||||
|
||||
Similarly to `caddy upgrade`, replaces the current Caddy binary with the latest version with the same modules installed, _plus_ the packages listed as arguments included in the new binary. Find the list of packages you can install from [our download page](https://caddyserver.com/download). Each argument should be the full package name.
|
||||
|
||||
For example:
|
||||
|
||||
<pre><code class="cmd bash">caddy add-package github.com/caddy-dns/cloudflare</code></pre>
|
||||
|
||||
|
||||
|
||||
### `caddy remove-package`
|
||||
|
||||
<pre><code class="cmd bash">caddy remove-package <packages...>
|
||||
[--keep-backup]</code></pre>
|
||||
|
||||
Similarly to `caddy upgrade`, replaces the current Caddy binary with the latest version with the same modules installed, but _without_ the packages listed as arguments, if they existed in the current binary. Run `caddy list-modules --packages` to see the list of package names of non-standard modules included in the current binary.
|
||||
|
||||
|
||||
|
||||
### `caddy validate`
|
||||
|
||||
<pre><code class="cmd bash">caddy validate
|
||||
[--config <path>]
|
||||
[--adapter <name>]</code></pre>
|
||||
|
||||
Validates a configuration file, then exits. This command deserializes the config, then loads and provisions all of its modules as if to start the config, but the config is not actually started. This exposes errors in a configuration that arise during loading or provisioning phases and is a stronger error check than merely serializing a config as JSON.
|
||||
|
||||
`--config` is the config file to validate. If `-`, the config is read from stdin. Default is the `Caddyfile` in the current directory, if any.
|
||||
|
||||
`--adapter` is the name of the config adapter to use, if the config file is not in Caddy's native JSON format. If the config file starts with `Caddyfile`, the `caddyfile` adapter is used by default.
|
||||
|
||||
|
||||
|
||||
### `caddy version`
|
||||
<pre><code class="cmd bash">caddy version</code></pre>
|
||||
|
||||
Prints the version and exits.
|
||||
|
||||
|
||||
|
||||
## Signals
|
||||
|
||||
Caddy traps certain signals and ignores others. Signals can initiate specific process behavior.
|
||||
|
||||
Signal | Behavior
|
||||
-------|----------
|
||||
`SIGINT` | Graceful exit. Send signal again to force exit immediately.
|
||||
`SIGQUIT` | Quits Caddy immediately, but still cleans up locks in storage because it is important.
|
||||
`SIGTERM` | Graceful exit.
|
||||
`SIGUSR1` | Ignored. For config updates, use the `caddy reload` command or [the API](/docs/api).
|
||||
`SIGUSR2` | Ignored.
|
||||
`SIGHUP` | Ignored.
|
||||
|
||||
A graceful exit means that new connections are no longer accepted, and existing connections will be drained before the socket is closed. A grace period may apply (and is configurable). Once the grace period is up, connections will be forcefully terminated. Locks in storage and other resources that individual modules need to release are cleaned up during a graceful shutdown.
|
||||
|
||||
## Exit codes
|
||||
|
||||
Caddy returns a code when the process exits:
|
||||
|
||||
Code | Meaning
|
||||
-----|---------
|
||||
`0` | Normal exit.
|
||||
`1` | Failed startup. **Do not automatically restart the process; it will likely error again unless changes are made.**
|
||||
`2` | Forced quit. Caddy was forced to exit without cleaning up resources.
|
||||
`3` | Failed quit. Caddy exited with some errors during cleanup.
|
||||
|
||||
In bash, you can get the exit code of the last command with `echo $?`.
|
49
src/docs/markdown/config-adapters.md
Normal file
49
src/docs/markdown/config-adapters.md
Normal file
|
@ -0,0 +1,49 @@
|
|||
---
|
||||
title: Config Adapters
|
||||
---
|
||||
|
||||
# Config Adapters
|
||||
|
||||
Caddy's native config language is [JSON](https://www.json.org/json-en.html), but writing JSON by hand can be tedious and error-prone. That's why Caddy supports being configured with other languages through **config adapters**. They are Caddy plugins which make it possible to use config in your preferred format by outputting [Caddy JSON](/docs/json/) for you.
|
||||
|
||||
For example, a config adapter could [turn your NGINX config into Caddy JSON](https://github.com/caddyserver/nginx-adapter).
|
||||
|
||||
## Known config adapters
|
||||
|
||||
The following config adapters are currently available (some are third-party projects):
|
||||
|
||||
- [**caddyfile**](/docs/caddyfile) (standard)
|
||||
- [**nginx**](https://github.com/caddyserver/nginx-adapter)
|
||||
- [**jsonc**](https://github.com/caddyserver/jsonc-adapter)
|
||||
- [**json5**](https://github.com/caddyserver/json5-adapter)
|
||||
- [**yaml**](https://github.com/abiosoft/caddy-yaml)
|
||||
- [**cue**](https://github.com/caddyserver/cue-adapter)
|
||||
- [**toml**](https://github.com/awoodbeck/caddy-toml-adapter)
|
||||
- [**hcl**](https://github.com/francislavoie/caddy-hcl)
|
||||
- [**dhall**](https://github.com/mholt/caddy-dhall)
|
||||
|
||||
## Using config adapters
|
||||
|
||||
You can use a config adapter by specifying it on the command line by using the `--adapter` flag on most subcommands that take a config:
|
||||
|
||||
<pre><code class="cmd bash">caddy run --config caddy.yaml --adapter yaml</code></pre>
|
||||
|
||||
Or via the API at the [`/load` endpoint](/docs/api#post-load):
|
||||
|
||||
<pre><code class="cmd bash">curl localhost:2019/load \
|
||||
-H "Content-Type: application/yaml" \
|
||||
--data-binary @caddy.yaml</code></pre>
|
||||
|
||||
If you only want to get the output JSON without running it, you can use the [`caddy adapt`](/docs/command-line#caddy-adapt) command:
|
||||
|
||||
<pre><code class="cmd bash">caddy adapt --config caddy.yaml --adapter yaml</code></pre>
|
||||
|
||||
## Caveats
|
||||
|
||||
Not all config languages are 100% compatible with Caddy; some features or behaviors simply don't translate well or are not yet programmed into the adapter or Caddy itself.
|
||||
|
||||
Some adapters do a 1-1 translation, like YAML->JSON or TOML->JSON. Others are designed specifically for Caddy, like the Caddyfile. Generally, these adapters will always work.
|
||||
|
||||
However, not all adapters work all of the time. Config adapters do their best to translate your input to Caddy JSON with the highest fidelity and correctness. Because this conversion process is not guaranteed to be complete and correct all the time, we don't call them "converters" or "translators". They are "adapters" since they will at least give you a good starting point to finish crafting your final JSON config.
|
||||
|
||||
Config adapters can output the resulting JSON, warnings, and errors. JSON results if no errors occur. Errors occur when something is wrong with the input (for example, syntax errors). Warnings are emitted when something is wrong with the adaptation but which is not necessarily fatal (for example, feature not supported). Caution is advised if using configs that were adapted with warnings.
|
182
src/docs/markdown/conventions.md
Normal file
182
src/docs/markdown/conventions.md
Normal file
|
@ -0,0 +1,182 @@
|
|||
---
|
||||
title: Conventions
|
||||
---
|
||||
|
||||
# Conventions
|
||||
|
||||
The Caddy ecosystem adheres to a few conventions to make things consistent and intuitive across the platform.
|
||||
|
||||
|
||||
## Network addresses
|
||||
|
||||
When specifying a network address to dial or bind, Caddy accepts a string in the following format:
|
||||
|
||||
```
|
||||
network/address
|
||||
```
|
||||
|
||||
The network part is optional (defaulting to `tcp`), and is anything that [Go's `net.Dial` function](https://pkg.go.dev/net#Dial) recognizes. If a network is specified, a single forward slash `/` must separate the network and address portions.
|
||||
|
||||
The network can be any of the following; ones suffixed with `4` or `6` are IPv4 or IPv6 only, respectively:
|
||||
|
||||
- TCP: `tcp`, `tcp4`, `tcp6`
|
||||
- UDP: `udp`, `udp4`, `udp6`
|
||||
- IP: `ip`, `ip4`, `ip6`
|
||||
- Unix: `unix`, `unixgram`, `unixpacket`
|
||||
|
||||
The address part may be any of these forms:
|
||||
|
||||
- `host`
|
||||
- `host:port`
|
||||
- `:port`
|
||||
- `/path/to/unix/socket`
|
||||
|
||||
The host may be any hostname, resolvable domain name, or IP address.
|
||||
|
||||
The port may be a single value (`:8080`) or an inclusive range (`:8080-8085`). A port range will be multiplied into singular addresses. Not all config fields accept port ranges. The special port `:0` means any available port.
|
||||
|
||||
A unix socket path is only acceptable when using a `unix*` network type. The forward slash that separates the network and address is not considered part of the path.
|
||||
|
||||
Valid examples:
|
||||
|
||||
```
|
||||
:8080
|
||||
127.0.0.1:8080
|
||||
localhost:8080
|
||||
localhost:8080-8085
|
||||
tcp/localhost:8080
|
||||
tcp/localhost:8080-8085
|
||||
udp/localhost:9005
|
||||
unix//path/to/socket
|
||||
```
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
Caddy network addresses are not URLs. URLs couple the lower and higher layers of the [OSI model](https://en.wikipedia.org/wiki/OSI_model#Layer_architecture), but Caddy often uses network addresses independently of a specific application, so combining them would be problematic. In Caddy, network addresses refer precisely to resources that can be dialed or bound at L3-L5, but URLs combine L3-L7, which is too many. A network address requires a host+port and path to be mutually exclusive, but URLs do not. Network addresses sometimes support port ranges, but URLs do not.
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
## Placeholders
|
||||
|
||||
Caddy's configuration supports the use of _placeholders_ (variables). Using placeholders is a simple way to inject dynamic values into a static configuration.
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
Placeholders are a similar idea to variables in other software. For example, [nginx has variables](https://nginx.org/en/docs/varindex.html) like `$uri` and `$document_root`.
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
Placeholders are bounded on either side by curly braces `{ }` and contain the variable name inside, for example: `{foo.bar}`. Placeholder braces can be escaped, `\{like so\}`. Variable names are typically namespaced with dots to avoid collisions across modules.
|
||||
|
||||
Which placeholders are available depends on the context. Not all placeholders are available in all parts of the config. For example, [the HTTP app sets placeholders](/docs/json/apps/http/#docs) that are only available in areas of the config related to handling HTTP requests.
|
||||
|
||||
The following placeholders are always available:
|
||||
|
||||
Placeholder | Description
|
||||
------------|-------------
|
||||
`{env.*}` | Environment variable (example: `{env.HOME}`)
|
||||
`{system.hostname}` | The system's local hostname
|
||||
`{system.slash}` | The system's filepath separator
|
||||
`{system.os}` | The system's OS
|
||||
`{system.arch}` | The system's architecture
|
||||
`{time.now}` | The current time as a Go Time struct
|
||||
`{time.now.unix}` | The current time as a unix timestamp in seconds
|
||||
`{time.now.unix_ms}` | The current time as a unix timestamp in milliseconds
|
||||
`{time.now.common_log}` | The current time in Common Log Format
|
||||
`{time.now.year}` | The current year in YYYY format
|
||||
|
||||
Not all config fields support placeholders, but most do where you would expect it.
|
||||
|
||||
|
||||
## File locations
|
||||
|
||||
This section contains information about where to find various files. File and directory paths described here are defaults at best; some can be overridden.
|
||||
|
||||
### Your config files
|
||||
|
||||
There is no single, conventional place for you to put your config files. Put them wherever makes the most sense to you.
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
The only exception to this might be a file named `Caddyfile` in the current working directory, which the caddy command tries for convenience if no other config file is specified.
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
Distributions that ship with a default config file should document where this config file is at, even if it might be obvious to the package/distro maintainers. For most Linux installations, the Caddyfile will be found at `/etc/caddy/Caddyfile`.
|
||||
|
||||
|
||||
### Data directory
|
||||
|
||||
Caddy stores TLS certificates and other important assets in a data directory, which is backed by [the configured storage module](/docs/json/storage/) (default: local file system).
|
||||
|
||||
If the `XDG_DATA_HOME` environment variable is set, it is `$XDG_DATA_HOME/caddy`.
|
||||
|
||||
Otherwise, its path varies by platform, adhering to OS conventions:
|
||||
|
||||
OS | Data directory path
|
||||
---|---------------------
|
||||
**Linux, BSD** | `$HOME/.local/share/caddy`
|
||||
**Windows** | `%AppData%\Caddy`
|
||||
**macOS** | `$HOME/Library/Application Support/Caddy`
|
||||
**Plan 9** | `$HOME/lib/caddy`
|
||||
**Android** | `$HOME/caddy` (or `/sdcard/caddy`)
|
||||
|
||||
All other OSes use the Linux/BSD directory path.
|
||||
|
||||
**The data directory must not be treated as a cache.** Its contents are **not** ephemeral or merely for the sake of performance. Caddy stores TLS certificates, private keys, OCSP staples, and other necessary information to the data directory. It should not be purged without understanding the implications.
|
||||
|
||||
It is crucial that this directory is persistent and writeable by Caddy.
|
||||
|
||||
|
||||
### Configuration directory
|
||||
|
||||
This is where Caddy may store certain configuration to disk. Most notably, it persists the last active configuration (by default) to this folder for easy resumption later using [`caddy run --resume`](/docs/command-line#caddy-run).
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
The configuration directory is *not* where you need to store [your config files](#your-config-files). (Though, you are allowed to.)
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
If the `XDG_CONFIG_HOME` environment variable is set, it is `$XDG_CONFIG_HOME/caddy`.
|
||||
|
||||
Otherwise, its path varies by platform, adhering to OS conventions:
|
||||
|
||||
|
||||
OS | Config directory path
|
||||
---|---------------------
|
||||
**Linux, BSD** | `$HOME/.config/caddy`
|
||||
**Windows** | `%AppData%\Caddy`
|
||||
**macOS** | `$HOME/Library/Application Support/Caddy`
|
||||
**Plan 9** | `$HOME/lib/caddy`
|
||||
|
||||
All other OSes use the Linux/BSD directory path.
|
||||
|
||||
It is crucial that this directory is persistent and writeable by Caddy.
|
||||
|
||||
|
||||
## Durations
|
||||
|
||||
Duration strings are commonly used throughout Caddy's configuration. They take on the same format as [Go's `time.ParseDuration` syntax](https://golang.org/pkg/time/#ParseDuration) except you can also use `d` for day (we assume 1 day = 24 hours for simplicity). Valid units are:
|
||||
|
||||
- `ns` (nanosecond)
|
||||
- `us`/`µs` (microsecond)
|
||||
- `ms` (millisecond)
|
||||
- `s` (second)
|
||||
- `m` (minute)
|
||||
- `h` (hour)
|
||||
- `d` (day)
|
||||
|
||||
Examples:
|
||||
|
||||
- `250ms`
|
||||
- `5s`
|
||||
- `1.5h`
|
||||
- `2h45m`
|
||||
- `90d`
|
||||
|
||||
In the [JSON config](/docs/json/), duration values can also be integers which represent nanoseconds.
|
394
src/docs/markdown/extending-caddy.md
Normal file
394
src/docs/markdown/extending-caddy.md
Normal file
|
@ -0,0 +1,394 @@
|
|||
---
|
||||
title: "Extending Caddy"
|
||||
---
|
||||
|
||||
# Extending Caddy
|
||||
|
||||
Caddy is easy to extend because of its modular architecture. Most kinds of Caddy extensions (or plugins) are known as _modules_ if they extend or plug into Caddy's configuration structure. To be clear, Caddy modules are distinct from [Go modules](https://github.com/golang/go/wiki/Modules) (but they are also Go modules).
|
||||
|
||||
**Prerequisites:**
|
||||
- Basic understanding of [Caddy's architecture](/docs/architecture)
|
||||
- Go language proficiency
|
||||
- [`go`](https://golang.org/doc/install)
|
||||
- [`xcaddy`](https://github.com/caddyserver/xcaddy)
|
||||
|
||||
|
||||
## Quick Start
|
||||
|
||||
A Caddy module is any named type that registers itself as a Caddy module when its package is imported. Crucially, a module always implements the [caddy.Module](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#Module) interface, which provides its name and a constructor function.
|
||||
|
||||
In a new Go module, paste the following template into a Go file and customize your package name, type name, and Caddy module ID:
|
||||
|
||||
```go
|
||||
package mymodule
|
||||
|
||||
import "github.com/caddyserver/caddy/v2"
|
||||
|
||||
func init() {
|
||||
caddy.RegisterModule(Gizmo{})
|
||||
}
|
||||
|
||||
// Gizmo is an example; put your own type here.
|
||||
type Gizmo struct {
|
||||
}
|
||||
|
||||
// CaddyModule returns the Caddy module information.
|
||||
func (Gizmo) CaddyModule() caddy.ModuleInfo {
|
||||
return caddy.ModuleInfo{
|
||||
ID: "foo.gizmo",
|
||||
New: func() caddy.Module { return new(Gizmo) },
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then run this command from your project's directory, and you should see your module in the list:
|
||||
|
||||
<pre><code class="cmd bash">xcaddy list-modules
|
||||
...
|
||||
foo.gizmo
|
||||
...</code></pre>
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
The [`xcaddy` command](https://github.com/caddyserver/xcaddy) is an important part of every module developer's workflow. It compiles Caddy with your plugin, then runs it with the given arguments. It discards the temporary binary each time (similar to `go run`).
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
Congratulations, your module registers with Caddy and can be used in [Caddy's config document](/docs/json/) in whatever places use modules in the same namespace.
|
||||
|
||||
Under the hood, `xcaddy` is simply making a new Go module that requires both Caddy and your plugin (with an appropriate `replace` to use your local development version), then adds an import to ensure it is compiled in:
|
||||
|
||||
```go
|
||||
import _ "github.com/example/mymodule"
|
||||
```
|
||||
|
||||
|
||||
## Module Basics
|
||||
|
||||
Caddy modules:
|
||||
|
||||
1. Implement the `caddy.Module` interface to provide an ID and constructor
|
||||
2. Have a unique name in the proper namespace
|
||||
3. Usually satisfy some interface(s) that are meaningful to the host module for that namespace
|
||||
|
||||
**Host modules** (or _parent modules_) are modules which load/initialize other modules. They typically define namespaces for guest modules.
|
||||
|
||||
**Guest modules** (or _child modules_) are modules which get loaded or initialized. All modules are guest modules.
|
||||
|
||||
|
||||
## Module IDs
|
||||
|
||||
Each Caddy module has a unique ID, consisting of a namespace and name:
|
||||
|
||||
- A complete ID looks like `foo.bar.module_name`
|
||||
- The namespace would be `foo.bar`
|
||||
- The name would be `module_name` which must be unique in its namespace
|
||||
|
||||
Module IDs must use `snake_case` convention.
|
||||
|
||||
### Namespaces
|
||||
|
||||
Namespaces are like classes, i.e. a namespace defines some functionality that is common among all modules within it. For example, we can expect that all modules within the `http.handlers` namespace are HTTP handlers. It follows that a host module may type-assert guest modules in that namespace from `interface{}` types into a more specific, useful type such as `caddyhttp.MiddlewareHandler`.
|
||||
|
||||
A guest module must be properly namespaced in order for it to be recognized by a host module because host modules will ask Caddy for modules within a certain namespace to provide the functionality desired by the host module. For example, if you were to write an HTTP handler module called `gizmo`, your module's name would be `http.handlers.gizmo`, because the `http` app will look for handlers in the `http.handlers` namespace.
|
||||
|
||||
Put another way, Caddy modules are expected to implement [certain interfaces](/docs/extending-caddy/namespaces) depending on their module namespace. With this convention, module developers can say intuitive things such as, "All modules in the `http.handlers` namespace are HTTP handlers." More technically, this usually means, "All modules in the `http.handlers` namespace implement the `caddyhttp.MiddlewareHandler` interface." Because that method set is known, the more specific type can be asserted and used.
|
||||
|
||||
**[View a table mapping all the standard Caddy namespaces to their Go types.](/docs/extending-caddy/namespaces)**
|
||||
|
||||
The `caddy` and `admin` namespaces are reserved and cannot be app names.
|
||||
|
||||
To write modules which plug into 3rd-party host modules, consult those modules for their namespace documentation.
|
||||
|
||||
### Names
|
||||
|
||||
The name within a namespace is significant and highly visible to users, but is not particularly important, as long as it is unique, concise, and makes sense for what it does.
|
||||
|
||||
|
||||
## App Modules
|
||||
|
||||
Apps are modules with an empty namespace, and which conventionally become their own top-level namespace. App modules implement the [caddy.App](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#App) interface.
|
||||
|
||||
These modules appear in the [`"apps"`](/docs/json/#apps) property of the top-level of Caddy's config:
|
||||
|
||||
```json
|
||||
{
|
||||
"apps": {}
|
||||
}
|
||||
```
|
||||
|
||||
Example [apps](/docs/json/apps/) are `http` and `tls`. Theirs is the empty namespace.
|
||||
|
||||
Guest modules written for these apps should be in a namespace derived from the app name. For example, HTTP handlers use the `http.handlers` namespace and TLS certificate loaders use the `tls.certificates` namespace.
|
||||
|
||||
## Module Implementation
|
||||
|
||||
A module can be virtually any type, but structs are the most common because they can hold user configuration.
|
||||
|
||||
|
||||
### Configuration
|
||||
|
||||
Most modules require some configuration. Caddy takes care of this automatically, as long as your type is compatible with JSON. Thus, if a module is a struct type, it will need struct tags on its fields, which should use `snake_casing` according to Caddy convention:
|
||||
|
||||
```go
|
||||
type Gizmo struct {
|
||||
MyField string `json:"my_field,omitempty"`
|
||||
Number int `json:"number,omitempty"`
|
||||
}
|
||||
```
|
||||
|
||||
Using struct tags in this way will ensure that config properties are consisently named across all of Caddy.
|
||||
|
||||
When a module is initialized, it will already have its configuration filled out. It is also possible to perform additional [provisioning](#provisioning) and [validation](#validating) steps after a module is initialized.
|
||||
|
||||
|
||||
### Module Lifecycle
|
||||
|
||||
A module's life begins when it is loaded by a host module. The following happens:
|
||||
|
||||
1. [`New()`](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#ModuleInfo.New) is called to get an instance of the module's value.
|
||||
2. The module's configuration is unmarshaled into that instance.
|
||||
3. If the module is a [caddy.Provisioner](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#Provisioner), the `Provision()` method is called.
|
||||
4. If the module is a [caddy.Validator](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#Validator), the `Validate()` method is called.
|
||||
5. At this point, the host module is given the loaded guest module as an `interface{}` value, so the host module will usually type-assert the guest module into a more useful type. Check the documentation for the host module to know what is required of a guest module in its namespace, e.g. what methods need to be implemented.
|
||||
6. When a module is no longer needed, and if it is a [caddy.CleanerUpper](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#CleanerUpper), the `Cleanup()` method is called.
|
||||
|
||||
Note that multiple loaded instances of your module may overlap at a given time! During config changes, new modules are started before the old ones are stopped. Be sure to use global state carefully. Use the [caddy.UsagePool](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#UsagePool) type to help manage global state across module loads. If your module listens on a socket, use `caddy.Listen*()` to get a socket that supports overlapping usage.
|
||||
|
||||
### Provisioning
|
||||
|
||||
A module's configuration will be unmarshaled into its value automatically. This means, for example, that struct fields will be filled out for you.
|
||||
|
||||
However, if your module requires additional provisioning steps, you can implement the (optional) [caddy.Provisioner](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#Provisioner) interface:
|
||||
|
||||
```go
|
||||
// Provision sets up the module.
|
||||
func (g *Gizmo) Provision(ctx caddy.Context) error {
|
||||
// TODO: set up the module
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
This is typically where host modules will load their guest/child modules, but it can be used for pretty much anything. Module provisioning is done in an arbitrary order.
|
||||
|
||||
A module may access other apps by calling `ctx.App()`, but modules must not have circular dependencies. In other words, a module loaded by the `http` app cannot depend on the `tls` app if a module loaded by the `tls` app depends on the `http` app. (Very similar to rules forbidding import cycles in Go.)
|
||||
|
||||
Additionally, you should avoid performing expensive operations in `Provision`, since provisioning is performed even if a config is only being validated. When in the provisioning phase, do not expect that the module will actually be used.
|
||||
|
||||
#### Logs
|
||||
|
||||
If your module needs logging, do not use `log.Print*()` from the Go standard library. In other words, **do not use Go's global logger**. Caddy uses high-performance, highly flexible, structured logging with [zap](https://github.com/uber-go/zap).
|
||||
|
||||
To emit logs, get a logger in your module's Provision method:
|
||||
|
||||
```go
|
||||
func (g *Gizmo) Provision(ctx caddy.Context) error {
|
||||
g.logger = ctx.Logger() // g.logger is a *zap.Logger
|
||||
}
|
||||
```
|
||||
|
||||
Then you can emit structured, leveled logs using `g.logger`. See [zap's godoc](https://pkg.go.dev/go.uber.org/zap?tab=doc#Logger) for details.
|
||||
|
||||
|
||||
### Validating
|
||||
|
||||
Modules which would like to validate their configuration may do so by satisfying the (optional) [`caddy.Validator`](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#Validator) interface:
|
||||
|
||||
```go
|
||||
// Validate validates that the module has a usable config.
|
||||
func (g Gizmo) Validate() error {
|
||||
// TODO: validate the module's setup
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
Validate should be a read-only function. It is run after the `Provision()` method.
|
||||
|
||||
|
||||
### Interface guards
|
||||
|
||||
Caddy module behavior is implicit because Go interfaces are satisfied implicitly. Simply adding the right methods to your module's type is all it takes to make or break your module's correctness. Thus, making a typo or getting the method signature wrong can lead to unexpected (lack of) behavior.
|
||||
|
||||
Fortunately, there is an easy, no-overhead, compile-time check you can add to your code to ensure you've added the right methods. These are called interface guards:
|
||||
|
||||
```go
|
||||
var _ InterfaceName = (*YourType)(nil)
|
||||
```
|
||||
|
||||
Replace `InterfaceName` with the interface you intend to satisfy, and `YourType` with the name of your module's type.
|
||||
|
||||
For example, an HTTP handler such as the static file server might satisfy multiple interfaces:
|
||||
|
||||
```go
|
||||
// Interface guards
|
||||
var (
|
||||
_ caddy.Provisioner = (*FileServer)(nil)
|
||||
_ caddyhttp.MiddlewareHandler = (*FileServer)(nil)
|
||||
)
|
||||
```
|
||||
|
||||
This prevents the program from compiling if `*FileServer` does not satisfy those interfaces.
|
||||
|
||||
Without interface guards, confusing bugs can slip in. For example, if your module must provision itself before being used but your `Provision()` method has a mistake (e.g. misspelled or wrong signature), provisioning will never happen, leading to head-scratching. Interface guards are super easy and can prevent that. They usually go at the bottom of the file.
|
||||
|
||||
|
||||
## Host Modules
|
||||
|
||||
A module becomes a host module when it loads its own guest modules. This is useful if a piece of the module's functionality can be implemented in different ways.
|
||||
|
||||
A host module is almost always a struct. Normally, supporting a guest module requires two struct fields: one to hold its raw JSON, and another to hold its decoded value:
|
||||
|
||||
```go
|
||||
type Gizmo struct {
|
||||
GadgetRaw json.RawMessage `json:"gadget,omitempty" caddy:"namespace=foo.gizmo.gadgets inline_key=gadgeter"`
|
||||
|
||||
Gadget Gadgeter `json:"-"`
|
||||
}
|
||||
```
|
||||
|
||||
The first field (`GadgetRaw` in this example) is where the raw, unprovisioned JSON form of the guest module can be found.
|
||||
|
||||
The second field (`Gadget`) is where the final, provisioned value will eventually be stored. Since the second field is not user-facing, we exclude it from JSON with a struct tag. (You could also unexport it if it is not needed by other packages, and then no struct tag is needed.)
|
||||
|
||||
### Caddy struct tags
|
||||
|
||||
The `caddy` struct tag on the raw module field helps Caddy to know the namespace and name (comprising the complete ID) of the module to load. It is also used for generating documentation.
|
||||
|
||||
The struct tag has a very simple format: `key1=val1 key2=val2 ...`
|
||||
|
||||
For module fields, the struct tag will look like:
|
||||
|
||||
```go
|
||||
`caddy:"namespace=foo.bar inline_key=baz"`
|
||||
```
|
||||
|
||||
The `namespace=` part is required. It defines the namespace in which to look for the module.
|
||||
|
||||
The `inline_key=` part is only used if the module's name will be found _inline_ with the module itself; this implies that the value is an object where one of the keys is the _inline key_, and its value is the name of the module. If omitted, then the field type must be a [`caddy.ModuleMap`](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#ModuleMap) or `[]caddy.ModuleMap`, where the map key is the module name.
|
||||
|
||||
|
||||
### Loading guest modules
|
||||
|
||||
To load a guest module, call [`ctx.LoadModule()`](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#Context.LoadModule) during the provision phase:
|
||||
|
||||
```go
|
||||
// Provision sets up g and loads its gadget.
|
||||
func (g *Gizmo) Provision(ctx caddy.Context) error {
|
||||
if g.GadgetRaw != nil {
|
||||
val, err := ctx.LoadModule(g, "GadgetRaw")
|
||||
if err != nil {
|
||||
return fmt.Errorf("loading gadget module: %v", err)
|
||||
}
|
||||
g.Gadget = val.(Gadgeter)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
Note that the `LoadModule()` call takes a pointer to the struct and the field name as a string. Weird, right? Why not just pass the struct field directly? It's because there are a few different ways to load modules depending on the layout of the config. This method signature allows Caddy to use reflection to figure out the best way to load the module and, most importantly, read its struct tags.
|
||||
|
||||
If a guest module must explicitly be set by the user, you should return an error if the Raw field is nil or empty before trying to load it.
|
||||
|
||||
Notice how the loaded module is type-asserted: `g.Gadget = val.(Gadgeter)` - this is because the returned `val` is a `interface{}` type which is not very useful. However, we expect that all modules in the declared namespace (`foo.gizmo.gadgets` from the struct tag in our example) implement the `Gadgeter` interface, so this type assertion is safe, and then we can use it!
|
||||
|
||||
If your host module defines a new namespace, be sure to document both that namespace and its Go type(s) for developers [like we have done here](/docs/extending-caddy/namespaces).
|
||||
|
||||
## Complete Example
|
||||
|
||||
Let's suppose we want to write an HTTP handler module. This will be a contrived middleware for demonstration purposes which prints the visitor's IP address to a stream on every HTTP request.
|
||||
|
||||
We also want it to be configurable via the Caddyfile, because most people prefer to use the Caddyfile in non-automated situations. We do this by registering a Caddyfile handler directive, which is a kind of directive that can add a handler to the HTTP route. We also implement the `caddyfile.Unmarshaler` interface. By adding these few lines of code, this module can be configured with the Caddyfile! For example: `visitor_ip stdout`.
|
||||
|
||||
Here is the code for such a module, with explanatory comments:
|
||||
|
||||
```go
|
||||
package visitorip
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
|
||||
"github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
|
||||
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
|
||||
)
|
||||
|
||||
func init() {
|
||||
caddy.RegisterModule(Middleware{})
|
||||
httpcaddyfile.RegisterHandlerDirective("visitor_ip", parseCaddyfile)
|
||||
}
|
||||
|
||||
// Middleware implements an HTTP handler that writes the
|
||||
// visitor's IP address to a file or stream.
|
||||
type Middleware struct {
|
||||
// The file or stream to write to. Can be "stdout"
|
||||
// or "stderr".
|
||||
Output string `json:"output,omitempty"`
|
||||
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
// CaddyModule returns the Caddy module information.
|
||||
func (Middleware) CaddyModule() caddy.ModuleInfo {
|
||||
return caddy.ModuleInfo{
|
||||
ID: "http.handlers.visitor_ip",
|
||||
New: func() caddy.Module { return new(Middleware) },
|
||||
}
|
||||
}
|
||||
|
||||
// Provision implements caddy.Provisioner.
|
||||
func (m *Middleware) Provision(ctx caddy.Context) error {
|
||||
switch m.Output {
|
||||
case "stdout":
|
||||
m.w = os.Stdout
|
||||
case "stderr":
|
||||
m.w = os.Stderr
|
||||
default:
|
||||
return fmt.Errorf("an output stream is required")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate implements caddy.Validator.
|
||||
func (m *Middleware) Validate() error {
|
||||
if m.w == nil {
|
||||
return fmt.Errorf("no writer")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ServeHTTP implements caddyhttp.MiddlewareHandler.
|
||||
func (m Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
|
||||
m.w.Write([]byte(r.RemoteAddr))
|
||||
return next.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// UnmarshalCaddyfile implements caddyfile.Unmarshaler.
|
||||
func (m *Middleware) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
||||
for d.Next() {
|
||||
if !d.Args(&m.Output) {
|
||||
return d.ArgErr()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseCaddyfile unmarshals tokens from h into a new Middleware.
|
||||
func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
|
||||
var m Middleware
|
||||
err := m.UnmarshalCaddyfile(h.Dispenser)
|
||||
return m, err
|
||||
}
|
||||
|
||||
// Interface guards
|
||||
var (
|
||||
_ caddy.Provisioner = (*Middleware)(nil)
|
||||
_ caddy.Validator = (*Middleware)(nil)
|
||||
_ caddyhttp.MiddlewareHandler = (*Middleware)(nil)
|
||||
_ caddyfile.Unmarshaler = (*Middleware)(nil)
|
||||
)
|
||||
```
|
138
src/docs/markdown/extending-caddy/caddyfile.md
Normal file
138
src/docs/markdown/extending-caddy/caddyfile.md
Normal file
|
@ -0,0 +1,138 @@
|
|||
---
|
||||
title: "Caddyfile Support"
|
||||
---
|
||||
|
||||
# Caddyfile Support
|
||||
|
||||
Caddy modules are automatically added to the [native JSON config](/docs/json/) by virtue of their namespace when they are [registered](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#RegisterModule), making them both usable and documented. This makes Caddyfile support purely optional, but it is often requested by users who prefer the Caddyfile.
|
||||
|
||||
## Unmarshaler
|
||||
|
||||
To add Caddyfile support for your module, simply implement the [`caddyfile.Unmarshaler`](https://pkg.go.dev/github.com/caddyserver/caddy/v2/caddyconfig/caddyfile?tab=doc#Unmarshaler) interface. You get to choose the Caddyfile syntax your module has by how you parse the tokens.
|
||||
|
||||
An unmarshaler's job is simply to set up your module's type, e.g. by populating its fields, using the [`caddyfile.Dispenser`](https://pkg.go.dev/github.com/caddyserver/caddy/v2/caddyconfig/caddyfile?tab=doc#Dispenser) passed to it. For example, a module type named `Gizmo` might have this method:
|
||||
|
||||
```go
|
||||
// UnmarshalCaddyfile implements caddyfile.Unmarshaler. Syntax:
|
||||
//
|
||||
// gizmo <name> [<option>]
|
||||
//
|
||||
func (g *Gizmo) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
||||
for d.Next() {
|
||||
if !d.Args(&g.Name) {
|
||||
// not enough args
|
||||
return d.ArgErr()
|
||||
}
|
||||
if d.NextArg() {
|
||||
// optional arg
|
||||
g.Option = d.Val()
|
||||
}
|
||||
if d.NextArg() {
|
||||
// too many args
|
||||
return d.ArgErr()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
It is a good idea to document the syntax in the godoc comment for the method. See the [godoc for the `caddyfile` package](https://pkg.go.dev/github.com/caddyserver/caddy/v2/caddyconfig/caddyfile?tab=doc) for more information about parsing the Caddyfile.
|
||||
|
||||
It is also important for an unmarshaler to accept multiple occurrences of its directive (rare, but can happen in some cases). Since the first token will typically be the module's name or directive (and can often be skipped by the unmarshaler), this usually means wrapping your parsing logic in a `for d.Next() { ... }` loop.
|
||||
|
||||
Make sure to check for missing or excess arguments.
|
||||
|
||||
You should also add an [interface guard](/docs/extending-caddy#interface-guards) to ensure the interface is satisfied properly:
|
||||
|
||||
```go
|
||||
var _ caddyfile.Unmarshaler = (*Gizmo)(nil)
|
||||
```
|
||||
|
||||
### Blocks
|
||||
|
||||
To accept more configuration than can fit on a single line, you may wish to allow a block with subdirectives. This can be done using `d.NextBlock()` and iterating until you return to the original nesting level:
|
||||
|
||||
```go
|
||||
for nesting := d.Nesting(); d.NextBlock(nesting); {
|
||||
switch d.Val() {
|
||||
case "sub_directive_1":
|
||||
// ...
|
||||
case "sub_directive_2":
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
As long as each iteration of the loop consumes the entire segment (line or block), then this is an elegant way to handle blocks.
|
||||
|
||||
## HTTP Directives
|
||||
|
||||
The HTTP Caddyfile is Caddy's default Caddyfile adapter syntax (or "server type"). It is extensible, meaning you can [register](https://pkg.go.dev/github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile?tab=doc#RegisterDirective) your own "top-level" directives for your module:
|
||||
|
||||
```go
|
||||
func init() {
|
||||
httpcaddyfile.RegisterDirective("gizmo", parseCaddyfile)
|
||||
}
|
||||
```
|
||||
|
||||
If your directive only returns a single HTTP handler (as is common), you may find [`RegisterHandlerDirective`](https://pkg.go.dev/github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile?tab=doc#RegisterHandlerDirective) easier:
|
||||
|
||||
```go
|
||||
func init() {
|
||||
httpcaddyfile.RegisterHandlerDirective("gizmo", parseCaddyfileHandler)
|
||||
}
|
||||
```
|
||||
|
||||
The basic idea is that [the parsing function](https://pkg.go.dev/github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile?tab=doc#UnmarshalFunc) you associate with your directive returns one or more [`ConfigValue`](https://pkg.go.dev/github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile?tab=doc#ConfigValue) values. (Or, if using `RegisterHandlerDirective`, it simply returns the populated `caddyhttp.MiddlewareHandler` value directly.) Each config value is associated with a ["class"](#classes) which helps the HTTP Caddyfile adapter to know which part(s) of the final JSON config it can be used in. All the config values get dumped into a pile from which the adapter draws when constructing the final JSON config.
|
||||
|
||||
This design allows your directive to return any config values for any recognized classes, which means it can influence any parts of the config that the HTTP Caddyfile adapter has a designated class for.
|
||||
|
||||
If you've already implemented the `UnmarshalCaddyfile()` method, then your parse function could be as simple as:
|
||||
|
||||
```go
|
||||
// parseCaddyfileHandler unmarshals tokens from h into a new middleware handler value.
|
||||
func parseCaddyfileHandler(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
|
||||
var g Gizmo
|
||||
err := g.UnmarshalCaddyfile(h.Dispenser)
|
||||
return g, err
|
||||
}
|
||||
```
|
||||
|
||||
See the [`httpcaddyfile` package godoc](https://pkg.go.dev/github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile?tab=doc) for more information about how to use the `httpcaddyfile.Helper` type.
|
||||
|
||||
|
||||
### Handler order
|
||||
|
||||
All directives which return HTTP middleware/handler values need to be evaluated in the correct order. For example, a handler that sets the root directory of the site has to come before a handler that accesses the root directory, so that it will know what the directory path is.
|
||||
|
||||
The HTTP Caddyfile [has a hard-coded ordering for the standard directives](/docs/caddyfile/directives#directive-order). This ensures that users do not need to know the implementation details of the most common functions of their web server, and makes it easier for them to write correct configurations. A single, hard-coded list also prevents nondeterminism given the extensible nature of the Caddyfile.
|
||||
|
||||
**When you register a new handler directive, it must be added to that list before it can be used (outside of a `route` block).** This is done in configuration using one of two methods:
|
||||
|
||||
- The [`order` global option](/docs/caddyfile/options) modifies the standard order for that configuration only. For example: `order mydir before respond` will insert a new directive `mydir` to be evaluated before the `respond` handler. Then the directive can be used normally.
|
||||
- Or, use the directive in a [`route` block](/docs/caddyfile/directives/route). Because directives in a route block are not reordered, the directives used in a route block do not need to appear in the list.
|
||||
|
||||
Please document for your users where in the list is the right place for your directive to be ordered so that they can use it properly.
|
||||
|
||||
|
||||
### Classes
|
||||
|
||||
This table describes each class with exported types that is recognized by the HTTP Caddyfile adapter:
|
||||
|
||||
Class name | Expected type | Description
|
||||
---------- | ------------- | -----------
|
||||
bind | `[]string` | Server listener bind addresses
|
||||
tls.connection_policy | `*caddytls.ConnectionPolicy` | TLS connection policy
|
||||
route | `caddyhttp.Route` | HTTP handler route
|
||||
error_route | `*caddyhttp.Subroute` | HTTP error handling route
|
||||
tls.cert_issuer | `certmagic.Issuer` | TLS certificate issuer
|
||||
tls.cert_loader | `caddytls.CertificateLoader` | TLS certificate loader
|
||||
|
||||
|
||||
## Server Types
|
||||
|
||||
Structurally, the Caddyfile is a simple format, so there can be different types of Caddyfile formats (sometimes called "server types") to suit different needs.
|
||||
|
||||
The default Caddyfile format is the HTTP Caddyfile, which you are probably familiar with. This format primarily configures the [`http` app](/docs/modules/http) while only potentially sprinkling some config in other parts of the Caddy config structure (e.g. the `tls` app to load and automate certificates).
|
||||
|
||||
To configure apps other than HTTP, you may want to implement your own config adapter that uses [your own server type](https://pkg.go.dev/github.com/caddyserver/caddy/v2/caddyconfig/caddyfile?tab=doc#Adapter). The Caddyfile adapter will actually parse the input for you and give you the list of server blocks, and options, and it's up to your adapter to make sense of that structure and turn it into a JSON config.
|
62
src/docs/markdown/extending-caddy/config-adapters.md
Normal file
62
src/docs/markdown/extending-caddy/config-adapters.md
Normal file
|
@ -0,0 +1,62 @@
|
|||
---
|
||||
title: "Writing Config Adapters"
|
||||
---
|
||||
|
||||
# Writing Config Adapters
|
||||
|
||||
For various reasons, you may wish to configure Caddy using a format that is not [JSON](/docs/json/). Caddy has first-class support for this through [config adapters](/docs/config-adapters).
|
||||
|
||||
If one does not already exist for the language/syntax/format you prefer, you can write one!
|
||||
|
||||
## Template
|
||||
|
||||
Here's a template you can start with:
|
||||
|
||||
```go
|
||||
package myadapter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/caddyserver/caddy/v2/caddyconfig"
|
||||
)
|
||||
|
||||
func init() {
|
||||
caddyconfig.RegisterAdapter("adapter_name", MyAdapter{})
|
||||
}
|
||||
|
||||
// MyAdapter adapts ____ to Caddy JSON.
|
||||
type MyAdapter struct{
|
||||
}
|
||||
|
||||
// Adapt adapts the body to Caddy JSON.
|
||||
func (a MyAdapter) Adapt(body []byte, options map[string]interface{}) ([]byte, []caddyconfig.Warning, error) {
|
||||
// TODO: parse body and convert it to JSON
|
||||
return nil, nil, fmt.Errorf("not implemented")
|
||||
}
|
||||
```
|
||||
|
||||
- See godoc for [`RegisterAdapter()`](https://pkg.go.dev/github.com/caddyserver/caddy/v2/caddyconfig?tab=doc#RegisterAdapter)
|
||||
- See godoc for ['Adapter'](https://pkg.go.dev/github.com/caddyserver/caddy/v2/caddyconfig?tab=doc#Adapter) interface
|
||||
|
||||
The returned JSON should **not** be indented; it should always be compact. The caller can always prettify it if they want to.
|
||||
|
||||
Note that while config adapters are Caddy _plugins_, they are not Caddy _modules_ because they do not integrate into a part of the config (but they will show up in `list-modules` for convenience). Thus, they do not have `Provision()` or `Validate()` methods or follow the rest of the module lifecycle. They need only implement the `Adapter` interface and be registered as adapters.
|
||||
|
||||
When populating fields of the config that are `json.RawMessage` types (i.e. module fields), use the `JSON()` and `JSONModuleObject()` functions:
|
||||
|
||||
- [`caddyconfig.JSON()`](https://pkg.go.dev/github.com/caddyserver/caddy/v2/caddyconfig?tab=doc#JSON) is for marshaling module values without the module name embedded. (Often used for ModuleMap fields where the module name is the map key.)
|
||||
- [`caddyconfig.JSONModuleObject()`](https://pkg.go.dev/github.com/caddyserver/caddy/v2/caddyconfig?tab=doc#JSONModuleObject) is for marshaling module values with the module name added to the object. (Used pretty much everywhere else.)
|
||||
|
||||
|
||||
## Caddyfile Server Types
|
||||
|
||||
It is also possible to implement a custom Caddyfile format. The Caddyfile adapter is a single adapter implementation and its default "server type" is HTTP, but it supports alternate "server types" at registration. For example, the HTTP Caddyfile is registered like so:
|
||||
|
||||
```go
|
||||
func init() {
|
||||
caddyconfig.RegisterAdapter("caddyfile", caddyfile.Adapter{ServerType: ServerType{}})
|
||||
}
|
||||
```
|
||||
|
||||
You would implement the [`caddyfile.ServerType` interface](https://pkg.go.dev/github.com/caddyserver/caddy/v2/caddyconfig/caddyfile?tab=doc#ServerType) and register your own adapter accordingly.
|
34
src/docs/markdown/extending-caddy/namespaces.md
Normal file
34
src/docs/markdown/extending-caddy/namespaces.md
Normal file
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
title: "Module Namespaces"
|
||||
---
|
||||
|
||||
# Module Namespaces
|
||||
|
||||
Caddy guest modules are loaded generically as `interface{}` or `any` types. In order for the host modules to be able to use them, the loaded guest modules are usually type-asserted to a known type first. This page describes the mapping from module namespaces to Go types for all the standard modules.
|
||||
|
||||
Documentation for non-standard module namespaces can be found with the documentation for the host module that defines them.
|
||||
|
||||
<aside class="tip">
|
||||
One way to read this table is, "If your module is in <namespace>, then it should compile as <type>."
|
||||
</aside>
|
||||
|
||||
Namespace | Expected Type | Description | Notes
|
||||
--------- | ------------- | ----------- | ----------
|
||||
| | [`caddy.App`](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#App) | Caddy app
|
||||
caddy.fs | [`fs.FS`](https://pkg.go.dev/io/fs#FS) | Virtual file system | <i>⚠️ Experimental</i>
|
||||
caddy.logging.encoders.filter | [`logging.LogFieldFilter`](https://pkg.go.dev/github.com/caddyserver/caddy/v2/modules/logging?tab=doc#LogFieldFilter) | Log field filter</i>
|
||||
caddy.logging.writers | [`caddy.WriterOpener`](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#WriterOpener) | Log writers
|
||||
caddy.storage | [`caddy.StorageConverter`](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#StorageConverter) | Storage backends
|
||||
http.authentication.hashes | [`caddyauth.Comparer`](https://pkg.go.dev/github.com/caddyserver/caddy/v2/modules/caddyhttp/caddyauth?tab=doc#Comparer) | Password hashers/comparers
|
||||
http.authentication.providers | [`caddyauth.Authenticator`](https://pkg.go.dev/github.com/caddyserver/caddy/v2/modules/caddyhttp/caddyauth?tab=doc#Authenticator) | HTTP authentication providers
|
||||
http.handlers | [`caddyhttp.MiddlewareHandler`](https://pkg.go.dev/github.com/caddyserver/caddy/v2/modules/caddyhttp?tab=doc#MiddlewareHandler) | HTTP handlers
|
||||
http.matchers | [`caddyhttp.RequestMatcher`](https://pkg.go.dev/github.com/caddyserver/caddy/v2/modules/caddyhttp?tab=doc#RequestMatcher) | HTTP request matchers<br>
|
||||
http.reverse_proxy.circuit_breakers | [`reverseproxy.CircuitBreaker`](https://pkg.go.dev/github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy?tab=doc#CircuitBreaker) | Reverse proxy circuit breakers
|
||||
http.reverse_proxy.selection_policies | [`reverseproxy.Selector`](https://pkg.go.dev/github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy?tab=doc#Selector) | Load balancing selection policies<br>
|
||||
http.reverse_proxy.transport | [`http.RoundTripper`](https://pkg.go.dev/net/http?tab=doc#RoundTripper) | HTTP reverse proxy transports
|
||||
http.reverse_proxy.upstreams | [`reverseproxy.UpstreamSource`](https://pkg.go.dev/github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy?tab=doc#UpstreamSource) | Dynamic upstream source | <i>⚠️ Experimental</i>
|
||||
tls.certificates | [`caddytls.CertificateLoader`](https://pkg.go.dev/github.com/caddyserver/caddy/v2/modules/caddytls?tab=doc#CertificateLoader) | TLS certificate source</i>
|
||||
tls.handshake_match | [`caddytls.ConnectionMatcher`](https://pkg.go.dev/github.com/caddyserver/caddy/v2/modules/caddytls?tab=doc#ConnectionMatcher) | TLS connection matcher</i>
|
||||
tls.issuance | [`certmagic.Issuer`](https://pkg.go.dev/github.com/caddyserver/certmagic?tab=doc#Issuer) | TLS certificate issuer<br>
|
||||
tls.get_certificate | [`certmagic.CertificateManager`](https://pkg.go.dev/github.com/caddyserver/certmagic?tab=doc#CertificateManager) | TLS certificate manager | <i>⚠️ Experimental</i>
|
||||
tls.stek | [`caddytls.STEKProvider`](https://pkg.go.dev/github.com/caddyserver/caddy/v2/modules/caddytls?tab=doc#STEKProvider) | TLS session ticket key source</i>
|
276
src/docs/markdown/getting-started.md
Normal file
276
src/docs/markdown/getting-started.md
Normal file
|
@ -0,0 +1,276 @@
|
|||
---
|
||||
title: "Getting Started"
|
||||
---
|
||||
|
||||
# Getting Started
|
||||
|
||||
This guide will help you get a site up and running with Caddy on **Linux** in a matter of minutes, but it is _not the only way_ to do it. There are many ways you can [download](/download), [install](/docs/install), [configure](/docs/introduction), and [run](/docs/running) Caddy. **If you are already comfortable with setting up services using systemd, jump to [Introduction](/docs/introduction).**
|
||||
|
||||
You can jump out of this tutorial at any time when you feel like you know what to do next.
|
||||
|
||||
**Objectives:**
|
||||
- 🔲 Install Caddy as a service
|
||||
- 🔲 Discover the unit configuration
|
||||
- 🔲 Prepare your site
|
||||
- 🔲 Serve your site over HTTPS
|
||||
- 🔲 Add a reverse proxy
|
||||
- 🔲 Learn how to troubleshoot problems
|
||||
|
||||
**Prerequisites:**
|
||||
- A computer where you have administrator, root, or sudo privileges
|
||||
- Know how to use a terminal / command line
|
||||
- Familiarity with Unix permissions
|
||||
- Be comfortable editing text files
|
||||
- A registered domain name
|
||||
|
||||
---
|
||||
|
||||
First, ensure no other web servers are running on your machine (to avoid port-binding conflicts).
|
||||
|
||||
**[Install Caddy](/docs/install) by following the instructions for your system.** For example, if you're on Ubuntu, follow the steps that use `apt`; on Fedora, use `dnf`; etc. If a package isn't available for your distro, you can also [manually install Caddy as a service](/docs/running) on any Linux machine that has systemd.
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
All you really need to run Caddy is the executable file itself. "Installing" Caddy could be defined simply as putting Caddy in your PATH. But installing Caddy _as a service_ is best practice for production systems because generally, a service keeps the process running after reboots, implements a tighter permissions/security model, and centralizes logging.
|
||||
|
||||
</aside>
|
||||
|
||||
Verify that the Caddy service is running:
|
||||
|
||||
<pre><code class="cmd bash">systemctl status caddy</code></pre>
|
||||
|
||||
You should see output like this:
|
||||
|
||||
```plain
|
||||
● caddy.service - Caddy
|
||||
Loaded: loaded (/lib/systemd/system/caddy.service; enabled; vendor preset: enabled)
|
||||
Active: active (running) since Tue 2022-09-06 21:15:31 MDT; 1 day 1h ago
|
||||
...
|
||||
```
|
||||
|
||||
Ensure it says "enabled" and "active (running)" -- these are crucial for production. (Enabled means the service will be started automatically after a reboot.)
|
||||
|
||||
If Caddy failed to start, the most likely cause is you have another web server running. The output will also show the most recent log lines which you can inspect for error messages. After resolving the issue, run `sudo systemctl start caddy` to try again.
|
||||
|
||||
<aside class="complete">Install Caddy as a service</aside>
|
||||
|
||||
How is your web server's service configured? A unit file (ending with `.service`) contains the service configuration. The [default unit file we provide](https://github.com/caddyserver/dist/blob/master/init/caddy.service) runs Caddy with a configuration file. It tells you the precise `caddy` command, the location of the Caddy config, special permissions, the process' working directory, and any environment variables passed to the process.
|
||||
|
||||
Notice the output above shows the location of the `caddy.service` file. Let's print its contents:
|
||||
|
||||
<pre><code class="cmd bash">cat /lib/systemd/system/caddy.service</code></pre>
|
||||
|
||||
You will see the `ExecStart=` line, which defines the command to execute. The `ExecReload=` line the command that is executed to reload the configuration when you do `systemctl reload caddy`. The `--config` flag in the `caddy` commands is the location of the Caddy configuration file. Take note of this, as its location varies by platform (but it is often `/etc/caddy/Caddyfile`).
|
||||
|
||||
<aside class="complete">Discover the unit configuration</aside>
|
||||
|
||||
- **If you are running Caddy locally on your own computer:** you can go to [http://localhost](http://localhost) in your browser and you should see a slanted page telling you how to get rid of the slanted page. (It's our default "welcome" page to let you know the server is working. 🙃) You can follow those instructions if you want; they're similar to this tutorial but more succinct.
|
||||
|
||||
- **If you are setting up a remote server:** you can either run `curl localhost` on that machine, or you can navigate to the IP address of your server in your web browser or run `curl <ip>` locally.
|
||||
|
||||
## Your first site
|
||||
|
||||
Copy your site's static files (HTML, CSS, JS, images, etc.) into a folder that is accessible to the `caddy` user/group. This folder is called the _site root_. In production, it's often `/var/www/html` and we'll use that path in this tutorial. Expect that everything in this directory will become publicly accessible.
|
||||
|
||||
Once your site files are in place, make sure Caddy can access them; for example:
|
||||
|
||||
<pre><code class="cmd bash">chown -R caddy:caddy /var/www/html</code></pre>
|
||||
|
||||
Next, we need to tell Caddy where to find the site root. Open the configuration file you noted above (e.g. `/etc/caddy/Caddyfile`) and change its `root` directive to point to your site's directory:
|
||||
|
||||
```caddy
|
||||
:80 {
|
||||
root * /var/www/html
|
||||
file_server
|
||||
}
|
||||
```
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
The permissions on this Caddyfile are restricted to prevent tampering and accidental changes. To save changes to this Caddyfile, you may need to open it as root (`sudo`).
|
||||
|
||||
</aside>
|
||||
|
||||
Be sure to save the changes.
|
||||
|
||||
Since we changed the Caddyfile, we need to load the new config into Caddy:
|
||||
|
||||
<pre><code class="cmd bash">sudo systemctl reload caddy</code></pre>
|
||||
|
||||
- **If that failed:** double-check your Caddyfile. Spaces are significant; make sure it looks tidy. Check file and folder permissions. Ensure the path is correct.
|
||||
|
||||
- **If that succeeded:** open your browser to [http://localhost](http://localhost) again and you should see your site! If you don't, make sure the file permissions are correct and that you have an index file in your site root (e.g. `index.html`).
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
Advanced sites often have additional configuration in production to [set headers](/docs/caddyfile/directives/header), enable [compression](/docs/caddyfile/directives/encode) or use compressed [sidecar files](/docs/caddyfile/directives/file_server), and [enable HTTP request logging](/docs/caddyfile/directives/log).
|
||||
|
||||
</aside>
|
||||
|
||||
<aside class="complete">Prepare your site</aside>
|
||||
|
||||
|
||||
## HTTPS
|
||||
|
||||
Given a domain name, Caddy will obtain a TLS certificate for your site and keep it renewed while it stays running. It's all [automatic](/docs/automatic-https)!
|
||||
|
||||
Before continuing, **point your domain to your server's IP address.** This means setting the value of your domain's A/AAAA record(s) to the public IP address of your server.
|
||||
|
||||
Usually this means logging into your DNS provider and creating or changing the A (IPv4) and/or AAAA (IPv6) record for your domain (it can be a subdomain). We'll use `example.com` for this tutorial. Verify it has been set by running `dig example.com`.
|
||||
|
||||
Then, **verify that your server's IP is publicly routable on the standard Web ports (80 and 443).** Ensure there are no firewalls or routers blocking these ports. On a home network, you may need to forward those ports to your machine (just be aware that your machine will become publicly accessible on those ports).
|
||||
|
||||
Once your DNS and network infrastructure are properly configured, **all you need to do is replace `:80` in the Caddyfile with your domain name:**
|
||||
|
||||
```caddy
|
||||
example.com {
|
||||
root * /var/www/html
|
||||
file_server
|
||||
}
|
||||
```
|
||||
|
||||
Then reload the config once again:
|
||||
|
||||
<pre><code class="cmd bash">sudo systemctl reload caddy</code></pre>
|
||||
|
||||
Watch the logs to make sure it works:
|
||||
|
||||
<pre><code class="cmd bash">journalctl -u caddy -f</code></pre>
|
||||
|
||||
- **If it succeeds:** navigate to your site in your browser and see your site served over HTTPS, just like that!
|
||||
- **If it fails:** refer to the [troubleshooting tips](#troubleshooting) below.
|
||||
|
||||
As you have just seen, Caddy serves sites over HTTPS automatically and by default (unless you explicitly configure `http://` or the HTTP port). As long as you keep your network and DNS properly configured, Caddy will keep your certificates renewed automatically.
|
||||
|
||||
Caddy is the only server that works like this!
|
||||
|
||||
<aside class="complete">Serve your site over HTTPS</aside>
|
||||
|
||||
If you don't want to use a public domain name or are running this internally or locally instead, you can easily have Caddy use [fully-managed self-signed certificates](/docs/automatic-https#local-https) by specifying either:
|
||||
|
||||
- your local/internal IP address,
|
||||
- the hostname `localhost`,
|
||||
- or any hostname that ends in `.localhost`
|
||||
|
||||
instead of a registered public domain name.
|
||||
|
||||
|
||||
## Reverse proxy
|
||||
|
||||
Oftentimes, your site consists of a backend application, but you want to put Caddy in front to handle TLS, routing, and other network-related details. Caddy's proxy is easy to use and extremely powerful.
|
||||
|
||||
For example, if we have a backend that provides the site's API endpoints, we can easily proxy those with just 1 additional line of configuration:
|
||||
|
||||
```caddy
|
||||
example.com {
|
||||
root * /var/www/html
|
||||
file_server
|
||||
reverse_proxy /api/* 127.0.0.1:9000
|
||||
}
|
||||
```
|
||||
|
||||
Notice the `reverse_proxy` directive. The first argument, `/api/*`, is a [path matcher](/docs/caddyfile/matchers) which filters only requests within `/api/`. Then it proxies those to the backend app listening on :9000.
|
||||
|
||||
If your backend is a PHP app, simply replace the `reverse_proxy` directive with the `php_fastcgi` directive:
|
||||
|
||||
```caddy
|
||||
example.com {
|
||||
root * /var/www/html
|
||||
file_server
|
||||
php_fastcgi /api/* 127.0.0.1:9000
|
||||
}
|
||||
```
|
||||
|
||||
Make sure the address is the same as your php-fpm listener.
|
||||
|
||||
Note that you don't have to enable a file server or set a site root if you _only_ want to proxy requests. You can enable a proxy by itself:
|
||||
|
||||
|
||||
```caddy
|
||||
example.com {
|
||||
reverse_proxy 127.0.0.1:9000
|
||||
}
|
||||
```
|
||||
|
||||
That config terminates TLS and proxies everything to port 9000.
|
||||
|
||||
<aside class="complete">Add a reverse proxy</aside>
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
The most important task when trying to fix a problem is to first get the error message(s) and/or logs.
|
||||
|
||||
### Debug logs
|
||||
|
||||
Enable debug logging if you haven't already. Put this at the top of your Caddyfile:
|
||||
|
||||
```caddy
|
||||
{
|
||||
debug
|
||||
}
|
||||
```
|
||||
|
||||
A block at the very top of the file without any name is called a [global options block](/docs/caddyfile/options). If you already have a global options block, simply add the `debug` option to it; you can't have two global option blocks.
|
||||
|
||||
Reload your Caddy configuration and you will observe DEBUG-level logs which can give helpful insights!
|
||||
|
||||
|
||||
### Request logs
|
||||
|
||||
Caddy can also log all the HTTP requests it receives (sometimes known as "access logs"). Simply add the `log` directive within your site block. For example:
|
||||
|
||||
```caddy
|
||||
example.com {
|
||||
root * /var/www/html
|
||||
file_server
|
||||
log
|
||||
}
|
||||
```
|
||||
|
||||
These logs are printed to the same place as Caddy's runtime or process logs (stderr), but have the name `http.log.access` so you can tell them apart. Access logs show you great detail about HTTP requests and responses.
|
||||
|
||||
### curl
|
||||
|
||||
If your site isn't working the way you expect, avoid using a web browser unless you know what you're doing. Browser behavior is often overly magical, misleading, inconsistent, and frustrating, as it hides or obfuscates the underlying technical details you need to debug your site.
|
||||
|
||||
Use `curl -v` instead. The `-v` option prints HTTP information including the header which is vital to knowing what is happening. For example:
|
||||
|
||||
<pre><code class="cmd bash">curl -v https://example.com/</code></pre>
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
To perform the exact same HTTP request as your browser, open its dev tools, go to the Network tab, and right-click the request. There should be an option like "Copy as curl". Then paste that into your terminal.
|
||||
|
||||
</aside>
|
||||
|
||||
Obviously, change the URL to the one you are trying to debug. You will see curl establish a TLS connection (if HTTPS), make an HTTP request, then print the resulting status code, response headers, and body. It does not follow redirects, enable compression, cache anything, think it is smarter than you, or do anything unexpected. The `curl` command is your true friend and ally in the war against errors.
|
||||
|
||||
Combined with server logs, curl requests are quite a powerful way to gain insights to what is happening.
|
||||
|
||||
|
||||
### Certificates
|
||||
|
||||
If Caddy is having trouble getting certificates, leave Caddy running while you double-check your network and DNS configurations. These cause the _vast majority_ of problems.
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
Caddy has special programming for handling certificate automation errors. It will retry with other CAs, gradually back off, and use test CAs (if available) until success. It's usually OK to leave it running while you fix any problems.
|
||||
|
||||
</aside>
|
||||
|
||||
Check the error messages: Caddy prints the errors as returned by the CA, so they can be quite helpful. For example, a connection timeout indicates the CA couldn't connect to your server, suggesting a problem with your network configuration or DNS records pointing to the wrong network.
|
||||
|
||||
- Make sure your A/AAAA records are correct.
|
||||
- Make sure ports 80 and 443 are publicly accessible
|
||||
- Make sure Caddy—not another server—is on the receiving end of ports 80 and 443
|
||||
|
||||
### Simplify
|
||||
|
||||
Many times, configuration files contain more than is needed or relevant to troubleshoot a problem. Try removing everything in your config file except the absolute minimum needed to make the site function. For example, you could disable compression or remove headers added in the reverse proxy. Incrementally making changes to your config will tell you lots about what is causing the problem.
|
||||
|
||||
And if nothing undesireable happens or breaks when you remove some config, then you removed config that was unnecessary. Congrats!
|
||||
|
||||
If you're behind a CDN like Cloudflare, consider disabling it temporarily while you troubleshoot. If the problem goes away, you can know it is related to your CDN configuration.
|
||||
|
||||
<aside class="complete">Learn how to troubleshoot problems</aside>
|
||||
|
39
src/docs/markdown/index.md
Normal file
39
src/docs/markdown/index.md
Normal file
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
title: Welcome
|
||||
---
|
||||
|
||||
# Welcome to Caddy
|
||||
|
||||
Caddy is a powerful, extensible platform to serve your sites, services, and apps, written in Go. If you're new to Caddy, the way you serve the Web is about to change.
|
||||
|
||||
## Introduction
|
||||
|
||||
Most people use Caddy as a web server or proxy, but at its core, Caddy is a server of servers. With the [requisite modules](/docs/modules/), it can take on the role of any long-running process!
|
||||
|
||||
Configuration is both dynamic and exportable with [Caddy's API](/docs/api). Although no config files required, you can still use them; most people's favorite way of configuring Caddy is using the [Caddyfile](/docs/caddyfile). The format of the config document takes many forms with [config adapters](/docs/config-adapters), but Caddy's native config language is [JSON](/docs/json/).
|
||||
|
||||
Caddy compiles for all major platforms and has no runtime dependencies.
|
||||
|
||||
|
||||
## First time?
|
||||
|
||||
No problem! **We suggest that _everyone_ regardless of experience go through our [Getting Started guide](/docs/getting-started).** It will give you a well-rounded perspective on your new web server that will be invaluable as you continue learning.
|
||||
|
||||
If you only have a few minutes and need to hit the ground running, try one of our [quick starts](/docs/quick-starts).
|
||||
|
||||
For expanded content like specific examples, check out [our community wiki](https://caddy.community/c/wiki/13) - then contribute to it!
|
||||
|
||||
We recommend sticking to these official resources to [install](/docs/install), [configure](/docs/caddyfile), and [run](/docs/command-line) Caddy, rather than running commands or copying config snippets from random blogs and Q&A boards. You will find that our material is generally more accurate and up-to-date. We also encourage you to craft your own configurations to ensure that you understand how your server works so you'll be more able to fix problems if they arise later on.
|
||||
|
||||
But whatever you do, enjoy using your new web server. Caddy is an experience unlike any other server software you've used!
|
||||
|
||||
|
||||
## Getting help
|
||||
|
||||
If you need help using Caddy, please ask nicely in [our community forum](https://caddy.community). We would be happy to help you. All we ask is that you fill out the help template as thoroughly as possible, and pay it forward by helping others. We always need more helpers.
|
||||
|
||||
Only use [our issue tracker](https://github.com/caddyserver/caddy/issues) if you've positively identified a bug in Caddy or have a specific feature request.
|
||||
|
||||
This website is [maintained on GitHub](https://github.com/caddyserver/website). To submit improvements, open an issue or pull request.
|
||||
|
||||
Thank you for participating in our community! We hope Caddy will serve you well.
|
170
src/docs/markdown/install.md
Normal file
170
src/docs/markdown/install.md
Normal file
|
@ -0,0 +1,170 @@
|
|||
---
|
||||
title: "Install"
|
||||
---
|
||||
|
||||
# Install
|
||||
|
||||
This page describes various methods for installing Caddy on your system.
|
||||
|
||||
**Official:**
|
||||
|
||||
- [Static binaries](#static-binaries)
|
||||
- [Debian, Ubuntu, Raspbian packages](#debian-ubuntu-raspbian)
|
||||
- [Fedora, RedHat, CentOS packages](#fedora-redhat-centos)
|
||||
- [Arch Linux, Manjaro, Parabola packages](#arch-linux-manjaro-parabola)
|
||||
- [Docker image](#docker)
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
Our [official packages](https://github.com/caddyserver/dist) come only with the standard modules. If you need third-party plugins, [build from source with `xcaddy`](/docs/build#xcaddy) or use [our download page](/download).
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
**Community-maintained:**
|
||||
|
||||
- [Homebrew](#homebrew)
|
||||
- [Webi](#webi)
|
||||
- [Chocolatey](#chocolatey)
|
||||
- [Ansible](#ansible)
|
||||
- [Scoop](#scoop)
|
||||
- [Termux](#termux)
|
||||
|
||||
|
||||
## Static binaries
|
||||
|
||||
**If installing onto a production system, we recommend using our official package for your distro if available below.**
|
||||
|
||||
1. Obtain a Caddy binary:
|
||||
- [from releases on GitHub](https://github.com/caddyserver/caddy/releases) (expand "Assets")
|
||||
- [from our download page](/download)
|
||||
- [by building from source](/docs/build) (either with `go` or `xcaddy`)
|
||||
2. [Install Caddy as a system service.](/docs/running#manual-installation) This is strongly recommended, especially for production servers.
|
||||
|
||||
Place the binary in one of your `$PATH` (or `%PATH%` on Windows) directories so you can run `caddy` without typing the full path of the executable file. (Run `echo $PATH` to see the list of directories that qualify.)
|
||||
|
||||
You can upgrade static binaries by replacing them with newer versions and restarting Caddy. The [`caddy upgrade` command](/docs/command-line#caddy-upgrade) can make this easy.
|
||||
|
||||
|
||||
|
||||
## Debian, Ubuntu, Raspbian
|
||||
|
||||
Installing this package automatically starts and runs Caddy as a [systemd service](/docs/running#linux-service) named `caddy`. It also comes with an optional `caddy-api` service which is _not_ enabled by default, but should be used if you primarily configure Caddy via its API instead of config files.
|
||||
|
||||
**Stable releases:**
|
||||
|
||||
<pre><code class="cmd"><span class="bash">sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https</span>
|
||||
<span class="bash">curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg</span>
|
||||
<span class="bash">curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list</span>
|
||||
<span class="bash">sudo apt update</span>
|
||||
<span class="bash">sudo apt install caddy</span></code></pre>
|
||||
|
||||
**Testing releases** (includes betas and release candidates):
|
||||
|
||||
<pre><code class="cmd"><span class="bash">sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https</span>
|
||||
<span class="bash">curl -1sLf 'https://dl.cloudsmith.io/public/caddy/testing/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-testing-archive-keyring.gpg</span>
|
||||
<span class="bash">curl -1sLf 'https://dl.cloudsmith.io/public/caddy/testing/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-testing.list</span>
|
||||
<span class="bash">sudo apt update</span>
|
||||
<span class="bash">sudo apt install caddy</span></code></pre>
|
||||
|
||||
[**View the Cloudsmith repos**](https://cloudsmith.io/~caddy/repos/)
|
||||
|
||||
If you wish to use the packaged support files (systemd services, bash completion and default configuration) with a custom Caddy build, instructions can be [found here](https://caddyserver.com/docs/build#package-support-files-for-custom-builds-for-debianubunturaspbian).
|
||||
|
||||
|
||||
## Fedora, RedHat, CentOS
|
||||
|
||||
This package comes with both of Caddy's [systemd service](/docs/running#linux-service) unit files, but does not enable them by default.
|
||||
|
||||
Fedora or RHEL/CentOS 8:
|
||||
|
||||
<pre><code class="cmd"><span class="bash">dnf install 'dnf-command(copr)'</span>
|
||||
<span class="bash">dnf copr enable @caddy/caddy</span>
|
||||
<span class="bash">dnf install caddy</span></code></pre>
|
||||
|
||||
RHEL/CentOS 7:
|
||||
|
||||
<pre><code class="cmd"><span class="bash">yum install yum-plugin-copr</span>
|
||||
<span class="bash">yum copr enable @caddy/caddy</span>
|
||||
<span class="bash">yum install caddy</span></code></pre>
|
||||
|
||||
[**View the Caddy COPR**](https://copr.fedorainfracloud.org/coprs/g/caddy/caddy/)
|
||||
|
||||
|
||||
## Arch Linux, Manjaro, Parabola
|
||||
|
||||
This package comes with both of Caddy's [systemd service](/docs/running#linux-service) unit files, but does not enable them by default.
|
||||
|
||||
<pre><code class="cmd"><span class="bash">pacman -Syu caddy</span></code></pre>
|
||||
|
||||
[**View Caddy in the Arch Linux repositories**](https://archlinux.org/packages/community/x86_64/caddy/)
|
||||
|
||||
|
||||
## Docker
|
||||
|
||||
<pre><code class="cmd bash">docker pull caddy</code></pre>
|
||||
|
||||
[**View on Docker Hub**](https://hub.docker.com/_/caddy)
|
||||
|
||||
|
||||
## Homebrew
|
||||
|
||||
_Note: This is a community-maintained installation method._
|
||||
|
||||
<pre><code class="cmd bash">brew install caddy</code></pre>
|
||||
|
||||
[**View the Homebrew formula**](https://formulae.brew.sh/formula/caddy)
|
||||
|
||||
|
||||
## Webi
|
||||
|
||||
_Note: This is a community-maintained installation method._
|
||||
|
||||
Linux and macOS:
|
||||
|
||||
<pre><code class="cmd bash">curl -sS https://webi.sh/caddy | sh</code></pre>
|
||||
|
||||
Windows:
|
||||
|
||||
<pre><code class="cmd">curl.exe https://webi.ms/caddy | powershell</code></pre>
|
||||
|
||||
You may need to adjust the Windows firewall rules to allow non-localhost incoming connections.
|
||||
|
||||
[**View on Webi**](https://webinstall.dev/caddy)
|
||||
|
||||
|
||||
## Chocolatey
|
||||
|
||||
_Note: This is a community-maintained installation method._
|
||||
|
||||
<pre><code class="cmd">choco install caddy</code></pre>
|
||||
|
||||
[**View the Chocolatey package**](https://chocolatey.org/packages/caddy)
|
||||
|
||||
|
||||
## Ansible
|
||||
|
||||
_Note: This is a community-maintained installation method._
|
||||
|
||||
<pre><code class="cmd bash">ansible-galaxy install nvjacobo.caddy</code></pre>
|
||||
|
||||
[**View the Ansible role repository**](https://github.com/nvjacobo/caddy)
|
||||
|
||||
|
||||
## Scoop
|
||||
|
||||
_Note: This is a community-maintained installation method._
|
||||
|
||||
<pre><code class="cmd">scoop install caddy</code></pre>
|
||||
|
||||
[**View the Scoop manifest**](https://github.com/ScoopInstaller/Main/blob/master/bucket/caddy.json)
|
||||
|
||||
|
||||
## Termux
|
||||
|
||||
_Note: This is a community-maintained installation method._
|
||||
|
||||
<pre><code class="cmd">pkg install caddy</code></pre>
|
||||
|
||||
[**View the Termux build.sh file**](https://github.com/termux/termux-packages/blob/master/packages/caddy/build.sh)
|
||||
|
277
src/docs/markdown/introduction.md
Normal file
277
src/docs/markdown/introduction.md
Normal file
|
@ -0,0 +1,277 @@
|
|||
---
|
||||
title: "Introduction"
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
||||
Welcome to Caddy! This tutorial will explore the basics of using Caddy and help you get familiar with it at a high level.
|
||||
|
||||
**Objectives:**
|
||||
- 🔲 Run the daemon
|
||||
- 🔲 Try the API
|
||||
- 🔲 Give Caddy a config
|
||||
- 🔲 Test config
|
||||
- 🔲 Make a Caddyfile
|
||||
- 🔲 Use the config adapter
|
||||
- 🔲 Start with an initial config
|
||||
- 🔲 Compare JSON and Caddyfile
|
||||
- 🔲 Compare API and config files
|
||||
- 🔲 Run in the background
|
||||
- 🔲 Zero-downtime config reload
|
||||
|
||||
**Prerequisites:**
|
||||
- Basic terminal / command line skills
|
||||
- Basic text editor skills
|
||||
- `caddy` and `curl` in your PATH
|
||||
|
||||
---
|
||||
|
||||
**If you [installed Caddy](/docs/install) from a package manager, Caddy might already be running as a service. If so, please stop the service before doing this tutorial.**
|
||||
|
||||
Let's start by running it:
|
||||
|
||||
<pre><code class="cmd bash">caddy</code></pre>
|
||||
|
||||
Oops; without a subcommand, the `caddy` command only displays help text. You can use this any time you forget what to do.
|
||||
|
||||
To start Caddy as a daemon, use the `run` subcommand:
|
||||
|
||||
<pre><code class="cmd bash">caddy run</code></pre>
|
||||
|
||||
<aside class="complete">Run the daemon</aside>
|
||||
|
||||
This blocks forever, but what is it doing? At the moment... nothing. By default, Caddy's configuration ("config") is blank. We can verify this using the [admin API](/docs/api) in another terminal:
|
||||
|
||||
<pre><code class="cmd bash">curl localhost:2019/config/</code></pre>
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
This is **not** your website: the administration endpoint at localhost:2019 is used for controlling Caddy and is restricted to localhost by default.
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
<aside class="complete">Try the API</aside>
|
||||
|
||||
We can make Caddy useful by giving it a config. This can be done many ways, but we'll start by making a POST request to the [/load](/docs/api#post-load) endpoint using `curl` in the next section.
|
||||
|
||||
|
||||
|
||||
## Your first config
|
||||
|
||||
To prepare our request, we need to make a config. At its core, Caddy's configuration is simply a [JSON document](/docs/json/).
|
||||
|
||||
Save this to a JSON file (e.g. `caddy.json`):
|
||||
|
||||
```json
|
||||
{
|
||||
"apps": {
|
||||
"http": {
|
||||
"servers": {
|
||||
"example": {
|
||||
"listen": [":2015"],
|
||||
"routes": [
|
||||
{
|
||||
"handle": [{
|
||||
"handler": "static_response",
|
||||
"body": "Hello, world!"
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
You do not have to use config files, but we are for this tutorial. Caddy's [admin API](/docs/api) is designed for use by other programs or scripts.
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
Then upload it:
|
||||
|
||||
<pre><code class="cmd bash">curl localhost:2019/load \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @caddy.json
|
||||
</code></pre>
|
||||
|
||||
<aside class="complete">Give Caddy a config</aside>
|
||||
|
||||
We can verify that Caddy applied our new config with another GET request:
|
||||
|
||||
<pre><code class="cmd bash">curl localhost:2019/config/</code></pre>
|
||||
|
||||
Test that it works by going to [localhost:2015](http://localhost:2015) in your browser or use `curl`:
|
||||
|
||||
<pre><code class="cmd"><span class="bash">curl localhost:2015</span>
|
||||
Hello, world!</code></pre>
|
||||
|
||||
If you see _Hello, world!_, then congrats -- it's working! It's always a good idea to make sure your config works as you expect, especially before deploying into production.
|
||||
|
||||
<aside class="complete">Test config</aside>
|
||||
|
||||
|
||||
## Your first Caddyfile
|
||||
|
||||
That was _kind of a lot of work_ just for Hello World.
|
||||
|
||||
Another way to configure Caddy is with the [**Caddyfile**](/docs/caddyfile). The same config we wrote in JSON above can be expressed simply as:
|
||||
|
||||
```caddy
|
||||
:2015
|
||||
|
||||
respond "Hello, world!"
|
||||
```
|
||||
|
||||
|
||||
Save that to a file named `Caddyfile` (no extension) in the current directory.
|
||||
|
||||
<aside class="complete">Make a Caddyfile</aside>
|
||||
|
||||
Stop Caddy if it is already running (Ctrl+C), then run:
|
||||
|
||||
<pre><code class="cmd bash">caddy adapt</code></pre>
|
||||
|
||||
Or if you stored the Caddyfile somewhere else or named it something other than `Caddyfile`:
|
||||
|
||||
<pre><code class="cmd bash">caddy adapt --config /path/to/Caddyfile</code></pre>
|
||||
|
||||
You will see JSON output! What happened here?
|
||||
|
||||
We just used a [_config adapter_](/docs/config-adapters) to convert our Caddyfile to Caddy's native JSON structure.
|
||||
|
||||
<aside class="complete">Use the config adapter</aside>
|
||||
|
||||
While we could take that output and make another API request, we can skip all those steps because the `caddy` command can do it for us. If there is a file called Caddyfile in the current directory and no other config is specified, Caddy will load the Caddyfile, adapt it for us, and run it right away.
|
||||
|
||||
Now that there is a Caddyfile in the current folder, let's do `caddy run` again:
|
||||
|
||||
<pre><code class="cmd bash">caddy run</code></pre>
|
||||
|
||||
Or if your Caddyfile is somewhere else:
|
||||
|
||||
<pre><code class="cmd bash">caddy run --config /path/to/Caddyfile</code></pre>
|
||||
|
||||
(If it is called something else that doesn't start with "Caddyfile", you will need to specify `--adapter caddyfile`.)
|
||||
|
||||
You can now try loading your site again and you will see that it is working!
|
||||
|
||||
<aside class="complete">Start with an initial config</aside>
|
||||
|
||||
As you can see, there are several ways you can start Caddy with an initial config:
|
||||
|
||||
- A file named Caddyfile in the current directory
|
||||
- The `--config` flag (optionally with the `--adapter` flag)
|
||||
- The `--resume` flag (if a config was loaded previously)
|
||||
|
||||
|
||||
## JSON vs. Caddyfile
|
||||
|
||||
Now you know that the Caddyfile is just converted to JSON for you.
|
||||
|
||||
The Caddyfile seems easier than JSON, but should you always use it? There are pros and cons to each approach. The answer depends on your requirements and use case.
|
||||
|
||||
JSON | Caddyfile
|
||||
-----|----------
|
||||
Easy to generate | Easy to craft by hand
|
||||
Easily programmable | Awkward to automate
|
||||
Extremely expressive | Moderately expressive
|
||||
Full range of Caddy functionality | Most of Caddy functionality
|
||||
Allows config traversal | Cannot traverse within Caddyfile
|
||||
Partial config changes | Whole config changes only
|
||||
Can be exported | Cannot be exported
|
||||
Compatible with all API endpoints | Compatible with some API endpoints
|
||||
Documentation generated automatically | Documentation is hand-written
|
||||
Ubiquitous | Niche
|
||||
More efficient | More computational
|
||||
Kind of boring | Kind of fun
|
||||
**Learn more: [JSON structure](/docs/json/)** | **Learn more: [Caddyfile docs](/docs/caddyfile)**
|
||||
|
||||
You will need to decide which is best for your use case.
|
||||
|
||||
It is important to note that both JSON and the Caddyfile (and [any other supported config adapter](/docs/config-adapters)) can be used with [Caddy's API](/docs/api). However, you get the full range of Caddy's functionality and API features if you use JSON. If using a config adapter, the only way to load or change the config with the API is the [/load endpoint](/docs/api#post-load).
|
||||
|
||||
<aside class="complete">Compare JSON and Caddyfile</aside>
|
||||
|
||||
|
||||
## API vs. Config files
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
Under the hood, even config files go through Caddy's API endpoints; the `caddy` command just wraps up those API calls for you.
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
You will also want to decide whether your workflow is API-based or CLI-based. (You _can_ use both the API and config files on the same server, but we don't recommend it: best to have one source of truth.)
|
||||
|
||||
API | Config files
|
||||
----|-------------
|
||||
Make config changes with HTTP requests | Make config changes with shell commands
|
||||
Easy to scale | Difficult to scale
|
||||
Difficult to manage by hand | Easy to manage by hand
|
||||
Really fun | Also fun
|
||||
**Learn more: [API tutorial](/docs/api-tutorial)** | **Learn more: [Caddyfile tutorial](/docs/caddyfile-tutorial)**
|
||||
|
||||
<aside class="tip">
|
||||
Manually managing a server's configuration with the API is totally doable with proper tools, for example: any REST client application.
|
||||
</aside>
|
||||
|
||||
The choice of API or config file workflow is orthogonal to the use of config adapters: you can use JSON but store it in a file and use the command line interface; conversely, you can also use the Caddyfile with the API.
|
||||
|
||||
But most people will use JSON+API or Caddyfile+CLI combinations.
|
||||
|
||||
As you can see, Caddy is well-suited for a wide variety of use cases and deployments!
|
||||
|
||||
<aside class="complete">Compare API and config files</aside>
|
||||
|
||||
|
||||
|
||||
## Start, stop, run
|
||||
|
||||
Since Caddy is a server, it runs indefinitely. That means your terminal won't unblock after you execute `caddy run` until the process is terminated (usually with Ctrl+C).
|
||||
|
||||
Although `caddy run` is the most common and is usually recommended (especially when making a system service!), you can alternatively use `caddy start` to start Caddy and have it run in the background:
|
||||
|
||||
<pre><code class="cmd bash">caddy start</code></pre>
|
||||
|
||||
This will let you use your terminal again, which is convenient in some interactive headless environments.
|
||||
|
||||
You will then have to stop the process yourself, since Ctrl+C won't stop it for you:
|
||||
|
||||
<pre><code class="cmd bash">caddy stop</code></pre>
|
||||
|
||||
Or use [the /stop endpoint](/docs/api#post-stop) of the API.
|
||||
|
||||
<aside class="complete">Run in the background</aside>
|
||||
|
||||
|
||||
## Reloading config
|
||||
|
||||
Your server can perform zero-downtime config reloads/changes.
|
||||
|
||||
All [API endpoints](/docs/api) that load or change config are graceful with zero downtime.
|
||||
|
||||
When using the command line, however, it may be tempting to use Ctrl+C to stop your server and then restart it again to pick up the new configuration. Don't do this: stopping and starting the server is orthogonal to config changes, and will result in downtime.
|
||||
|
||||
<aside class="tip">
|
||||
Stopping your server will cause the server to go down.
|
||||
</aside>
|
||||
|
||||
Instead, use the [`caddy reload`](/docs/command-line#caddy-reload) command for a graceful config change:
|
||||
|
||||
<pre><code class="cmd bash">caddy reload</code></pre>
|
||||
|
||||
This actually just uses the API under the hood. It will load and, if necessary, adapt your config file to JSON, then gracefully replace the active configuration without downtime.
|
||||
|
||||
If there are any errors loading the new config, Caddy rolls back to the last working config.
|
||||
|
||||
<aside class="tip">
|
||||
Technically, the new config is started before the old config is stopped, so for a brief time, both configs are running! If the new config fails, it aborts with an error, while the old one is simply not stopped.
|
||||
</aside>
|
||||
|
||||
<aside class="complete">Zero-downtime config reload</aside>
|
165
src/docs/markdown/logging.md
Normal file
165
src/docs/markdown/logging.md
Normal file
|
@ -0,0 +1,165 @@
|
|||
---
|
||||
title: How Logging Works
|
||||
---
|
||||
|
||||
How Logging Works
|
||||
=================
|
||||
|
||||
Caddy has powerful and flexible logging facilities, but they may be different than what you're used to, especially if you're coming from more archaic shared hosting or other legacy web servers.
|
||||
|
||||
|
||||
## Overview
|
||||
|
||||
There are two main aspects of logging: emission and consumption.
|
||||
|
||||
**Emission** means to produce messages. It consists of three steps:
|
||||
|
||||
1. Gathering relevant information (context)
|
||||
2. Building a useful representation (encoding)
|
||||
3. Sending that representation to an output (writing)
|
||||
|
||||
This functionality is baked into the core of Caddy, enabling any part of the Caddy code base or that of modules (plugins) to emit logs.
|
||||
|
||||
**Consumption** is the intake & processing of messages. In order to be useful, emitted logs must be consumed. Logs that are merely written but never read provide no value. Consuming logs can be as simple as an administrator reading console output, or as advanced as attaching a log aggregation tool or cloud service to filter, count, and index log messages.
|
||||
|
||||
### Caddy's role
|
||||
|
||||
_Caddy is a log emitter_. It does not consume logs, except for the minimum processing required to encode and write logs. This is important because it keeps Caddy's core simpler, leading to fewer bugs and edge cases, while reducing maintenance burden. Ultimately, log processing is out of the scope of Caddy core.
|
||||
|
||||
However, there's always the possibility for a Caddy app module that consumes logs. (It just doesn't exist yet, to our knowledge.)
|
||||
|
||||
|
||||
## Structured logs
|
||||
|
||||
As with most modern applications, Caddy's logs are _structured_. This means that the information in a message is not simply an opaque string or byte slice. Instead, data remains strongly typed and is keyed by individual _field names_ until it is time to encode the message and write it out.
|
||||
|
||||
Compare traditional unstructured logs—like the archaic Common Log Format (CLF)—commonly used with traditional HTTP servers:
|
||||
|
||||
```
|
||||
127.0.0.1 - - [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.1" 200 2326
|
||||
```
|
||||
|
||||
This format "has structure" but is not "structured": it can only be used to log HTTP requests. There is no (efficient) way to encode it differently, because it is an opaque string of bytes. It is also missing a lot of information. It does not even include the Host header of the request! This log format is only useful when hosting a single site, and for getting the most basic of information about requests.
|
||||
|
||||
<aside class="tip">
|
||||
The lack of host information in CLF is why these logs usually need to be written to separate files when hosting more than one site: there is no way to know the Host header from the request otherwise!
|
||||
</aside>
|
||||
|
||||
Now compare an equivalent structured log message from Caddy, encoded as JSON and formatted nicely for display:
|
||||
|
||||
```json
|
||||
{
|
||||
"level": "info",
|
||||
"ts": 1646861401.5241024,
|
||||
"logger": "http.log.access",
|
||||
"msg": "handled request",
|
||||
"request": {
|
||||
"remote_ip": "127.0.0.1",
|
||||
"remote_port": "41342",
|
||||
"proto": "HTTP/2.0",
|
||||
"method": "GET",
|
||||
"host": "localhost",
|
||||
"uri": "/",
|
||||
"headers": {
|
||||
"User-Agent": ["curl/7.82.0"],
|
||||
"Accept": ["*/*"],
|
||||
"Accept-Encoding": ["gzip, deflate, br"],
|
||||
},
|
||||
"tls": {
|
||||
"resumed": false,
|
||||
"version": 772,
|
||||
"cipher_suite": 4865,
|
||||
"proto": "h2",
|
||||
"server_name": "example.com"
|
||||
}
|
||||
},
|
||||
"user_id": "",
|
||||
"duration": 0.000929675,
|
||||
"size": 10900,
|
||||
"status": 200,
|
||||
"resp_headers": {
|
||||
"Server": ["Caddy"],
|
||||
"Content-Encoding": ["gzip"],
|
||||
"Content-Type": ["text/html; charset=utf-8"],
|
||||
"Vary": ["Accept-Encoding"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can see how the structured log is much more useful and contains much more information. The abundance of information in this log message is not only useful, but it comes at virtually no performance overhead: Caddy's logs are zero-allocation. Structured logs have no restrictions on data types or context: they can be used in any code path and include any kind of information.
|
||||
|
||||
Because the logs are structured and strongly-typed, they can be encoded into any format. So if you don't want to work with JSON, logs can be encoded into any other representation. Caddy supports others through [log encoder modules](/docs/json/logging/logs/encoder/), and even more can be added.
|
||||
|
||||
**Most importantly** in the distinction between structured logs and legacy formats, with a performance penalty a structured log [can be transformed into the legacy Common Log Format](https://github.com/caddyserver/transform-encoder), but not the other way around. It is non-trivial (or at least inefficient) to go from CLF to structured formats, and impossible considering the lack of information.
|
||||
|
||||
In essence, efficient, structured logging generally promotes these philosophies:
|
||||
|
||||
- Too many logs are better than too few
|
||||
- Filtering is better than discarding
|
||||
- Defer encoding for greater flexibility and interoperability
|
||||
|
||||
|
||||
## Emission
|
||||
|
||||
In code, a log emission resembles the following:
|
||||
|
||||
```go
|
||||
logger.Debug("proxy roundtrip",
|
||||
zap.String("upstream", di.Upstream.String()),
|
||||
zap.Object("request", caddyhttp.LoggableHTTPRequest{Request: req}),
|
||||
zap.Object("headers", caddyhttp.LoggableHTTPHeader(res.Header)),
|
||||
zap.Duration("duration", duration),
|
||||
zap.Int("status", res.StatusCode),
|
||||
)
|
||||
```
|
||||
|
||||
<aside class="tip">
|
||||
This is an actual line of code from Caddy's reverse proxy. This line is what allows you to inspect requests to configured upstreams when you have debug logging enabled. It is an invaluable piece of data when troubleshooting!
|
||||
</aside>
|
||||
|
||||
You can see that this one function call contains the log level, a message, and several fields of data. All these are strongly-typed, and Caddy uses a zero-allocation logging library so log emissions are quick and efficient with almost no overhead.
|
||||
|
||||
The `logger` variable is a `zap.Logger` that may have any amount of context associated with it, which includes both a name and fields of data. This allows loggers to "inherit" from parent contexts quite nicely, enabling advanced tracing and metrics.
|
||||
|
||||
From there, the message is sent through a highly efficient processing pipeline where it is encoded and written.
|
||||
|
||||
|
||||
## Logging pipeline
|
||||
|
||||
As you saw above, messages are emitted by **loggers**. The messages are then sent to **logs** for processing.
|
||||
|
||||
Caddy lets you [configure multiple logs](/docs/json/logging/logs/) which can process messages. A log consists of an encoder, writer, minimum level, sampling ratio, and a list of loggers to include or exclude. In Caddy, there is always a default log named `default`. You can customize it by specifying a log keyed as `"default"` in [this object](/docs/json/logging/logs/) in the config.
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
Now would be a good time to [explore Caddy's logging docs](/docs/json/logging/) so you can become familiar with the structure and parameters we're talking about.
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
- **Encoder:** The format for the log. Transforms the in-memory data representation into a byte slice. Encoders have access to all fields of a log message.
|
||||
- **Writer:** The log output. Can be any log writer module, like to a file or network socket. It simply writes bytes.
|
||||
- **Level:** Logs have various levels, from DEBUG to FATAL. Messages lower than the specified level will be ignored by the log.
|
||||
- **Sampling:** Extremely hot paths may emit more logs than can be processed effectively; enabling sampling is a way to reduce the load while still yielding a representative sample of messages.
|
||||
- **Include/exclude:** Each message is emitted by a logger, which has a name (usually derived from the module ID). Logs can include or exclude messages from certain loggers.
|
||||
|
||||
When a log message is emitted from Caddy:
|
||||
|
||||
- The originating logger's name is checked against each log's include/exclude list; if included (or not excluded), it is admitted into that log.
|
||||
- If sampling is enabled, a quick calculation determines whether to keep the log message.
|
||||
- The message is encoded using the log's configured encoder.
|
||||
- The encoded bytes are then written to the log's configured writer.
|
||||
|
||||
By default, all messages go to all configured logs. This adheres to the values of structured logging described above. You can limit which messages go to which logs by setting their include/exclude lists, but this is mostly for filtering messages from different modules; it is not intended to be used like a log aggregation service. To keep Caddy's logging pipeline streamlined and efficient, advanced processing of log messages is deferred to consumption.
|
||||
|
||||
## Consumption
|
||||
|
||||
After messages are sent to an output, a consumer will read them in, parse them, and handle them accordingly.
|
||||
|
||||
This is a very different problem domain from emitting logs, and the core of Caddy does not handle consumption (although a Caddy app module certainly could). There are numerous tools you can use for processing streams of JSON messages (or other formats) and viewing, filtering, indexing, and querying logs. You could even write or implement your own.
|
||||
|
||||
For example, if you run legacy software that requires CLF separated into different files based on a particular field (e.g. hostname), you could use or write a simple tool that reads in the JSON, calls `sprintf()` to create a CLF string, then write it to a file based on the value in the `request.host` field.
|
||||
|
||||
Caddy's logging facilities can be used to implement metrics and tracing as well: metrics basically count messages with certain characteristics, and tracing links multiple messages together based on commonalities between them.
|
||||
|
||||
There are countless possibilities for what you can do by consuming Caddy's logs!
|
269
src/docs/markdown/metrics.md
Normal file
269
src/docs/markdown/metrics.md
Normal file
|
@ -0,0 +1,269 @@
|
|||
---
|
||||
title: Monitoring Caddy with Prometheus metrics
|
||||
---
|
||||
|
||||
# Monitoring Caddy with Prometheus metrics
|
||||
|
||||
Whether you're running thousands of Caddy instances in the cloud, or a single
|
||||
Caddy server on an embedded device, it's likely that at some point you'll want
|
||||
to have a high-level overview of what Caddy is doing, and how long it's taking.
|
||||
In other words, you're going to want to be able to _monitor_ Caddy.
|
||||
|
||||
## Prometheus
|
||||
|
||||
[Prometheus](https://prometheus.io) is a monitoring platform that collects
|
||||
metrics from monitored targets by scraping metrics HTTP endpoints on these
|
||||
targets. As well as helping you to display metrics with a dashboarding tool like [Grafana](https://grafana.com/docs/grafana/latest/getting-started/what-is-grafana/), Prometheus is also used for [alerting](https://prometheus.io/docs/alerting/latest/overview/).
|
||||
|
||||
Like Caddy, Prometheus is written in Go and distributed as a single binary. To
|
||||
install it, see the [Prometheus Installation docs](https://prometheus.io/docs/prometheus/latest/installation/),
|
||||
or on MacOS just run `brew install prometheus`.
|
||||
|
||||
Read the [Prometheus docs](https://prometheus.io/docs/introduction/first_steps/)
|
||||
if you're brand new to Prometheus, otherwise read on!
|
||||
|
||||
To configure Prometheus to scrape from Caddy you'll need a YAML configuration
|
||||
file similar to this:
|
||||
|
||||
```yaml
|
||||
# prometheus.yaml
|
||||
global:
|
||||
scrape_interval: 15s # default is 1 minute
|
||||
|
||||
scrape_configs:
|
||||
- job_name: caddy
|
||||
static_configs:
|
||||
- targets: ['localhost:2019']
|
||||
```
|
||||
|
||||
You can then start up Prometheus like this:
|
||||
|
||||
```console
|
||||
$ prometheus --config.file=prometheus.yaml
|
||||
```
|
||||
|
||||
## Caddy's metrics
|
||||
|
||||
Like any process monitored with Prometheus, Caddy exposes an HTTP endpoint
|
||||
that responds in the [Prometheus exposition format](https://prometheus.io/docs/instrumenting/exposition_formats/#text-based-format).
|
||||
Caddy's Prometheus client is also configured to respond with the [OpenMetrics exposition format](https://pkg.go.dev/github.com/prometheus/client_golang@v1.7.1/prometheus/promhttp#HandlerOpts)
|
||||
if negotiated (that is, if the `Accept` header is set to
|
||||
`application/openmetrics-text; version=0.0.1`).
|
||||
|
||||
By default, there is a `/metrics` endpoint available at the [admin API](/docs/api)
|
||||
(i.e. http://localhost:2019/metrics). But if the admin API is
|
||||
disabled or you wish to listen on a different port or path, you can use the
|
||||
[`metrics` handler](/docs/caddyfile/directives/metrics) to configure this.
|
||||
|
||||
You can see the metrics with any browser or HTTP client like `curl`:
|
||||
|
||||
```console
|
||||
$ curl http://localhost:2019/metrics
|
||||
# HELP caddy_admin_http_requests_total Counter of requests made to the Admin API's HTTP endpoints.
|
||||
# TYPE caddy_admin_http_requests_total counter
|
||||
caddy_admin_http_requests_total{code="200",handler="metrics",method="GET",path="/metrics"} 2
|
||||
# HELP caddy_http_request_duration_seconds Histogram of round-trip request durations.
|
||||
# TYPE caddy_http_request_duration_seconds histogram
|
||||
caddy_http_request_duration_seconds_bucket{code="308",handler="static_response",method="GET",server="remaining_auto_https_redirects",le="0.005"} 1
|
||||
caddy_http_request_duration_seconds_bucket{code="308",handler="static_response",method="GET",server="remaining_auto_https_redirects",le="0.01"} 1
|
||||
caddy_http_request_duration_seconds_bucket{code="308",handler="static_response",method="GET",server="remaining_auto_https_redirects",le="0.025"} 1
|
||||
...
|
||||
```
|
||||
|
||||
There are a number of metrics you'll see, that broadly fall under 4 categories:
|
||||
|
||||
- Runtime metrics
|
||||
- Admin API metrics
|
||||
- HTTP Middleware metrics
|
||||
- Reverse proxy metrics
|
||||
|
||||
### Runtime metrics
|
||||
|
||||
These metrics cover the internals of the Caddy process, and are provided
|
||||
automatically by the Prometheus Go Client. They are prefixed with `go_*` and
|
||||
`process_*`.
|
||||
|
||||
Note that the `process_*` metrics are only collected on Linux and Windows.
|
||||
|
||||
See the documentation for the [Go Collector](https://pkg.go.dev/github.com/prometheus/client_golang/prometheus#NewGoCollector),
|
||||
[Process Collector](https://pkg.go.dev/github.com/prometheus/client_golang/prometheus#NewProcessCollector),
|
||||
and [BuildInfo Collector](https://pkg.go.dev/github.com/prometheus/client_golang/prometheus#NewBuildInfoCollector).
|
||||
|
||||
### Admin API metrics
|
||||
|
||||
These are metrics that help to monitor the Caddy admin API. Each of the admin
|
||||
endpoints is instrumented to track request counts and errors.
|
||||
|
||||
These metrics are prefixed with `caddy_admin_*`.
|
||||
|
||||
For example:
|
||||
|
||||
```console
|
||||
$ curl -s http://localhost:2019/metrics | grep ^caddy_admin
|
||||
caddy_admin_http_requests_total{code="200",handler="admin",method="GET",path="/config/"} 1
|
||||
caddy_admin_http_requests_total{code="200",handler="admin",method="GET",path="/debug/pprof/"} 2
|
||||
caddy_admin_http_requests_total{code="200",handler="admin",method="GET",path="/debug/pprof/cmdline"} 1
|
||||
caddy_admin_http_requests_total{code="200",handler="load",method="POST",path="/load"} 1
|
||||
caddy_admin_http_requests_total{code="200",handler="metrics",method="GET",path="/metrics"} 3
|
||||
```
|
||||
|
||||
#### `caddy_admin_http_requests_total`
|
||||
|
||||
A counter of the number of requests handled by admin endpoints, including
|
||||
modules in the `admin.api.*` namespace.
|
||||
|
||||
Label | Description
|
||||
-------|------------
|
||||
`code` | HTTP status code
|
||||
`handler` | The handler or module name
|
||||
`method` | The HTTP method
|
||||
`path` | The URL path the admin endpoint was mounted to
|
||||
|
||||
#### `caddy_admin_http_request_errors_total`
|
||||
|
||||
A counter of the number of errors encountered in admin endpoints, including
|
||||
modules in the `admin.api.*` namespace.
|
||||
|
||||
Label | Description
|
||||
-------|------------
|
||||
`handler` | The handler or module name
|
||||
`method` | The HTTP method
|
||||
`path` | The URL path the admin endpoint was mounted to
|
||||
|
||||
### HTTP Middleware metrics
|
||||
|
||||
All Caddy HTTP middleware handlers are instrumented automatically for
|
||||
determining request latency, time-to-first-byte, errors, and request/response
|
||||
body sizes.
|
||||
|
||||
<aside class="tip">
|
||||
Because all middleware handlers are instrumented, and many requests are handled by multiple handlers, make sure not to simply sum all the counters together.
|
||||
</aside>
|
||||
|
||||
For the histogram metrics below, the buckets are currently not configurable.
|
||||
For durations, the default ([`prometheus.DefBuckets`](https://pkg.go.dev/github.com/prometheus/client_golang/prometheus#pkg-variables)
|
||||
set of buckets is used (5ms, 10ms, 25ms, 50ms, 100ms, 250ms, 500ms, 1s, 2.5s, 5s, and 10s).
|
||||
For sizes, the buckets are 256b, 1kiB, 4kiB, 16kiB, 64kiB, 256kiB, 1MiB, and 4MiB.
|
||||
|
||||
#### `caddy_http_requests_in_flight`
|
||||
|
||||
A gauge of the number of requests currently being handled by this server.
|
||||
|
||||
Label | Description
|
||||
-------|------------
|
||||
`server` | The server name
|
||||
`handler` | The handler or module name
|
||||
|
||||
#### `caddy_http_request_errors_total`
|
||||
|
||||
A counter of middleware errors encountered while handling requests.
|
||||
|
||||
Label | Description
|
||||
-------|------------
|
||||
`server` | The server name
|
||||
`handler` | The handler or module name
|
||||
|
||||
#### `caddy_http_requests_total`
|
||||
|
||||
A counter of HTTP(S) requests made.
|
||||
|
||||
Label | Description
|
||||
-------|------------
|
||||
`server` | The server name
|
||||
`handler` | The handler or module name
|
||||
|
||||
#### `caddy_http_request_duration_seconds`
|
||||
|
||||
A histogram of the round-trip request durations.
|
||||
|
||||
Label | Description
|
||||
-------|------------
|
||||
`server` | The server name
|
||||
`handler` | The handler or module name
|
||||
`code` | HTTP status code
|
||||
`method` | The HTTP method
|
||||
|
||||
#### `caddy_http_request_size_bytes`
|
||||
|
||||
A histogram of the total (estimated) size of the request. Includes body.
|
||||
|
||||
Label | Description
|
||||
-------|------------
|
||||
`server` | The server name
|
||||
`handler` | The handler or module name
|
||||
`code` | HTTP status code
|
||||
`method` | The HTTP method
|
||||
|
||||
#### `caddy_http_response_size_bytes`
|
||||
|
||||
A histogram of the size of the returned response body.
|
||||
|
||||
Label | Description
|
||||
-------|------------
|
||||
`server` | The server name
|
||||
`handler` | The handler or module name
|
||||
`code` | HTTP status code
|
||||
`method` | The HTTP method
|
||||
|
||||
#### `caddy_http_response_duration_seconds`
|
||||
|
||||
A histogram of time-to-first-byte for responses.
|
||||
|
||||
Label | Description
|
||||
-------|------------
|
||||
`server` | The server name
|
||||
`handler` | The handler or module name
|
||||
`code` | HTTP status code
|
||||
`method` | The HTTP method
|
||||
|
||||
### Reverse proxy metrics
|
||||
|
||||
#### `caddy_reverse_proxy_upstreams_healthy`
|
||||
|
||||
A gauge of the reverse proxy upstreams healthiness.
|
||||
|
||||
Value `0` means the upstream is unhealthy, where as `1` means the upstream is healthy.
|
||||
|
||||
Label | Description
|
||||
-------|------------
|
||||
`upstream` | Address of the upstream
|
||||
|
||||
## Sample Queries
|
||||
|
||||
Once you have Prometheus scraping Caddy's metrics, you can start to see some
|
||||
interesting metrics about how Caddy's performing.
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
If you've started up a Prometheus server to scrape Caddy with the config above, try pasting these queries into the Prometheus UI at [http://localhost:9090/graph](http://localhost:9090/graph)
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
For example, to see the per-second request rate, as averaged over 5 minutes:
|
||||
|
||||
```
|
||||
rate(caddy_http_requests_total{handler="file_server"}[5m])
|
||||
```
|
||||
|
||||
To see the rate at which your latency threshold of 100ms is being exceeded:
|
||||
|
||||
```
|
||||
sum(rate(caddy_http_request_duration_seconds_count{server="srv0"}[5m])) by (handler)
|
||||
-
|
||||
sum(rate(caddy_http_request_duration_seconds_bucket{le="0.100", server="srv0"}[5m])) by (handler)
|
||||
```
|
||||
|
||||
To find the 95th percentile request duration on the `file_server`
|
||||
handler, you can use a query like this:
|
||||
|
||||
```
|
||||
histogram_quantile(0.95, sum(caddy_http_request_duration_seconds_bucket{handler="file_server"}) by (le))
|
||||
```
|
||||
|
||||
Or to see the median response size in bytes for successful `GET` requests on the
|
||||
`file_server` handler:
|
||||
|
||||
```
|
||||
histogram_quantile(0.5, caddy_http_response_size_bytes_bucket{method="GET", handler="file_server", code="200"})
|
||||
```
|
18
src/docs/markdown/quick-starts.md
Normal file
18
src/docs/markdown/quick-starts.md
Normal file
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
title: Quick-starts
|
||||
---
|
||||
|
||||
# Quick-starts
|
||||
|
||||
These tutorials are designed to get you up and running quickly without much explanation to get in the way.
|
||||
|
||||
It is **highly recommended** that you follow-up by reading other tutorials and reference documentation to fully understand how your web server works.
|
||||
|
||||
|
||||
## Menu
|
||||
|
||||
- #### [Using the API](/docs/quick-starts/api)
|
||||
- #### [Using a Caddyfile](/docs/quick-starts/caddyfile)
|
||||
- #### [Static file server](/docs/quick-starts/static-files)
|
||||
- #### [Reverse proxy](/docs/quick-starts/reverse-proxy)
|
||||
- #### [HTTPS](/docs/quick-starts/https)
|
106
src/docs/markdown/quick-starts/api.md
Normal file
106
src/docs/markdown/quick-starts/api.md
Normal file
|
@ -0,0 +1,106 @@
|
|||
---
|
||||
title: API Quick-start
|
||||
---
|
||||
|
||||
# API quick-start
|
||||
|
||||
**Prerequisites:**
|
||||
- Basic terminal / command line skills
|
||||
- `caddy` and `curl` in your PATH
|
||||
|
||||
---
|
||||
|
||||
First start Caddy:
|
||||
|
||||
<pre><code class="cmd bash">caddy start</code></pre>
|
||||
|
||||
Caddy is currently running idle (with a blank configuration). Give it a simple config with `curl`:
|
||||
|
||||
<pre><code class="cmd bash">curl localhost:2019/load \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @- << EOF
|
||||
{
|
||||
"apps": {
|
||||
"http": {
|
||||
"servers": {
|
||||
"hello": {
|
||||
"listen": [":2015"],
|
||||
"routes": [
|
||||
{
|
||||
"handle": [{
|
||||
"handler": "static_response",
|
||||
"body": "Hello, world!"
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF</code></pre>
|
||||
|
||||
Giving a POST body with [Heredoc](https://en.wikipedia.org/wiki/Here_document#Unix_shells) can be tedious, so if you prefer to use files, save the JSON to a file called `caddy.json` and then use this command instead:
|
||||
|
||||
<pre><code class="cmd bash">curl localhost:2019/load \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @caddy.json
|
||||
</code></pre>
|
||||
|
||||
Now load [localhost:2015](http://localhost:2015) in your browser or use `curl`:
|
||||
|
||||
<pre><code class="cmd"><span class="bash">curl localhost:2015</span>
|
||||
Hello, world!</code></pre>
|
||||
|
||||
We can also define multiple sites on different interfaces with this JSON:
|
||||
|
||||
```json
|
||||
{
|
||||
"apps": {
|
||||
"http": {
|
||||
"servers": {
|
||||
"hello": {
|
||||
"listen": [":2015"],
|
||||
"routes": [
|
||||
{
|
||||
"handle": [{
|
||||
"handler": "static_response",
|
||||
"body": "Hello, world!"
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
"bye": {
|
||||
"listen": [":2016"],
|
||||
"routes": [
|
||||
{
|
||||
"handle": [{
|
||||
"handler": "static_response",
|
||||
"body": "Goodbye, world!"
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Update your JSON then perform the API request again.
|
||||
|
||||
Try out your new "goodbye" endpoint [in your browser](http://localhost:2016) or with `curl` to make sure it works:
|
||||
|
||||
<pre><code class="cmd"><span class="bash">curl localhost:2016</span>
|
||||
Goodbye, world!</code></pre>
|
||||
|
||||
When you are done with Caddy, make sure to stop it:
|
||||
|
||||
<pre><code class="cmd bash">caddy stop</code></pre>
|
||||
|
||||
There's a lot more you can do with the API, including exporting configuration and making fine-grained changes to the config (as opposed to updating the whole thing). Be sure to read the [full API tutorial](/docs/api-tutorial) to learn how!
|
||||
|
||||
## Further reading
|
||||
|
||||
- [Full API tutorial](/docs/api-tutorial)
|
||||
- [API documentation](/docs/api)
|
83
src/docs/markdown/quick-starts/caddyfile.md
Normal file
83
src/docs/markdown/quick-starts/caddyfile.md
Normal file
|
@ -0,0 +1,83 @@
|
|||
---
|
||||
title: Caddyfile Quick-start
|
||||
---
|
||||
|
||||
# Caddyfile Quick-start
|
||||
|
||||
Create a new text file named `Caddyfile` (no extension).
|
||||
|
||||
The first thing to type in a Caddyfile is your site's address:
|
||||
|
||||
```caddy
|
||||
localhost
|
||||
```
|
||||
|
||||
<aside class="tip">
|
||||
|
||||
If the HTTP and HTTPS ports (80 and 443, respectively) are privileged ports on your OS, you will either need to run with elevated privileges or use higher ports. To gain permission, run as root with `sudo -E` or use `sudo setcap cap_net_bind_service=+ep $(which caddy)`. Alternatively, to use higher ports, just change the address to something like `localhost:2080` and change the HTTP port using the [`http_port`](/docs/caddyfile/options) Caddyfile option.
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
Then hit enter and type what you want it to do, so it looks like this:
|
||||
|
||||
```caddy
|
||||
localhost
|
||||
|
||||
respond "Hello, world!"
|
||||
```
|
||||
|
||||
Save this and run Caddy from the same folder that contains your Caddyfile:
|
||||
|
||||
<pre><code class="cmd bash">caddy start</code></pre>
|
||||
|
||||
You will probably be asked for your password, because Caddy serves all sites -- even local ones -- over HTTPS by default. (The password prompt should only happen the first time!)
|
||||
|
||||
<aside class="tip">
|
||||
For local HTTPS, Caddy automatically generates certificates and unique private keys for you. The root certificate is added to your system's trust store, which is why the password prompt is necessary. It allows you to develop locally over HTTPS without certificate errors.
|
||||
</aside>
|
||||
|
||||
(If you get permission errors, you may need to run with elevated privileges or choose a port higher than 1024.)
|
||||
|
||||
Either open your browser to [localhost](http://localhost) or `curl` it:
|
||||
|
||||
<pre><code class="cmd"><span class="bash">curl https://localhost</span>
|
||||
Hello, world!</code></pre>
|
||||
|
||||
You can define multiple sites in a Caddyfile by wrapping them in curly braces `{ }`. Change your Caddyfile to be:
|
||||
|
||||
```caddy
|
||||
localhost {
|
||||
respond "Hello, world!"
|
||||
}
|
||||
|
||||
localhost:2016 {
|
||||
respond "Goodbye, world!"
|
||||
}
|
||||
```
|
||||
|
||||
You can give Caddy the updated configuration two ways, either with the API directly:
|
||||
|
||||
<pre><code class="cmd bash">curl localhost:2019/load \
|
||||
-H "Content-Type: text/caddyfile" \
|
||||
--data-binary @Caddyfile
|
||||
</code></pre>
|
||||
|
||||
or with the reload command, which does the same API request for you:
|
||||
|
||||
<pre><code class="cmd bash">caddy reload</code></pre>
|
||||
|
||||
Try out your new "goodbye" endpoint [in your browser](https://localhost:2016) or with `curl` to make sure it works:
|
||||
|
||||
<pre><code class="cmd"><span class="bash">curl https://localhost:2016</span>
|
||||
Goodbye, world!</code></pre>
|
||||
|
||||
When you are done with Caddy, make sure to stop it:
|
||||
|
||||
<pre><code class="cmd bash">caddy stop</code></pre>
|
||||
|
||||
## Further reading
|
||||
|
||||
- [Common patterns](/docs/caddyfile/patterns)
|
||||
- [Caddyfile concepts](/docs/caddyfile/concepts)
|
||||
- [Directives](/docs/caddyfile/directives)
|
105
src/docs/markdown/quick-starts/https.md
Normal file
105
src/docs/markdown/quick-starts/https.md
Normal file
|
@ -0,0 +1,105 @@
|
|||
---
|
||||
title: HTTPS quick-start
|
||||
---
|
||||
|
||||
# HTTPS quick-start
|
||||
|
||||
This guide will show you how to get up and running with [fully-managed HTTPS](/docs/automatic-https) in no time.
|
||||
|
||||
<aside class="tip">
|
||||
Caddy uses HTTPS for all sites by default, as long as a host name is provided in the config. This tutorial assumes you want to get a publicly-trusted site (i.e. not "localhost") up over HTTPS, so we'll be using a public domain name and external ports.
|
||||
</aside>
|
||||
|
||||
**Prerequisites:**
|
||||
- Basic terminal / command line skills
|
||||
- Basic understanding of DNS
|
||||
- A registered public domain name
|
||||
- External access to ports 80 and 443
|
||||
- `caddy` and `curl` in your PATH
|
||||
|
||||
---
|
||||
|
||||
In this tutorial, replace `example.com` with your actual domain name.
|
||||
|
||||
Set your domain's A/AAAA records point to your server. You can do this by logging into your DNS provider and managing your domain name.
|
||||
|
||||
Before continuing, verify correct records with an authoritative lookup. Replace `example.com` with your domain name, and if you are using IPv6 replace `type=A` with `type=AAAA`:
|
||||
|
||||
<pre><code class="cmd bash">curl "https://cloudflare-dns.com/dns-query?name=example.com&type=A" \
|
||||
-H "accept: application/dns-json"</code></pre>
|
||||
|
||||
Also make sure your server is externally reachable on ports 80 and 443 from a public interface.
|
||||
|
||||
<aside class="tip">
|
||||
If you're on your home or other restricted network, you may need to forward ports or adjust firewall settings.
|
||||
</aside>
|
||||
|
||||
All we have to do is start Caddy with your domain name in the config. There are several ways to do this.
|
||||
|
||||
## Caddyfile
|
||||
|
||||
This is the most common way to get HTTPS.
|
||||
|
||||
Create a file called `Caddyfile` (no extension) where the first line is your domain name, for example:
|
||||
|
||||
```caddy
|
||||
example.com
|
||||
|
||||
respond "Hello, privacy!"
|
||||
```
|
||||
|
||||
Then from the same directory, run:
|
||||
|
||||
<pre><code class="cmd bash">caddy run</code></pre>
|
||||
|
||||
You will see Caddy provision a TLS certificate and serve your site over HTTPS. This was possible because your site's address in the Caddyfile contained a domain name.
|
||||
|
||||
|
||||
## The `file-server` command
|
||||
|
||||
If all you need is serving static files over HTTPS, run this command (replacing your domain name):
|
||||
|
||||
<pre><code class="cmd bash">caddy file-server --domain example.com</code></pre>
|
||||
|
||||
You will see Caddy provision a TLS certificate and serve your site over HTTPS.
|
||||
|
||||
|
||||
## The `reverse-proxy` command
|
||||
|
||||
If all you need is a simple reverse proxy over HTTPS (as a TLS terminator), run this command (replacing your domain name and actual backend address):
|
||||
|
||||
<pre><code class="cmd bash">caddy reverse-proxy --from example.com --to localhost:9000</code></pre>
|
||||
|
||||
You will see Caddy provision a TLS certificate and serve your site over HTTPS.
|
||||
|
||||
|
||||
## JSON config
|
||||
|
||||
The general rule of thumb is that any [host matcher](/docs/json/apps/http/servers/routes/match/host/) will trigger automatic HTTPS.
|
||||
|
||||
Thus, a JSON config such as the following will enable production-ready [automatic HTTPS](/docs/automatic-https):
|
||||
|
||||
```json
|
||||
{
|
||||
"apps": {
|
||||
"http": {
|
||||
"servers": {
|
||||
"hello": {
|
||||
"listen": [":443"],
|
||||
"routes": [
|
||||
{
|
||||
"match": [{
|
||||
"host": ["example.com"]
|
||||
}],
|
||||
"handle": [{
|
||||
"handler": "static_response",
|
||||
"body": "Hello, privacy!"
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
114
src/docs/markdown/quick-starts/reverse-proxy.md
Normal file
114
src/docs/markdown/quick-starts/reverse-proxy.md
Normal file
|
@ -0,0 +1,114 @@
|
|||
---
|
||||
title: Reverse proxy quick-start
|
||||
---
|
||||
|
||||
# Reverse proxy quick-start
|
||||
|
||||
This guide will show you how to get a production-ready reverse proxy with or without HTTPS up and running quickly.
|
||||
|
||||
**Prerequisites:**
|
||||
- Basic terminal / command line skills
|
||||
- `caddy` in your PATH
|
||||
- A running backend process to proxy to
|
||||
|
||||
---
|
||||
|
||||
This tutorial assumes that you have a backend HTTP service running at `127.0.0.1:9000`. These commands are for Linux, but the same principles apply to other operating systems.
|
||||
|
||||
You can get a simple reverse proxy running without a config file, or you can use a config file for more flexibility and control.
|
||||
|
||||
|
||||
## Command line
|
||||
|
||||
To start a plaintext HTTP proxy from port 2080 to port 9000 on your machine:
|
||||
|
||||
<pre><code class="cmd bash">caddy reverse-proxy --from :2080 --to :9000</code></pre>
|
||||
|
||||
Then try it:
|
||||
|
||||
<pre><code class="cmd bash">curl -v 127.0.0.1:2080</code></pre>
|
||||
|
||||
The [`reverse-proxy` command](/docs/command-line#reverse-proxy) is intended for quick and easy reverse proxies. (You can use it in production if your requirements are simple.)
|
||||
|
||||
## Caddyfile
|
||||
|
||||
In the current working directory, create a file called `Caddyfile` with these contents:
|
||||
|
||||
```caddy
|
||||
:2080
|
||||
|
||||
reverse_proxy :9000
|
||||
```
|
||||
|
||||
That config file is roughly equivalent to the `caddy reverse-proxy` command above.
|
||||
|
||||
Then, from the same directory, run:
|
||||
|
||||
<pre><code class="cmd bash">caddy run</code></pre>
|
||||
|
||||
Then try your proxy:
|
||||
|
||||
<pre><code class="cmd bash">curl -v 127.0.0.1:2080</code></pre>
|
||||
|
||||
If you change the Caddyfile, make sure to [reload](/docs/command-line#caddy-reload) Caddy.
|
||||
|
||||
This was a simple example. You can do a lot more with the [`reverse_proxy` directive](/docs/caddyfile/directives/reverse_proxy).
|
||||
|
||||
## HTTPS from client to proxy
|
||||
|
||||
Caddy will serve your proxy over [HTTPS automatically and by default](/docs/automatic-https) if it knows the hostname (domain name). The `caddy reverse-proxy` command will default to `localhost` if you omit the `--from` flag, or you can replace the first line of your Caddyfile with the domain name of the proxy.
|
||||
|
||||
- If you use `localhost` or any domain ending in `.localhost`, Caddy will use an auto-renewing self-signed certificate. The first time you do this, you may need to enter a password as Caddy attempts to install its CA's root certificate into your trust store.
|
||||
- If you use any other domain name, Caddy will attempt to get a publicly-trusted certificate; make sure your DNS records point to your machine and that ports 80 and 443 are open to the public and directed toward Caddy.
|
||||
|
||||
If you don't specify a port, Caddy defaults to 443 for HTTPS. In that case you will also need permission to bind to low ports. A couple ways to do this on Linux:
|
||||
|
||||
- Run as root (e.g. `sudo -E`).
|
||||
- Or run `sudo setcap cap_net_bind_service=+ep $(which caddy)` to give Caddy this specific capability.
|
||||
|
||||
Here's the most basic `caddy reverse-proxy` command that gives you HTTPS:
|
||||
|
||||
<pre><code class="cmd bash">caddy reverse-proxy --to :9000</code></pre>
|
||||
|
||||
Then try it:
|
||||
|
||||
<pre><code class="cmd bash">curl -v https://localhost</code></pre>
|
||||
|
||||
You can customize the hostname using the `--from` flag:
|
||||
|
||||
<pre><code class="cmd bash">caddy reverse-proxy --from example.com --to :9000</code></pre>
|
||||
|
||||
If you don't have permission to bind to low ports, you can proxy from a higher port:
|
||||
|
||||
<pre><code class="cmd bash">caddy reverse-proxy --from example.com:8443 --to :9000</code></pre>
|
||||
|
||||
If you're using a Caddyfile, simply change the first line to your domain name, for example:
|
||||
|
||||
```caddy
|
||||
example.com
|
||||
|
||||
reverse_proxy :9000
|
||||
```
|
||||
|
||||
## HTTPS from proxy to backend
|
||||
|
||||
Caddy can also proxy using HTTPS between itself and the backend if the backend supports TLS. Just use `https://` in your backend address:
|
||||
|
||||
<pre><code class="cmd bash">caddy reverse-proxy --from :2080 --to https://localhost:9000</code></pre>
|
||||
|
||||
This requires that the backend's certificate is trusted by the system Caddy is running on. (Caddy doesn't trust self-signed certificates unless explicitly configured to do so.)
|
||||
|
||||
Of course, you can do HTTPS on both ends too:
|
||||
|
||||
<pre><code class="cmd bash">caddy reverse-proxy --from example.com --to https://example.com:9000</code></pre>
|
||||
|
||||
This serves HTTPS from client to proxy, and from proxy to backend.
|
||||
|
||||
If the hostname you're proxying to is different than the one you're proxying from, you will need to use the `--change-host-header` flag:
|
||||
|
||||
<pre><code class="cmd bash">caddy reverse-proxy \
|
||||
--from example.com \
|
||||
--to https://localhost:9000 \
|
||||
--change-host-header</code></pre>
|
||||
|
||||
By default, Caddy passes all HTTP headers through unchanged, including `Host`, and Caddy derives the TLS ServerName from the Host header. The `--change-host-header` resets the Host header to that of the backend so that the TLS handshake can complete successfully. In the example above, it would be changed from `example.com` to `localhost:9000` (and `localhost` would be used in the TLS handshake).
|
76
src/docs/markdown/quick-starts/static-files.md
Normal file
76
src/docs/markdown/quick-starts/static-files.md
Normal file
|
@ -0,0 +1,76 @@
|
|||
---
|
||||
title: Static files quick-start
|
||||
---
|
||||
|
||||
# Static files quick-start
|
||||
|
||||
This guide will show you how to get a production-ready static file server up and running quickly.
|
||||
|
||||
**Prerequisites:**
|
||||
- Basic terminal / command line skills
|
||||
- `caddy` in your PATH
|
||||
- A folder containing your website
|
||||
|
||||
---
|
||||
|
||||
There are two easy ways to get a quick file server up and running.
|
||||
|
||||
## Command line
|
||||
|
||||
In your terminal, change to the root directory of your site and run:
|
||||
|
||||
<pre><code class="cmd bash">caddy file-server</code></pre>
|
||||
|
||||
If you get a permissions error, it probably means your OS does not allow you to bind to low ports -- so use a high port instead:
|
||||
|
||||
<pre><code class="cmd bash">caddy file-server --listen :2015</code></pre>
|
||||
|
||||
Then open [localhost](http://localhost) (or [localhost:2015](http://localhost:2015)) in your browser to see your site!
|
||||
|
||||
If you don't have an index file but you want to display a file listing, use the `--browse` option:
|
||||
|
||||
<pre><code class="cmd bash">caddy file-server --browse</code></pre>
|
||||
|
||||
You can use another folder as the site root:
|
||||
|
||||
<pre><code class="cmd bash">caddy file-server --root ~/mysite</code></pre>
|
||||
|
||||
|
||||
|
||||
## Caddyfile
|
||||
|
||||
In the root of your site, create a file called `Caddyfile` with these contents:
|
||||
|
||||
```caddy
|
||||
localhost
|
||||
|
||||
file_server
|
||||
```
|
||||
|
||||
If you don't have permission to bind to low ports, replace `localhost` with `localhost:2015` (or some other high port).
|
||||
|
||||
Then, from the same directory, run:
|
||||
|
||||
<pre><code class="cmd bash">caddy run</code></pre>
|
||||
|
||||
You can then load [localhost](https://localhost) (or whatever the address is in your config) to see your site!
|
||||
|
||||
The [`file_server` directive](/docs/caddyfile/directives/file_server) has more options for you to customize your site. Make sure to [reload](/docs/command-line#caddy-reload) Caddy (or stop and start it again) when you change the Caddyfile!
|
||||
|
||||
If you don't have an index file but you want to display a file listing, use the `browse` argument:
|
||||
|
||||
```caddy
|
||||
localhost
|
||||
|
||||
file_server browse
|
||||
```
|
||||
|
||||
You can also use another folder as the site root:
|
||||
|
||||
```caddy
|
||||
localhost
|
||||
|
||||
root * /home/me/mysite
|
||||
file_server
|
||||
```
|
||||
|
257
src/docs/markdown/running.md
Normal file
257
src/docs/markdown/running.md
Normal file
|
@ -0,0 +1,257 @@
|
|||
---
|
||||
title: Keep Caddy Running
|
||||
---
|
||||
|
||||
# Keep Caddy Running
|
||||
|
||||
While Caddy can be run directly with its [command line interface](/docs/command-line), there are numerous advantages to using a service manager to keep it running, such as ensuring it starts automatically when the system reboots and to capture stdout/stderr logs.
|
||||
|
||||
|
||||
- [Linux Service](#linux-service)
|
||||
- [Unit Files](#unit-files)
|
||||
- [Manual Installation](#manual-installation)
|
||||
- [Using the Service](#using-the-service)
|
||||
- [Overrides](#overrides)
|
||||
- [Windows Service](#windows-service)
|
||||
- [Docker Compose](#docker-compose)
|
||||
|
||||
|
||||
## Linux Service
|
||||
|
||||
The recommended way to run Caddy on Linux distributions with systemd is with our official systemd unit files.
|
||||
|
||||
|
||||
### Unit Files
|
||||
|
||||
We provide two different systemd unit files that you can choose between, depending on your usecase:
|
||||
|
||||
- [**`caddy.service`**](https://github.com/caddyserver/dist/blob/master/init/caddy.service) if you configure Caddy with a [Caddyfile](/docs/caddyfile). If you prefer to use a different config adapter or a JSON config file, you may [override](#overrides) the `ExecStart` and `ExecReload` commands.
|
||||
|
||||
- [**`caddy-api.service`**](https://github.com/caddyserver/dist/blob/master/init/caddy-api.service) if you configure Caddy solely through its [API](/docs/api). This service uses the [`--resume`](/docs/command-line#caddy-run) option which will start Caddy using the `autosave.json` which is [persisted](/docs/json/admin/config/) by default.
|
||||
|
||||
They are very similar, but differ in the `ExecStart` and `ExecReload` commands to accommodate the workflows.
|
||||
|
||||
If you need to switch between the services, you should disable and stop the previous one before enabling and starting the other. For example, to switch from the `caddy` service to the `caddy-api` service:
|
||||
<pre><code class="cmd"><span class="bash">sudo systemctl disable --now caddy</span>
|
||||
<span class="bash">sudo systemctl enable --now caddy-api</span></code></pre>
|
||||
|
||||
|
||||
### Manual Installation
|
||||
|
||||
Some [installation methods](/docs/install) automatically set up Caddy to run as a service. If you chose a method that did not, you may follow these instructions to do so:
|
||||
|
||||
**Requirements:**
|
||||
|
||||
- `caddy` binary that you [downloaded](/download) or [built from source](/docs/build)
|
||||
- `systemctl --version` 232 or newer
|
||||
- `sudo` privileges
|
||||
|
||||
Move the caddy binary into your `$PATH`, for example:
|
||||
<pre><code class="cmd bash">sudo mv caddy /usr/bin/</code></pre>
|
||||
|
||||
Test that it worked:
|
||||
<pre><code class="cmd bash">caddy version</code></pre>
|
||||
|
||||
Create a group named `caddy`:
|
||||
<pre><code class="cmd bash">sudo groupadd --system caddy</code></pre>
|
||||
|
||||
Create a user named `caddy` with a writeable home directory:
|
||||
<pre><code class="cmd bash">sudo useradd --system \
|
||||
--gid caddy \
|
||||
--create-home \
|
||||
--home-dir /var/lib/caddy \
|
||||
--shell /usr/sbin/nologin \
|
||||
--comment "Caddy web server" \
|
||||
caddy</code></pre>
|
||||
|
||||
If using a config file, be sure it is readable by the `caddy` user you just created.
|
||||
|
||||
Next, [choose a systemd unit file](#unit-files) based on your use case.
|
||||
|
||||
**Double-check the `ExecStart` and `ExecReload` directives.** Make sure the binary's location and command line arguments are correct for your installation! For example: if using a config file, change your `--config` path if it is different from the defaults.
|
||||
|
||||
The usual place to save the service file is: `/etc/systemd/system/caddy.service`
|
||||
|
||||
After saving your service file, you can start the service for the first time with the usual systemctl dance:
|
||||
|
||||
<pre><code class="cmd"><span class="bash">sudo systemctl daemon-reload</span>
|
||||
<span class="bash">sudo systemctl enable --now caddy</span></code></pre>
|
||||
|
||||
Verify that it is running:
|
||||
<pre><code class="cmd bash">systemctl status caddy</code></pre>
|
||||
|
||||
Now you're ready to [use the service](#using-the-service)!
|
||||
|
||||
|
||||
|
||||
### Using the Service
|
||||
|
||||
If using a Caddyfile, you can edit your configuration with `nano`, `vi`, or your preferred editor:
|
||||
<pre><code class="cmd bash">sudo nano /etc/caddy/Caddyfile</code></pre>
|
||||
|
||||
You can place your static site files in either `/var/www/html` or `/srv`. Make sure the `caddy` user has permission to read the files.
|
||||
|
||||
To verify that the service is running:
|
||||
<pre><code class="cmd bash">systemctl status caddy</code></pre>
|
||||
The status command will also show the location of the currently running service file.
|
||||
|
||||
When running with our official service file, Caddy's output will be redirected to `journalctl`. To read your full logs and to avoid lines being truncated:
|
||||
<pre><code class="cmd bash">journalctl -u caddy --no-pager | less +G</code></pre>
|
||||
|
||||
If using a config file, you can gracefully reload Caddy after making any changes:
|
||||
<pre><code class="cmd bash">sudo systemctl reload caddy</code></pre>
|
||||
|
||||
You can stop the service with:
|
||||
<pre><code class="cmd bash">sudo systemctl stop caddy</code></pre>
|
||||
|
||||
<aside class="advice">
|
||||
Do not stop the service to change Caddy's configuration. Stopping the server will incur downtime. Use the reload command instead.
|
||||
</aside>
|
||||
|
||||
The Caddy process will run as the `caddy` user, which has its `$HOME` set to `/var/lib/caddy`. This means that:
|
||||
- The default [data storage location](/docs/conventions#data-directory) (for certificates and other state information) will be in `/var/lib/caddy/.local/share/caddy`.
|
||||
- The default [config storage location](/docs/conventions#configuration-directory) (for the auto-saved JSON config, primarily useful for the `caddy-api` service) will be in `/var/lib/caddy/.config/caddy`.
|
||||
|
||||
|
||||
|
||||
### Overrides
|
||||
|
||||
The best way to override aspects of the service files is with this command:
|
||||
<pre><code class="cmd bash">sudo systemctl edit caddy</code></pre>
|
||||
|
||||
This will open a blank file with your default terminal text editor in which you can override or add directives to the unit definition. This is called a "drop-in" file.
|
||||
|
||||
For example, if you need to define environment variables for use in your config, you may do so like this:
|
||||
```systemd
|
||||
[Service]
|
||||
Environment="CF_API_TOKEN=super-secret-cloudflare-tokenvalue"
|
||||
```
|
||||
|
||||
Or, for example if you need to change the config file from the default of the Caddyfile, to instead using a JSON file (note that `Exec*` directives [must be reset with empty strings](https://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStart=) before setting a new value):
|
||||
```systemd
|
||||
[Service]
|
||||
ExecStart=
|
||||
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/caddy.json
|
||||
ExecReload=
|
||||
ExecReload=/usr/bin/caddy reload --config /etc/caddy/caddy.json
|
||||
```
|
||||
|
||||
Then, save the file and exit the text editor, and restart the service for it to take effect:
|
||||
<pre><code class="cmd bash">sudo systemctl restart caddy</code></pre>
|
||||
|
||||
|
||||
## Windows service
|
||||
|
||||
There are two ways to run Caddy as a service on Windows: sc.exe or WinSW.
|
||||
|
||||
### sc.exe
|
||||
|
||||
To create the service, run:
|
||||
|
||||
```
|
||||
sc.exe create caddy start= auto binPath= "YOURPATH\caddy.exe run"
|
||||
```
|
||||
|
||||
(replace YOURPATH with the actual path to your `caddy.exe`)
|
||||
|
||||
To start:
|
||||
|
||||
```
|
||||
sc.exe start caddy
|
||||
```
|
||||
|
||||
To stop:
|
||||
|
||||
```
|
||||
sc.exe stop caddy
|
||||
```
|
||||
|
||||
|
||||
### WinSW
|
||||
|
||||
Install Caddy as a service on Windows with these instructions.
|
||||
|
||||
**Requirements:**
|
||||
|
||||
- `caddy.exe` binary that you [downloaded](/download) or [built from source](/docs/build)
|
||||
- Any `.exe` from the latest release of the
|
||||
[WinSW](https://github.com/winsw/winsw/releases/latest) service wrapper (the below service config is written for v2.x releases)
|
||||
|
||||
Put all files into a service directory. In the following examples, we use `C:\caddy`.
|
||||
|
||||
Rename the `WinSW-x64.exe` file to `caddy-service.exe`.
|
||||
|
||||
Add a `caddy-service.xml` in the same directory:
|
||||
|
||||
```xml
|
||||
<service>
|
||||
<id>caddy</id>
|
||||
<!-- Display name of the service -->
|
||||
<name>Caddy Web Server (powered by WinSW)</name>
|
||||
<!-- Service description -->
|
||||
<description>Caddy Web Server (https://caddyserver.com/)</description>
|
||||
<executable>%BASE%\caddy.exe</executable>
|
||||
<arguments>run</arguments>
|
||||
<log mode="roll-by-time">
|
||||
<pattern>yyyy-MM-dd</pattern>
|
||||
</log>
|
||||
</service>
|
||||
```
|
||||
|
||||
You can now install the service using:
|
||||
<pre><code class="cmd bash">caddy-service install</code></pre>
|
||||
|
||||
You might want to start the Windows Services Console to see if the service is runnnig correctly:
|
||||
<pre><code class="cmd bash">services.msc</code></pre>
|
||||
|
||||
Be aware that Windows services cannot be reloaded, so you have to tell caddy directly to relaod:
|
||||
<pre><code class="cmd bash">caddy reload</code></pre>
|
||||
|
||||
Restarting is possible via the normal Windows services commands, for example via the Task Manager's "Services" tab.
|
||||
|
||||
For customizing the service wrapper, see the [WinSW documentation](https://github.com/winsw/winsw/tree/master#usage)
|
||||
|
||||
|
||||
## Docker Compose
|
||||
|
||||
The simplest way to get up and running with Docker is to use Docker Compose. _The below is only an excerpt. See the docs on [Docker Hub](https://hub.docker.com/_/caddy) for more details_.
|
||||
|
||||
First, create a file `docker-compose.yml` (or add this service to your existing file):
|
||||
|
||||
```yaml
|
||||
version: "3.7"
|
||||
|
||||
services:
|
||||
caddy:
|
||||
image: caddy:<version>
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "443:443/udp"
|
||||
volumes:
|
||||
- $PWD/Caddyfile:/etc/caddy/Caddyfile
|
||||
- $PWD/site:/srv
|
||||
- caddy_data:/data
|
||||
- caddy_config:/config
|
||||
|
||||
volumes:
|
||||
caddy_data:
|
||||
caddy_config:
|
||||
```
|
||||
|
||||
Make sure to fill in `<version>` with the latest version number, which you can find listed on [Docker Hub](https://hub.docker.com/_/caddy) under the "Tags" section.
|
||||
|
||||
Then, create a file named `Caddyfile` beside the `docker-compose.yml`, and write your [Caddyfile](/docs/caddyfile/concepts) configuration.
|
||||
|
||||
If you have static files to serve, you may place them in a `site/` directory beside the configs, then set the [`root` directive](/docs/caddyfile/directives/root) to `/srv/`. If you don't, then you may remove the `/srv` volume mount.
|
||||
|
||||
Then, you can start the container:
|
||||
<pre><code class="cmd bash">docker-compose up -d</code></pre>
|
||||
|
||||
To reload Caddy after making changes to your Caddyfile:
|
||||
<pre><code class="cmd bash">docker-compose exec -w /etc/caddy caddy caddy reload</code></pre>
|
||||
|
||||
To see Caddy's logs:
|
||||
<pre><code class="cmd bash">docker-compose logs caddy</code></pre>
|
||||
|
382
src/docs/markdown/v2-upgrade.md
Normal file
382
src/docs/markdown/v2-upgrade.md
Normal file
|
@ -0,0 +1,382 @@
|
|||
---
|
||||
title: Upgrading to Caddy 2
|
||||
---
|
||||
|
||||
Upgrade Guide
|
||||
=============
|
||||
|
||||
Caddy 2 is a whole new code base, written from scratch, to improve on Caddy 1. Caddy 2 is not backwards-compatible with Caddy 1. But don't worry, for most basic setups, not much is different. This guide will help you transition as easily as possible.
|
||||
|
||||
This guide won't delve into the new features available -- which are really cool, by the way, you should [learn them](https://caddyserver.com/docs/getting-started) -- the goal here is to just get you up and running on Caddy 2 quickly.
|
||||
|
||||
|
||||
### Menu
|
||||
|
||||
- [High-order bits](#high-order-bits)
|
||||
- [Steps](#steps)
|
||||
- [HTTPS and ports](#https-and-ports)
|
||||
- [Command line](#command-line)
|
||||
- [Caddyfile](#caddyfile)
|
||||
- [Primary changes](#primary-changes)
|
||||
- [basicauth](#basicauth)
|
||||
- [browse](#browse)
|
||||
- [errors](#errors)
|
||||
- [ext](#ext)
|
||||
- [fastcgi](#fastcgi)
|
||||
- [gzip](#gzip)
|
||||
- [header](#header)
|
||||
- [log](#log)
|
||||
- [proxy](#proxy)
|
||||
- [redir](#redir)
|
||||
- [rewrite](#rewrite)
|
||||
- [root](#root)
|
||||
- [status](#status)
|
||||
- [templates](#templates)
|
||||
- [tls](#tls)
|
||||
- [Service files](#service-files)
|
||||
- [Plugins](#plugins)
|
||||
- [Getting help](#getting-help)
|
||||
|
||||
|
||||
|
||||
## High-order bits
|
||||
|
||||
- "Caddy 2" is still just called `caddy`. We may use "Caddy 2" to clarify which version to make the transition less confusing.
|
||||
- Most users will simply need to replace their `caddy` binary and their updated `Caddyfile` config (after testing that it works).
|
||||
- It might be best to go into Caddy 2 with no assumptions carried over from Caddy 1.
|
||||
- You might not be able to perfectly replicate your niche v1 configuration in v2. Usually, there's a good reason for that.
|
||||
- The command line is no longer used for server configuration.
|
||||
- Environment variables are no longer needed for configuration.
|
||||
- The primary way to give Caddy 2 its configuration is through its [API](/docs/api), but the [`caddy` command](/docs/command-line) can also be used.
|
||||
- You should know that Caddy 2's native configuration language is [JSON](/docs/json/), and the Caddyfile is just another [config adapter](/docs/config-adapters) that converts to JSON for you. Extremely custom/advanced use cases may require JSON, as not every possible configuration can be expressed by the Caddyfile.
|
||||
- The Caddyfile is mostly the same, but also much more powerful; directives have changed.
|
||||
|
||||
|
||||
|
||||
## Steps
|
||||
|
||||
1. Get familiar with Caddy 2 by doing our [Getting Started](https://caddyserver.com/docs/getting-started) tutorial.
|
||||
2. Do step 1 if you haven't yet. Seriously -- we can't stress how important it is to at least know how to use Caddy 2. (It's more fun!)
|
||||
3. Use the guide below to transition your `caddy` command(s).
|
||||
4. Use the guide below to transition your Caddyfile.
|
||||
5. Test your new config locally or in staging.
|
||||
6. Test, test, test again
|
||||
7. Deploy and have fun!
|
||||
|
||||
|
||||
|
||||
## HTTPS and ports
|
||||
|
||||
Caddy's default port is no longer `:2015`. Caddy 2's default port is `:443` or, if no hostname/IP is known, port `:80`. You can always customize the ports in your config.
|
||||
|
||||
Caddy 2's default protocol is [_always_ HTTPS if a hostname or IP is known](/docs/automatic-https#overview). This is different from Caddy 1, where only public-looking domains used HTTPS by default. Now, _every_ site uses HTTPS (unless you disable it by explicitly specifying port `:80` or `http://`).
|
||||
|
||||
IP addresses and localhost domains will be issued certificates from a [locally-trusted, embedded CA](/docs/automatic-https#local-https). All other domains will use ZeroSSL or Let's Encrypt. (This is all configurable.)
|
||||
|
||||
The storage structure of certificates and ACME resources has changed. Caddy 2 will probably obtain new certificates for your sites; but if you have a lot of certificates you can migrate them manually if it does not do it for you. See issues [#2955](https://github.com/caddyserver/caddy/issues/2955) and [#3124](https://github.com/caddyserver/caddy/issues/3124) for details.
|
||||
|
||||
|
||||
|
||||
## Command line
|
||||
|
||||
The `caddy` command is now `caddy run`.
|
||||
|
||||
All command line flags are different. Remove them; all server config now exists within the actual config document (usually Caddyfile or JSON). You will probably find what you need in the [JSON structure](/docs/json/) or in the [Caddyfile global options](/docs/caddyfile/options) to replace most of the command line flags from v1.
|
||||
|
||||
A command like `caddy -conf ../Caddyfile` would become `caddy run --config ../Caddyfile`.
|
||||
|
||||
As before, if your Caddyfile is in the current folder, Caddy will find and use it automatically; you don't need to use the `--config` flag in that case.
|
||||
|
||||
Signals are mostly the same, except USR1 and USR2 are no longer supported. Use the [`caddy reload`](/docs/command-line#caddy-reload) command or the [API](/docs/api) instead to load new configuration.
|
||||
|
||||
Running `caddy` without any config used to run a simple file server. The equivalent in Caddy 2 is [`caddy file-server`](/docs/command-line#caddy-file-server).
|
||||
|
||||
Environment variables are no longer relevant, except for `HOME` (and, optionally, any `XDG_*` variables you set). The `CADDYPATH` is [replaced by OS conventions](/docs/conventions#file-locations).
|
||||
|
||||
|
||||
|
||||
## Caddyfile
|
||||
|
||||
The [v2 Caddyfile](/docs/caddyfile/concepts) is very similar to what you're already familiar with. The main thing you'll need to do is change your directives.
|
||||
|
||||
⚠️ **Be sure to read into the new directives!** Especially if your config is more advanced, there are many nuances to consider. These tips will get you mostly switched over pretty quickly, but please read the full documentation for each directive so you can understand the implications of the upgrade. And of course, always test your configs thoroughly before putting them into production.
|
||||
|
||||
|
||||
### Primary changes
|
||||
|
||||
- If you are serving static files, you will need to add a [`file_server` directive](/docs/caddyfile/directives/file_server), since Caddy 2 does not assume this by default. Caddy 2 does not sniff MIME by default, either, for security reasons; if a Content-Type is missing you may need to set the header yourself using the [header](/docs/caddyfile/directives/header) directive.
|
||||
|
||||
- In v1, you could only filter (or "match") directives by request path. In v2, [request matching](/docs/caddyfile/matchers) is much more powerful. Any v2 directives which add a middleware to the HTTP handler chain or which manipulate the HTTP request/response in any way take advantage of this new matching functionality. [Read more about v2 request matchers.](/docs/caddyfile/matchers) You'll need to know about them to make sense of the v2 Caddyfile.
|
||||
|
||||
- Although many [placeholders](/docs/conventions#placeholders) are the same, many have changed, and there are now [many new ones](/docs/modules/http#docs), including [shorthands for the Caddyfile](/docs/caddyfile/concepts#placeholders).
|
||||
|
||||
- Caddy 2 logs are all structured, and the default format is JSON. All log levels can simply go to the same log to be processed (but you can customize this if needed).
|
||||
|
||||
- Where you matched requests by path prefix in Caddy 1, path matching is now exact by default in Caddy 2. If you want to match a prefix like `/foo/`, you'll need `/foo/*` in Caddy 2.
|
||||
|
||||
We'll list some of the most common v1 directives here and describe how to convert them for use in the v2 Caddyfile.
|
||||
|
||||
⚠️ **Just because a v1 directive is missing from this page does not mean v2 can't do it!** Some v1 directives aren't needed, don't translate well, or are fulfilled other ways in v2. For some advanced customization, you may need to drop down to the JSON to get what you want. Explore [our documentation](/docs/caddyfile) to find what you need!
|
||||
|
||||
|
||||
### basicauth
|
||||
|
||||
HTTP Basic Authentication is still configured with the [`basicauth`](/docs/caddyfile/directives/basicauth) directive. However, Caddy 2 configuration does not accept plaintext passwords. You must hash them, which the [`caddy hash-password`](/docs/command-line#caddy-hash-password) can help with.
|
||||
|
||||
- **v1:**
|
||||
```
|
||||
basicauth /secret/ Bob hiccup
|
||||
```
|
||||
|
||||
- **v2:**
|
||||
```caddy-d
|
||||
basicauth /secret/* {
|
||||
Bob JDJhJDEwJEVCNmdaNEg2Ti5iejRMYkF3MFZhZ3VtV3E1SzBWZEZ5Q3VWc0tzOEJwZE9TaFlZdEVkZDhX
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### browse
|
||||
|
||||
File browsing is now enabled through the [`file_server`](/docs/caddyfile/directives/file_server) directive.
|
||||
|
||||
- **v1:**
|
||||
```
|
||||
browse /subfolder/
|
||||
```
|
||||
- **v2:**
|
||||
```caddy-d
|
||||
file_server /subfolder/* browse
|
||||
```
|
||||
|
||||
|
||||
### errors
|
||||
|
||||
Custom error pages can be accomplished with [`handle_errors`](/docs/caddyfile/directives/handle_errors).
|
||||
|
||||
|
||||
- **v1:**
|
||||
|
||||
```
|
||||
errors {
|
||||
404 404.html
|
||||
500 500.html
|
||||
}
|
||||
```
|
||||
|
||||
- **v2:**
|
||||
|
||||
```
|
||||
handle_errors {
|
||||
rewrite * /{err.status_code}.html
|
||||
file_server
|
||||
}
|
||||
```
|
||||
|
||||
### ext
|
||||
|
||||
Implied file extensions can be done with [`try_files`](/docs/caddyfile/directives/try_files).
|
||||
|
||||
- **v1:** `ext .html`
|
||||
- **v2:** `try_files {path}.html {path}`
|
||||
|
||||
|
||||
### fastcgi
|
||||
|
||||
Assuming you're serving PHP, the v2 equivalent is [`php_fastcgi`](/docs/caddyfile/directives/php_fastcgi).
|
||||
|
||||
- **v1:**
|
||||
```
|
||||
fastcgi / localhost:9005 php
|
||||
```
|
||||
- **v2:**
|
||||
```caddy-d
|
||||
php_fastcgi localhost:9005
|
||||
```
|
||||
|
||||
Note that the `fastcgi` directive from v1 did a lot under the hood, including trying files on disk, rewriting requests, and even redirecting. The v2 `php_fastcgi` directive also does these things for you, but the docs give its [expanded form](/docs/caddyfile/directives/php_fastcgi#expanded-form) that you can modify if your requirements are different.
|
||||
|
||||
There is no `php` preset needed in v2, since the `php_fastcgi` directive assumes PHP by default. A line such as `php_fastcgi 127.0.0.1:9000 php` will cause the reverse proxy to think that there is a second backend called `php`, leading to connection errors.
|
||||
|
||||
The subdirectives are different in v2 -- you probably will not need any for PHP.
|
||||
|
||||
|
||||
### gzip
|
||||
|
||||
A single directive [`encode`](/docs/caddyfile/directives/encode) is now used for all response encodings, including multiple compression formats.
|
||||
|
||||
- **v1:**
|
||||
```
|
||||
gzip
|
||||
```
|
||||
- **v2:**
|
||||
```caddy-d
|
||||
encode gzip
|
||||
```
|
||||
|
||||
Fun fact: Caddy 2 also supports `zstd` (but no browsers do yet).
|
||||
|
||||
|
||||
### header
|
||||
|
||||
[Mostly unchanged](/docs/caddyfile/directives/header), but now way more powerful since it can do substring replacements in v2.
|
||||
|
||||
- **v1:**
|
||||
```
|
||||
header / Strict-Transport-Security max-age=31536000;
|
||||
```
|
||||
- **v2:**
|
||||
```caddy-d
|
||||
header Strict-Transport-Security max-age=31536000;
|
||||
```
|
||||
|
||||
|
||||
### log
|
||||
|
||||
Enables access logging; the [`log`](/docs/caddyfile/directives/log) directive can still be used in v2, but all logs are structured, encoded as JSON, by default.
|
||||
|
||||
The recommended way to enable access logging is simply:
|
||||
|
||||
```caddy-d
|
||||
log
|
||||
```
|
||||
|
||||
which emits structured logs to stderr. (You can also emit to a file or network socket; see the [`log`](/docs/caddyfile/directives/log) directive docs.)
|
||||
|
||||
By default, logs will be in [structured](/docs/logging) JSON format. If you still need logs in Common Log Format (CLF) for legacy reasons, you may use the [`transform-encoder`](https://github.com/caddyserver/transform-encoder) plugin.
|
||||
|
||||
|
||||
### proxy
|
||||
|
||||
The v2 equivalent is [`reverse_proxy`](/docs/caddyfile/directives/reverse_proxy).
|
||||
|
||||
Notable subdirective changes are `header_upstream` and `header_downstream` have become `header_up` and `header_down`, respectively; and load-balancing-related subdirectives are prefixed with `lb_`.
|
||||
|
||||
One other significant difference is that the v2 proxy passes all incoming headers thru by default (including the `Host` header) and sets the `X-Forwarded-For` header. In other words, v1's "transparent" mode is basically the default in v2 (but if you need other headers like X-Real-IP you have to set those yourself). You can still override/customize the `Host` header using the `header_up` subdirective.
|
||||
|
||||
Websocket proxying "just works" in v2; there is no need to "enable" websockets like in v1.
|
||||
|
||||
The `without` subdirective has been removed because [rewrite hacks](#rewrite) are no longer necessary in v2 thanks to improved matcher support.
|
||||
|
||||
- **v1:**
|
||||
```
|
||||
proxy / localhost:9005
|
||||
```
|
||||
- **v2:**
|
||||
```caddy-d
|
||||
reverse_proxy localhost:9005
|
||||
```
|
||||
|
||||
|
||||
### redir
|
||||
|
||||
[Unchanged](/docs/caddyfile/directives/redir), except for a few details about the optional status code argument. Most configs won't need to make any changes.
|
||||
|
||||
- **v1:** `redir https://example.com{uri}`
|
||||
- **v2:** `redir https://example.com{uri}`
|
||||
|
||||
|
||||
### rewrite
|
||||
|
||||
The semantics of request rewriting ("internal redirecting") has changed slightly. If you used a so-called "rewrite hack" in v1 as a way to match requests on something other than a simple path prefix, that is completely unnecessary in v2.
|
||||
|
||||
The [new `rewrite` directive](/docs/caddyfile/directives/rewrite) is very simple but very powerful, as most of its complexity is handled by [matchers](/docs/caddyfile/matchers) in v2:
|
||||
|
||||
- **v1:**
|
||||
```
|
||||
rewrite {
|
||||
if {>User-Agent} has mobile
|
||||
to /mobile{uri}
|
||||
}
|
||||
```
|
||||
- **v2:**
|
||||
```caddy-d
|
||||
@mobile {
|
||||
header User-Agent *mobile*
|
||||
}
|
||||
rewrite @mobile /mobile{uri}
|
||||
```
|
||||
|
||||
Notice how we simply use Caddy 2's usual [matcher tokens](/docs/caddyfile/matchers); it's no longer a special case for this directive.
|
||||
|
||||
Start by removing all rewrite hacks; turn them into [named matchers](/docs/caddyfile/concepts#named-matchers) instead. Evaluate each v1 `rewrite` to see if it's really needed in v2. Hint: A v1 Caddyfile that uses `rewrite` to add a path prefix and then `proxy` with `without` to remove that same prefix is a rewrite hack, and can be eliminated.
|
||||
|
||||
You may find the new [`route`](/docs/caddyfile/directives/route) and [`handle`](/docs/caddyfile/directives/handle) directives useful for having greater control over advanced routing logic.
|
||||
|
||||
|
||||
### root
|
||||
|
||||
[Unchanged](/docs/caddyfile/directives/root), but if your root path starts with `/`, you'll need to add a `*` matcher token to distinguish it from a [path matcher](/docs/caddyfile/concepts#path-matchers).
|
||||
|
||||
- **v1:** `root /var/www`
|
||||
- **v2:** `root * /var/www`
|
||||
|
||||
Because it accepts a matcher in v2, this means you can also change the site root depending on the request.
|
||||
|
||||
Remember to add a [`file_server` directive](https://caddyserver.com/docs/caddyfile/directives/file_server) if serving static files, since Caddy 2 does not assume this by default, whereas in v1 always had it enabled.
|
||||
|
||||
|
||||
### status
|
||||
|
||||
The v2 equivalent is [`respond`](/docs/caddyfile/directives/respond), which can also write a response body.
|
||||
|
||||
- **v1:**
|
||||
```
|
||||
status 404 /secrets/
|
||||
```
|
||||
- **v2:**
|
||||
```caddy-d
|
||||
respond /secrets/* 404
|
||||
```
|
||||
|
||||
|
||||
### templates
|
||||
|
||||
The overall syntax of the [`templates`](/docs/caddyfile/directives/templates) directive is unchanged, but the actual template actions/functions are different and much improved. For example, templates are capable of including files, rendering markdown, making internal sub-requests, parsing front matter, and more!
|
||||
|
||||
[See the docs](/docs/modules/http.handlers.templates) for details about the new functions.
|
||||
|
||||
- **v1:** `templates`
|
||||
- **v2:** `templates`
|
||||
|
||||
|
||||
### tls
|
||||
|
||||
The fundamentals of the [`tls`](/docs/caddyfile/directives/tls) directive have not changed, for example specifying your own cert and key:
|
||||
|
||||
- **v1:** `tls cert.pem key.pem`
|
||||
- **v2:** `tls cert.pem key.pem`
|
||||
|
||||
But Caddy's [auto-HTTPS logic](/docs/automatic-https) _has_ changed, so be aware of that!
|
||||
|
||||
The cipher suite names have also changed.
|
||||
|
||||
A common configuration in Caddy 2 is to use `tls internal` to have it serve a locally-trusted certificate for a dev hostname that isn't `localhost` or an IP address.
|
||||
|
||||
Most sites will not need this directive at all.
|
||||
|
||||
|
||||
## Service files
|
||||
|
||||
We recommend using [one of our official systemd service files](/docs/running#linux-service) for Caddy deployments.
|
||||
|
||||
If you need a custom service file, base it off of ours. They've been carefully tuned to what it is for good reasons! Be sure to customize yours if needed.
|
||||
|
||||
|
||||
## Plugins
|
||||
|
||||
Plugins written for v1 are not automatically compatible with v2. Many v1 plugins are not even needed in v2. On the other hand, v2 is way more easily extensible and flexible than v1!
|
||||
|
||||
If you want to write a plugin for Caddy 2, [learn how to write a Caddy module](/docs/extending-caddy).
|
||||
|
||||
|
||||
### Building Caddy 2 with plugins
|
||||
|
||||
Caddy 2 can be downloaded with plugins at the [interactive download page](https://caddyserver.com/download). Alternatively, you can [build Caddy yourself](https://caddyserver.com/docs/build) using `xcaddy` and choose which plugins to include. `xcaddy` automates the instructions in Caddy's [main.go](https://github.com/caddyserver/caddy/blob/master/cmd/caddy/main.go) file.
|
||||
|
||||
|
||||
## Getting help
|
||||
|
||||
If you're struggling to get Caddy working, please take a look through our website for documentation first. Take time to try new things and understand what is going on - v2 is very different from v1 in a lot of ways (but it's also very familiar)!
|
||||
|
||||
If you still need assistance, please be a part of [our community](https://caddy.community)! You may find that helping others is the best way to help yourself, too.
|
56
src/docs/modules/index.html
Normal file
56
src/docs/modules/index.html
Normal file
|
@ -0,0 +1,56 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Modules - Caddy Documentation</title>
|
||||
{{include "/includes/docs/head.html"}}
|
||||
<link rel="stylesheet" href="/resources/css/docs-json.css">
|
||||
<script src="/resources/js/marked-0.8.0.min.js"></script>
|
||||
<script src="/resources/js/docs-api.js"></script>
|
||||
<script src="/resources/js/module-docs.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
{{include "/includes/docs/header.html"}}
|
||||
<main>
|
||||
{{include "/includes/docs/nav.html"}}
|
||||
<div class="article-container">
|
||||
<div class="paper" id="paper1"></div>
|
||||
<div class="paper" id="paper2"></div>
|
||||
<div class="paper paper3">
|
||||
<article id="module-list-container">
|
||||
<h1>All Modules</h1>
|
||||
<p>
|
||||
This page lists all registered Caddy modules. Modules are plugins which extend Caddy's <a href="/docs/json/">JSON configuration structure</a>.
|
||||
</p>
|
||||
<p>
|
||||
We recommend using your browser's "Find in page" feature for quick lookups.
|
||||
</p>
|
||||
<table id="module-list">
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Module ID</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<!--Populated by JS-->
|
||||
</table>
|
||||
</article>
|
||||
<div id="module-docs-container">
|
||||
<div class="pad"><h1 class="module-name"><!--Populated by JS--></h1></div>
|
||||
<div id="module-multiple-repos">
|
||||
There is more than one module named <b class="module-name"><!--Populated by JS--></b>. Choose one by its repository.
|
||||
</div>
|
||||
<div id="module-template" class="module-repo-container">
|
||||
<div class="module-repo-selector"></div>
|
||||
<article>
|
||||
{{include "/includes/docs/renderbox.html"}}
|
||||
{{include "/includes/docs/details.html"}}
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar"></div>
|
||||
</main>
|
||||
{{include "/includes/docs/hovercard.html"}}
|
||||
{{include "/includes/footer.html"}}
|
||||
</body>
|
||||
</html>
|
90
src/download.html
Normal file
90
src/download.html
Normal file
|
@ -0,0 +1,90 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Download Caddy</title>
|
||||
{{include "/includes/head.html"}}
|
||||
<link rel="stylesheet" href="/resources/css/download.css">
|
||||
<script src="/resources/js/jquery-3.4.1.min.js"></script>
|
||||
<script src="/resources/js/sweetalert.min.js"></script>
|
||||
<script src="/resources/js/download.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<header>
|
||||
<div id="logo-container">
|
||||
<a href="/"><img src="/resources/images/caddy-wordmark.svg" id="logo" alt="Caddy"></a>
|
||||
<br>
|
||||
a <a href="https://zerossl.com"><img src="/resources/images/zerossl-logo.svg" id="zerossl-logo"></a> project
|
||||
</div>
|
||||
{{include "/includes/header-nav.html"}}
|
||||
</header>
|
||||
|
||||
<div class="download-bar">
|
||||
<div>
|
||||
<div>
|
||||
<b>Platform:</b>
|
||||
<select size="1" id="platform" selected="linux-amd64">
|
||||
<option value="dragonfly-amd64">Dragonfly amd64</option>
|
||||
<option value="freebsd-amd64">FreeBSD amd64</option>
|
||||
<option value="freebsd-arm-6">FreeBSD arm 6</option>
|
||||
<option value="freebsd-arm-7">FreeBSD arm 7</option>
|
||||
<option value="freebsd-arm64">FreeBSD arm64</option>
|
||||
<option value="linux-amd64">Linux amd64</option>
|
||||
<option value="linux-arm-5">Linux arm 5</option>
|
||||
<option value="linux-arm-6">Linux arm 6</option>
|
||||
<option value="linux-arm-7">Linux arm 7</option>
|
||||
<option value="linux-arm64">Linux arm64</option>
|
||||
<option value="linux-mips">Linux mips</option>
|
||||
<option value="linux-mips64">Linux mips64</option>
|
||||
<option value="linux-mips64le">Linux mips64le</option>
|
||||
<option value="linux-mipsle">Linux mipsle</option>
|
||||
<option value="linux-ppc64">Linux ppc64</option>
|
||||
<option value="linux-ppc64le">Linux ppc64le</option>
|
||||
<option value="linux-s390x">Linux s390x</option>
|
||||
<option value="darwin-amd64">macOS amd64 (Intel)</option>
|
||||
<option value="darwin-arm64">macOS arm64 (Apple)</option>
|
||||
<option value="openbsd-amd64">OpenBSD amd64</option>
|
||||
<option value="openbsd-arm-6">OpenBSD arm 6</option>
|
||||
<option value="openbsd-arm-7">OpenBSD arm 7</option>
|
||||
<option value="openbsd-arm64">OpenBSD arm64</option>
|
||||
<option value="windows-amd64">Windows amd64</option>
|
||||
<option value="windows-arm-6">Windows arm 6</option>
|
||||
<option value="windows-arm-7">Windows arm 7</option>
|
||||
<option value="windows-arm64">Windows arm64</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<b>Standard features:</b> <span title="All official Caddy builds come with standard plugins">☑️</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<b>Extra features:</b> <span id="package-count">0</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<a href="/api/download" class="blue button" id="download">Download</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type="search" id="filter" placeholder="Filter packages and modules...">
|
||||
|
||||
<div class="text-center">
|
||||
<span class="warning">⚠️ Only choose plugins you need and trust</span>
|
||||
</div>
|
||||
<div class="text-center" id="darwin-warning">
|
||||
<span class="warning">⚠️ Run the following against the downloaded binary:
|
||||
<code>xattr -d com.apple.quarantine </code>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div id="optional-packages">
|
||||
<!-- Populated by JavaScript -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{include "/includes/footer.html"}}
|
||||
</body>
|
||||
</html>
|
5
src/includes/account/head.html
Normal file
5
src/includes/account/head.html
Normal file
|
@ -0,0 +1,5 @@
|
|||
{{include "/includes/head.html"}}
|
||||
<link rel="stylesheet" href="/resources/css/account/common.css">
|
||||
<script src="/resources/js/jquery-3.4.1.min.js"></script>
|
||||
<script src="/resources/js/sweetalert.min.js"></script>
|
||||
<script src="/resources/js/account/common.js"></script>
|
16
src/includes/account/nav.html
Normal file
16
src/includes/account/nav.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
<nav>
|
||||
<div class="logo-container">
|
||||
<img src="/resources/images/caddy-lock.png" alt="Caddy Portal" title="Caddy Portal" class="logo">
|
||||
<br>
|
||||
<b>Portal</b>
|
||||
<br>
|
||||
<span class="help beta" title="Still experimental; subject to change or reset. Thanks for your patience and understanding.">(beta)</span>
|
||||
</div>
|
||||
<ul>
|
||||
<li><a href="/account/">🎛 Dashboard</a></li>
|
||||
<li><a href="/account/register-package">📦 Register Package</a></li>
|
||||
<li><a href="/account/logout">🔒 Log Out</a></li>
|
||||
<br>
|
||||
<li><a href="/">⬅️ Main Site</a></li>
|
||||
</ul>
|
||||
</nav>
|
18
src/includes/docs/details.html
Normal file
18
src/includes/docs/details.html
Normal file
|
@ -0,0 +1,18 @@
|
|||
<div>
|
||||
<div class="nonstandard-notice">
|
||||
<b>This module does not come with Caddy.</b> It can be added by using <b><a href="/docs/build#xcaddy">xcaddy</a></b> or our <b><a href="/download">download page</a></b>. Non-standard modules may be developed by the community and are not officially endorsed or maintained by the Caddy project. The documentation is shown here only as a courtesy.
|
||||
<br><br>
|
||||
<b>Code repository: <a href="javascript:" class="nonstandard-project-link"></a></b>
|
||||
<br><br>
|
||||
<b>Custom builds:</b> <code class="bash">xcaddy build --with <span class="nonstandard-package-path"></span></code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 id="docs">Description</h2>
|
||||
<div class="top-doc">
|
||||
<!--Populated by JS-->
|
||||
</div>
|
||||
<h2 class="field-list-header">Field List</h2>
|
||||
<dl class="field-list-contents">
|
||||
<!--Populated by JS-->
|
||||
</dl>
|
10
src/includes/docs/head.html
Normal file
10
src/includes/docs/head.html
Normal file
|
@ -0,0 +1,10 @@
|
|||
{{include "/includes/head.html"}}
|
||||
<link rel="stylesheet" href="/resources/css/docs.css">
|
||||
<link rel="stylesheet" href="/resources/css/chroma.css">
|
||||
{{$directives := list }}
|
||||
{{range $i, $file := (listFiles "/docs/markdown/caddyfile/directives")}}
|
||||
{{$directives = append $directives ($file | trimSuffix ".md")}}
|
||||
{{end}}
|
||||
<script type="text/javascript">window.CaddyfileDirectives = {{$directives | toJson}};</script>
|
||||
<script src="/resources/js/jquery-3.4.1.min.js"></script>
|
||||
<script src="/resources/js/docs.js"></script>
|
12
src/includes/docs/header.html
Normal file
12
src/includes/docs/header.html
Normal file
|
@ -0,0 +1,12 @@
|
|||
<header>
|
||||
<div>
|
||||
<div id="logo-container">
|
||||
<a href="/"><img src="/resources/images/caddy-wordmark.svg" id="logo" alt="Caddy"></a>
|
||||
<div id="logo-docs">Documentation</div>
|
||||
</div>
|
||||
<div id="zerossl-project">
|
||||
a <a href="https://zerossl.com"><img src="/resources/images/zerossl-logo.svg" id="zerossl-logo"></a> project
|
||||
</div>
|
||||
</div>
|
||||
{{include "/includes/header-nav.html"}}
|
||||
</header>
|
14
src/includes/docs/hovercard.html
Normal file
14
src/includes/docs/hovercard.html
Normal file
|
@ -0,0 +1,14 @@
|
|||
<div id="hovercard" class="arrow-box">
|
||||
<div id="hovercard-docs" class="hovercard-elem"><!--Populated by JS--></div>
|
||||
<div id="hovercard-module" class="hovercard-elem">
|
||||
<p id="hovercard-namespace-box">
|
||||
Fulfilled by modules in namespace: <span id="hovercard-namespace"><!--Populated by JS--></span>
|
||||
</p>
|
||||
<div id="hovercard-module-list"><!--Populated by JS--></div>
|
||||
</div>
|
||||
<div id="hovercard-inline-key" class="hovercard-elem">
|
||||
<p class="explain">This property is <b>required</b> because it specifies the module name.</p>
|
||||
</div>
|
||||
<div id="hovercard-breadcrumb-siblings" class="hovercard-elem"><!--Populated by JS--></div>
|
||||
<div id="hovercard-inline-link" class="hovercard-elem"><!--Populated by JS--></div>
|
||||
</div>
|
64
src/includes/docs/nav.html
Normal file
64
src/includes/docs/nav.html
Normal file
|
@ -0,0 +1,64 @@
|
|||
<nav class="sidebar">
|
||||
<ul>
|
||||
<li><a href="/docs/">Welcome</a></li>
|
||||
<li><a href="https://caddy.community/c/wiki/13">Wiki <img src="/resources/images/external-link.svg"></a></li>
|
||||
|
||||
<li class="heading">Get Caddy</li>
|
||||
<li><a href="/docs/install">Install</a></li>
|
||||
<li><a href="/docs/build">Build from source</a></li>
|
||||
|
||||
<li class="heading">Tutorials</li>
|
||||
<li><a href="/docs/getting-started">Getting Started</a></li>
|
||||
<li><a href="/docs/introduction">Introduction</a></li>
|
||||
<li>
|
||||
<a href="/docs/quick-starts">Quick-starts</a>
|
||||
<ul>
|
||||
<li><a href="/docs/quick-starts/api">Using the API</a></li>
|
||||
<li><a href="/docs/quick-starts/caddyfile">Using a Caddyfile</a></li>
|
||||
<li><a href="/docs/quick-starts/static-files">Static files</a></li>
|
||||
<li><a href="/docs/quick-starts/reverse-proxy">Reverse proxy</a></li>
|
||||
<li><a href="/docs/quick-starts/https">HTTPS</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="/docs/api-tutorial">Caddy API</a></li>
|
||||
<li><a href="/docs/caddyfile-tutorial">Caddyfile</a></li>
|
||||
|
||||
<li class="heading">Reference</li>
|
||||
<li><a href="/docs/command-line">Command Line</a></li>
|
||||
<li><a href="/docs/api">API</a></li>
|
||||
<li>
|
||||
<a href="/docs/caddyfile">Caddyfile</a>
|
||||
<ul>
|
||||
<li><a href="/docs/caddyfile/concepts">Concepts</a></li>
|
||||
<li><a href="/docs/caddyfile/directives">Directives</a></li>
|
||||
<li><a href="/docs/caddyfile/matchers">Request matchers</a></li>
|
||||
<li><a href="/docs/caddyfile/options">Global options</a></li>
|
||||
<li><a href="/docs/caddyfile/patterns">Common patterns</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="/docs/modules/">Modules</a></li>
|
||||
<li><a href="/docs/json/">JSON Config Structure</a></li>
|
||||
<li><a href="/docs/automatic-https">Automatic HTTPS</a></li>
|
||||
|
||||
<li class="heading">Articles</li>
|
||||
<li><a href="/docs/v2-upgrade">Upgrading to Caddy 2</a></li>
|
||||
<li><a href="/docs/conventions">Conventions</a></li>
|
||||
<li><a href="/docs/config-adapters">Config Adapters</a></li>
|
||||
<li><a href="/docs/logging">How Logging Works</a></li>
|
||||
<li><a href="/docs/metrics">Monitoring Caddy</a></li>
|
||||
<li><a href="/docs/architecture">Caddy Architecture</a></li>
|
||||
<li><a href="/docs/running">Keep Caddy Running</a></li>
|
||||
|
||||
<li class="heading">Developers</li>
|
||||
<li>
|
||||
<a href="/docs/extending-caddy">Extending Caddy</a>
|
||||
<ul>
|
||||
<li><a href="/docs/extending-caddy/caddyfile">Caddyfile Support</a></li>
|
||||
<li><a href="/docs/extending-caddy/config-adapters">Config Adapters</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="/docs/extending-caddy/namespaces">Module Namespaces</a></li>
|
||||
<br>
|
||||
<li><a href="/caddy-v1-docs-archive.tar.gz">v1 Docs <img src="/resources/images/external-link.svg"></a></li>
|
||||
</ul>
|
||||
</nav>
|
1
src/includes/docs/renderbox.html
Normal file
1
src/includes/docs/renderbox.html
Normal file
|
@ -0,0 +1 @@
|
|||
<pre><code class="json renderbox"><!--Populated by JS--></code></pre>
|
24
src/includes/footer.html
Normal file
24
src/includes/footer.html
Normal file
|
@ -0,0 +1,24 @@
|
|||
<div class="wrapper">
|
||||
<footer>
|
||||
<div>
|
||||
<img src="/resources/images/caddy-logo.svg" alt="Caddy" id="footer-logo">
|
||||
An <a href="https://github.com/caddyserver/caddy">open source</a> Go community project
|
||||
<br>
|
||||
in partnership with <a href="https://www.ardanlabs.com/">Ardan Labs</a>
|
||||
<br>
|
||||
<small><a href="https://usefathom.com/ref/AUKNWU">Privacy-respecting analytics by Fathom</a></small>
|
||||
</div>
|
||||
<div class="copyright">
|
||||
© {{now | date "2006"}} Stack Holdings. All rights reserved.
|
||||
<br>
|
||||
Caddy® is a registered trademark of Stack Holdings GmbH.
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<!-- Fathom - beautiful, simple website analytics -->
|
||||
<script src="https://mule.caddyserver.com/script.js" site="GVMGKAKP" honor-dnt="true" defer></script>
|
||||
<!-- / Fathom -->
|
||||
|
||||
<!-- Algolia DocSearch -->
|
||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@docsearch/js@3"></script>
|
39
src/includes/head.html
Normal file
39
src/includes/head.html
Normal file
|
@ -0,0 +1,39 @@
|
|||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<link rel="preconnect" href="https://BH4D9OD16A-dsn.algolia.net" crossorigin />
|
||||
|
||||
<link rel="icon" href="/resources/images/favicon.png">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:400,700|Maven+Pro:400,700,900|Montserrat:400,700|PT+Mono&display=swap">
|
||||
<link rel="stylesheet" href="/resources/css/common.css">
|
||||
<script src="/resources/js/common.js"></script>
|
||||
|
||||
<!-- General metatags -->
|
||||
<meta name="author" content="Caddy Web Server">
|
||||
<meta name="description" content="Caddy is a powerful, enterprise-ready, open source web server with automatic HTTPS written in Go">
|
||||
<meta name="theme-color" content="#5ea9a2">
|
||||
|
||||
<!-- Open Graph tags -->
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="https://caddyserver.com/">
|
||||
<meta property="og:description" content="Caddy is a powerful, enterprise-ready, open source web server with automatic HTTPS written in Go">
|
||||
<meta property="og:image" content="https://caddyserver.com/resources/images/caddy-open-graph.jpg">
|
||||
|
||||
<!-- Twitter card tags additive with the og: tags -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:domain" value="caddyserver.com">
|
||||
<meta name="twitter:description" value="Caddy is a powerful, enterprise-ready, open source web server with automatic HTTPS written in Go">
|
||||
<meta name="twitter:image" content="https://caddyserver.com/resources/images/caddy-open-graph.jpg">
|
||||
<meta name="twitter:url" value="https://caddyserver.com/">
|
||||
|
||||
<!-- Algolia DocSearch -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@docsearch/css@3">
|
||||
|
||||
<!-- Global site tag (gtag.js) - Google Analytics (Stack Holdings) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-2DLB04LK4P"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-2DLB04LK4P');
|
||||
</script>
|
11
src/includes/header-nav.html
Normal file
11
src/includes/header-nav.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
<!--TODO: add class="current" to the current link-->
|
||||
<nav>
|
||||
<div id="search"></div>
|
||||
<a href="/v2">v2 <span class="new">new</span></a>
|
||||
<a href="/download">Download</a>
|
||||
<a href="/docs/">Documentation</a>
|
||||
<a href="https://caddy.community">Forum</a>
|
||||
<a href="https://github.com/caddyserver/caddy">GitHub</a>
|
||||
<a href="/account/">Account</a>
|
||||
<a href="/business" class="red button">For business</a>
|
||||
</nav>
|
1020
src/index.html
Normal file
1020
src/index.html
Normal file
File diff suppressed because it is too large
Load diff
233
src/resources/321140.cast
Normal file
233
src/resources/321140.cast
Normal file
|
@ -0,0 +1,233 @@
|
|||
{"version": 2, "width": 79, "height": 20, "timestamp": 1587149050, "env": {"SHELL": "/bin/zsh", "TERM": "xterm-256color"}}
|
||||
[0.022225, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
|
||||
[0.023339, "o", "\u001b]7;file://Shadowfax.local/Users/matt/demo\u0007"]
|
||||
[0.023501, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J \r\n\u001b[90m╔[\u001b[32m√ \u001b[38;5;81mmatt\u001b[90m@\u001b[38;5;82mShadowfax\u001b[90m:\u001b[38;5;81m~/demo\u001b[90m] \r\n╚>\u001b[39m% \u001b[K"]
|
||||
[0.023536, "o", "\u001b[?2004h"]
|
||||
[1.887934, "o", "n"]
|
||||
[2.000861, "o", "\bna"]
|
||||
[2.072314, "o", "n"]
|
||||
[2.148447, "o", "o"]
|
||||
[2.304342, "o", " "]
|
||||
[2.444706, "o", "C"]
|
||||
[2.564064, "o", "a"]
|
||||
[2.66464, "o", "d"]
|
||||
[2.825937, "o", "d"]
|
||||
[2.946425, "o", "y"]
|
||||
[3.129396, "o", "f"]
|
||||
[3.287358, "o", "i"]
|
||||
[3.359465, "o", "l"]
|
||||
[3.487032, "o", "e"]
|
||||
[3.66006, "o", "\u001b[?2004l\r\r\n"]
|
||||
[3.667071, "o", "\u001b[?1049h\u001b[1;20r\u001b(B\u001b[m\u001b[4l\u001b[?7h\u001b[?12l\u001b[?25h\u001b[?1h\u001b="]
|
||||
[3.667109, "o", "\u001b[?1h\u001b=\u001b[?1h\u001b="]
|
||||
[3.667473, "o", "\u001b[39;49m\u001b[39;49m\u001b(B\u001b[m\u001b[H\u001b[2J\u001b(B\u001b[0;7m GNU nano 2.0.6 File: Caddyfile \u001b[18;34H[ New File ]\r\u001b[19d^G\u001b(B\u001b[m Get Help \u001b(B\u001b[0;7m^O\u001b(B\u001b[m WriteOut \u001b(B\u001b[0;7m^R\u001b(B\u001b[m Read File \u001b(B\u001b[0;7m^Y\u001b(B\u001b[m Prev Page \u001b(B\u001b[0;7m^K\u001b(B\u001b[m Cut Text \u001b(B\u001b[0;7m^C\u001b(B\u001b[m Cur Pos\r\u001b[20d\u001b(B\u001b[0;7m^X\u001b(B\u001b[m Exit\u001b[14G\u001b(B\u001b[0;7m^J\u001b(B\u001b[m Justify \u001b(B\u001b[0;7m^W\u001b(B\u001b[m Where Is \u001b(B\u001b[0;7m^V\u001b(B\u001b[m Next Page \u001b(B\u001b[0;7m^U\u001b(B\u001b[m UnCut Text\u001b(B\u001b[0;7m^T\u001b(B\u001b[m To Spell\r\u001b[3d"]
|
||||
[4.535698, "o", "\u001b[1;70H\u001b(B\u001b[0;7mModified\r\u001b[3d\u001b(B\u001b[md"]
|
||||
[4.67723, "o", "e"]
|
||||
[4.755158, "o", "m"]
|
||||
[4.806295, "o", "o"]
|
||||
[5.029033, "o", "."]
|
||||
[5.165983, "o", "h"]
|
||||
[5.227794, "o", "t"]
|
||||
[5.353038, "o", "t"]
|
||||
[5.414159, "o", "p"]
|
||||
[5.523791, "o", "s"]
|
||||
[5.627998, "o", "."]
|
||||
[5.710455, "o", "d"]
|
||||
[5.840252, "o", "e"]
|
||||
[5.963799, "o", "v"]
|
||||
[6.647743, "o", "\r\u001b[4d"]
|
||||
[6.775947, "o", "\u001b[5d"]
|
||||
[6.933264, "o", "r"]
|
||||
[7.004905, "o", "o"]
|
||||
[7.122765, "o", "o"]
|
||||
[7.163639, "o", "t"]
|
||||
[7.244083, "o", " "]
|
||||
[7.346443, "o", "*"]
|
||||
[7.44394, "o", " "]
|
||||
[7.578595, "o", "/"]
|
||||
[7.826323, "o", "v"]
|
||||
[7.959474, "o", "\r\u001b[18d\u001b[K\u001b[5;10Ha"]
|
||||
[8.015511, "o", "r"]
|
||||
[8.103944, "o", "/"]
|
||||
[8.244526, "o", "w"]
|
||||
[8.52161, "o", "w"]
|
||||
[8.671104, "o", "w"]
|
||||
[9.968752, "o", "\r\u001b[6d"]
|
||||
[10.097106, "o", "\u001b[7d"]
|
||||
[10.218855, "o", "f"]
|
||||
[10.319563, "o", "i"]
|
||||
[10.391213, "o", "l"]
|
||||
[10.438339, "o", "e"]
|
||||
[10.606098, "o", "_"]
|
||||
[10.68185, "o", "s"]
|
||||
[10.767465, "o", "e"]
|
||||
[10.813916, "o", "r"]
|
||||
[11.008647, "o", "v"]
|
||||
[11.138442, "o", "e"]
|
||||
[11.178214, "o", "r"]
|
||||
[11.300523, "o", "\r\u001b[8d"]
|
||||
[11.477734, "o", "l"]
|
||||
[11.606149, "o", "o"]
|
||||
[11.66293, "o", "g"]
|
||||
[12.48292, "o", "\r\u001b[9d"]
|
||||
[12.649606, "o", "\u001b[10d"]
|
||||
[12.849532, "o", "#"]
|
||||
[13.198356, "o", " "]
|
||||
[13.299546, "o", "l"]
|
||||
[13.452749, "o", "o"]
|
||||
[13.51259, "o", "a"]
|
||||
[13.56063, "o", "d"]
|
||||
[13.690761, "o", " "]
|
||||
[13.771, "o", "b"]
|
||||
[13.911226, "o", "a"]
|
||||
[13.950191, "o", "l"]
|
||||
[14.047689, "o", "a"]
|
||||
[14.131014, "o", "n"]
|
||||
[14.214907, "o", "c"]
|
||||
[14.282838, "o", "e"]
|
||||
[14.325811, "o", " "]
|
||||
[14.466908, "o", "b"]
|
||||
[14.612588, "o", "e"]
|
||||
[14.685894, "o", "t"]
|
||||
[14.785785, "o", "w"]
|
||||
[14.84735, "o", "e"]
|
||||
[14.991994, "o", "e"]
|
||||
[15.089862, "o", "n"]
|
||||
[15.198188, "o", " "]
|
||||
[15.269788, "o", "t"]
|
||||
[15.32201, "o", "w"]
|
||||
[15.441701, "o", "o"]
|
||||
[15.517416, "o", " "]
|
||||
[15.614119, "o", "b"]
|
||||
[15.78414, "o", "a"]
|
||||
[15.869248, "o", "c"]
|
||||
[15.945455, "o", "k"]
|
||||
[16.028741, "o", "e"]
|
||||
[16.115068, "o", "n"]
|
||||
[16.19984, "o", "d"]
|
||||
[16.248232, "o", "s"]
|
||||
[16.442928, "o", "\r\u001b[11d"]
|
||||
[16.911683, "o", "r"]
|
||||
[16.97932, "o", "e"]
|
||||
[17.141613, "o", "v"]
|
||||
[17.282014, "o", "e"]
|
||||
[17.370161, "o", "r"]
|
||||
[17.490939, "o", "s"]
|
||||
[17.547477, "o", "e"]
|
||||
[17.740609, "o", "_"]
|
||||
[17.940825, "o", "p"]
|
||||
[17.992396, "o", "r"]
|
||||
[18.091587, "o", "o"]
|
||||
[18.185345, "o", "x"]
|
||||
[18.308829, "o", "y"]
|
||||
[18.361527, "o", " "]
|
||||
[18.651444, "o", "/"]
|
||||
[18.825604, "o", "a"]
|
||||
[18.904857, "o", "p"]
|
||||
[18.964969, "o", "i"]
|
||||
[19.188263, "o", "/"]
|
||||
[19.445601, "o", "*"]
|
||||
[19.505049, "o", " "]
|
||||
[20.21481, "o", "l"]
|
||||
[20.366859, "o", "o"]
|
||||
[20.442428, "o", "c"]
|
||||
[20.483119, "o", "a"]
|
||||
[20.542915, "o", "l"]
|
||||
[20.682475, "o", "h"]
|
||||
[20.747016, "o", "o"]
|
||||
[20.757983, "o", "s"]
|
||||
[20.845264, "o", "t"]
|
||||
[20.998991, "o", ":"]
|
||||
[21.173825, "o", "8"]
|
||||
[21.281686, "o", "0"]
|
||||
[21.84701, "o", "8"]
|
||||
[21.906424, "o", "0"]
|
||||
[22.062149, "o", " "]
|
||||
[22.305605, "o", "l"]
|
||||
[22.451357, "o", "o"]
|
||||
[22.520031, "o", "c"]
|
||||
[22.568039, "o", "a"]
|
||||
[22.632047, "o", "l"]
|
||||
[22.751563, "o", "h"]
|
||||
[22.816958, "o", "o"]
|
||||
[22.842836, "o", "s"]
|
||||
[22.914777, "o", "t"]
|
||||
[23.051619, "o", ":"]
|
||||
[23.221017, "o", "8"]
|
||||
[23.301663, "o", "0"]
|
||||
[23.679979, "o", "8"]
|
||||
[23.82229, "o", "1"]
|
||||
[25.554339, "o", "\r\u001b[18d\u001b(B\u001b[0;7mFile Name to Write: Caddyfile \u001b[19;14H\u001b(B\u001b[m \u001b(B\u001b[0;7m^T\u001b(B\u001b[m To Files \u001b(B\u001b[0;7mM-M\u001b(B\u001b[m Mac Format \u001b(B\u001b[0;7mM-P\u001b(B\u001b[m Prepend\u001b[K\u001b[20;2H\u001b(B\u001b[0;7mC\u001b(B\u001b[m Cancel \u001b(B\u001b[0;7mM-D\u001b(B\u001b[m DOS Format \u001b(B\u001b[0;7mM-A\u001b(B\u001b[m Append \u001b(B\u001b[0;7mM-B\u001b(B\u001b[m Backup File\u001b[K\u001b[18;30H"]
|
||||
[25.798317, "o", "\u001b[1;70H\u001b[39;49m\u001b(B\u001b[0;7m \u001b[18;31H\u001b(B\u001b[m\u001b[1K \u001b(B\u001b[0;7m[ Wrote 9 lines ]\u001b(B\u001b[m\u001b[K\u001b[19;14H\u001b(B\u001b[0;7m^O\u001b(B\u001b[m WriteOut \u001b(B\u001b[0;7m^R\u001b(B\u001b[m Read File \u001b(B\u001b[0;7m^Y\u001b(B\u001b[m Prev Page \u001b(B\u001b[0;7m^K\u001b(B\u001b[m Cut Text \u001b(B\u001b[0;7m^C\u001b(B\u001b[m Cur Pos\u001b[20;2H\u001b(B\u001b[0;7mX\u001b(B\u001b[m Exit \u001b(B\u001b[0;7m^J\u001b(B\u001b[m Justify \u001b(B\u001b[0;7m^W\u001b(B\u001b[m Where Is \u001b(B\u001b[0;7m^V\u001b(B\u001b[m Next Page \u001b(B\u001b[0;7m^U\u001b(B\u001b[m UnCut Text\u001b(B\u001b[0;7m^T\u001b(B\u001b[m To Spell\u001b[11;51H"]
|
||||
[26.578003, "o", "\r\u001b[19d\u001b[J\u001b[20;79H\u001b[20;1H\u001b[?1049l\r\u001b[?1l\u001b>"]
|
||||
[26.578762, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
|
||||
[26.57933, "o", "\u001b]7;file://Shadowfax.local/Users/matt/demo\u0007"]
|
||||
[26.579475, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J \r\n\u001b[90m╔[\u001b[32m√ \u001b[38;5;81mmatt\u001b[90m@\u001b[38;5;82mShadowfax\u001b[90m:\u001b[38;5;81m~/demo\u001b[90m] \r\n╚>\u001b[39m% \u001b[K\u001b[?2004h"]
|
||||
[28.181852, "o", "c"]
|
||||
[28.231774, "o", "\bca"]
|
||||
[28.339992, "o", "d"]
|
||||
[28.467448, "o", "d"]
|
||||
[28.551971, "o", "y"]
|
||||
[28.666558, "o", " "]
|
||||
[28.710012, "o", "s"]
|
||||
[28.773903, "o", "t"]
|
||||
[28.936621, "o", "a"]
|
||||
[28.995575, "o", "r"]
|
||||
[29.128429, "o", "t"]
|
||||
[30.256599, "o", "\u001b[?2004l\r\r\n"]
|
||||
[30.320169, "o", "2020/04/17 18:44:40.540\t\u001b[34mINFO\u001b[0m\tusing adjacent Caddyfile\r\n"]
|
||||
[30.322723, "o", "2020/04/17 18:44:40.543\t\u001b[34mINFO\u001b[0m\tadmin\tadmin endpoint started\t{\"address\": \"tcp/localhost:2019\", \"enforce_origin\": false, \"origins\": [\"localhost:2019\", \"[::1]:2019\", \"127.0.0.1:2019\"]}\r\n"]
|
||||
[30.322934, "o", "2020/04/17 12:44:40 [INFO][cache:0xc000849d10] Started certificate maintenance routine\r\n"]
|
||||
[30.322962, "o", "2020/04/17 18:44:40.543\t\u001b[34mINFO\u001b[0m\thttp\tserver is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS\t{\"server_name\": \"srv0\", \"https_port\": 443}\r\n2020/04/17 18:44:40.543\t\u001b[34mINFO\u001b[0m\thttp\tenabling automatic HTTP->HTTPS redirects\t{\"server_name\": \"srv0\"}\r\n"]
|
||||
[30.329471, "o", "2020/04/17 18:44:40.550\t\u001b[34mINFO\u001b[0m\ttls\tcleaned up storage units\r\n"]
|
||||
[30.32956, "o", "2020/04/17 18:44:40.550\t\u001b[34mINFO\u001b[0m\thttp\tenabling automatic TLS certificate management\t{\"domains\": [\"demo.https.dev\"]}\r\n"]
|
||||
[30.329848, "o", "2020/04/17 18:44:40.550\t\u001b[34mINFO\u001b[0m\tautosaved config\t{\"file\": \"/Users/matt/Library/Application Support/Caddy/autosave.json\"}\r\n2020/04/17 18:44:40.550\t\u001b[34mINFO\u001b[0m\tserving initial configuration\r\n"]
|
||||
[30.330126, "o", "Successfully started Caddy (pid=41376) - Caddy is running in the background\r\n"]
|
||||
[30.331898, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
|
||||
[30.332211, "o", "\u001b]7;file://Shadowfax.local/Users/matt/demo\u0007"]
|
||||
[30.332308, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J \r\n\u001b[90m╔[\u001b[32m√ \u001b[38;5;81mmatt\u001b[90m@\u001b[38;5;82mShadowfax\u001b[90m:\u001b[38;5;81m~/demo\u001b[90m] \r\n╚>\u001b[39m% \u001b[K\u001b[?2004h"]
|
||||
[30.336942, "o", "2020/04/17 12:44:40 [INFO][demo.https.dev] Obtain certificate; acquiring lock...\r\n"]
|
||||
[30.337162, "o", "2020/04/17 12:44:40 [INFO][demo.https.dev] Obtain: Lock acquired; proceeding...\r\n"]
|
||||
[31.96302, "o", "2020/04/17 12:44:42 [INFO][demo.https.dev] Waiting on rate limiter...\r\n2020/04/17 12:44:42 [INFO][demo.https.dev] Done waiting\r\n2020/04/17 12:44:42 [INFO] [demo.https.dev] acme: Obtaining bundled SAN certificate given a CSR\r\n"]
|
||||
[33.570607, "o", "2020/04/17 12:44:43 [INFO] [demo.https.dev] AuthURL: https://acme-v02.api.letsencrypt.org/acme/authz-v3/4019233382\r\n2020/04/17 12:44:43 [INFO] [demo.https.dev] acme: Could not find solver for: tls-alpn-01\r\n2020/04/17 12:44:43 [INFO] [demo.https.dev] acme: use http-01 solver\r\n2020/04/17 12:44:43 [INFO] [demo.https.dev] acme: Trying to solve HTTP-01\r\n"]
|
||||
[34.951173, "o", "2020/04/17 12:44:45 [INFO][demo.https.dev] Served key authentication (HTTP challenge)\r\n"]
|
||||
[34.989119, "o", "2020/04/17 12:44:45 [INFO][demo.https.dev] Served key authentication (HTTP challenge)\r\n"]
|
||||
[35.027001, "o", "2020/04/17 12:44:45 [INFO][demo.https.dev] Served key authentication (HTTP challenge)\r\n"]
|
||||
[35.104125, "o", "2020/04/17 12:44:45 [INFO][demo.https.dev] Served key authentication (HTTP challenge)\r\n"]
|
||||
[36.574519, "o", "2020/04/17 12:44:46 [INFO] [demo.https.dev] The server validated our request\r\n"]
|
||||
[36.575029, "o", "2020/04/17 12:44:46 [INFO] [demo.https.dev] acme: Validations succeeded; requesting certificates\r\n"]
|
||||
[37.414882, "o", "2020/04/17 12:44:47 [INFO] [demo.https.dev] Server responded with a certificate.\r\n"]
|
||||
[37.416159, "o", "2020/04/17 12:44:47 [INFO][demo.https.dev] Certificate obtained successfully\r\n2020/04/17 12:44:47 [INFO][demo.https.dev] Obtain: Releasing lock\r\n"]
|
||||
[39.497929, "o", "\u001b[?2004l\r\r\n"]
|
||||
[39.498104, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
|
||||
[39.498581, "o", "\u001b]7;file://Shadowfax.local/Users/matt/demo\u0007"]
|
||||
[39.498738, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J \r\n\u001b[90m╔[\u001b[32m√ \u001b[38;5;81mmatt\u001b[90m@\u001b[38;5;82mShadowfax\u001b[90m:\u001b[38;5;81m~/demo\u001b[90m] \r\n╚>\u001b[39m% \u001b[K\u001b[?2004h"]
|
||||
[40.091454, "o", "c"]
|
||||
[40.173651, "o", "\bcu"]
|
||||
[40.257827, "o", "r"]
|
||||
[40.350059, "o", "l"]
|
||||
[40.44162, "o", " "]
|
||||
[40.619544, "o", "-"]
|
||||
[40.993026, "o", "L"]
|
||||
[41.085153, "o", " "]
|
||||
[41.865854, "o", "d"]
|
||||
[41.982983, "o", "e"]
|
||||
[42.063097, "o", "m"]
|
||||
[42.113574, "o", "o"]
|
||||
[42.326516, "o", "."]
|
||||
[42.71396, "o", "h"]
|
||||
[42.773776, "o", "t"]
|
||||
[42.896163, "o", "t"]
|
||||
[42.935898, "o", "p"]
|
||||
[43.051751, "o", "s"]
|
||||
[43.155986, "o", "."]
|
||||
[43.238445, "o", "d"]
|
||||
[43.36391, "o", "e"]
|
||||
[43.459323, "o", "v"]
|
||||
[43.674326, "o", "\u001b[?2004l\r\r\n"]
|
||||
[43.703356, "o", "2020/04/17 18:44:53.923\t\u001b[34mINFO\u001b[0m\thttp.log.access\thandled request\t{\"request\": {\"method\": \"GET\", \"uri\": \"/\", \"proto\": \"HTTP/2.0\", \"remote_addr\": \"127.0.0.1:51883\", \"host\": \"demo.https.dev\", \"headers\": {\"User-Agent\": [\"curl/7.64.1\"], \"Accept\": [\"*/*\"]}, \"tls\": {\"resumed\": false, \"version\": 771, \"ciphersuite\": 49196, \"proto\": \"h2\", \"proto_mutual\": true, \"server_name\": \"demo.https.dev\"}}, \"common_log\": \"127.0.0.1 - - [17/Apr/2020:12:44:53 -0600] \\\"GET / HTTP/2.0\\\" 200 39\", \"latency\": 0.004248752, \"size\": 39, \"status\": 200, \"resp_headers\": {\"Server\": [\"Caddy\"], \"Etag\": [\"\\\"q8y3zo13\\\"\"], \"Content-Type\": [\"text/html; charset=utf-8\"], \"Last-Modified\": [\"Fri, 17 Apr 2020 18:43:00 GMT\"], \"Accept-Ranges\": [\"bytes\"], \"Content-Length\": [\"39\"]}}\r\n"]
|
||||
[43.703537, "o", "🔒 Easy HTTPS, just like that! 🎉\r\n\r\n"]
|
||||
[43.706045, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
|
||||
[43.706405, "o", "\u001b]7;file://Shadowfax.local/Users/matt/demo\u0007"]
|
||||
[43.706517, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J \r\n\u001b[90m╔[\u001b[32m√ \u001b[38;5;81mmatt\u001b[90m@\u001b[38;5;82mShadowfax\u001b[90m:\u001b[38;5;81m~/demo\u001b[90m] \r\n╚>\u001b[39m% \u001b[K\u001b[?2004h"]
|
||||
[48.347301, "o", "\u001b[?2004l\r\r\n"]
|
289
src/resources/css/account/common.css
Normal file
289
src/resources/css/account/common.css
Normal file
|
@ -0,0 +1,289 @@
|
|||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html, body {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
html {
|
||||
/* by setting the min-height of both html and body to 100%,
|
||||
it ensures that flex items are centered on screen, but
|
||||
also allows body to overflow screen height for tall content */
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
font: 16px sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
background: #e8ebf0;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #2b9cff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #0f6ab9;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: white;
|
||||
margin: auto;
|
||||
box-shadow: 0 20px 40px rgba(0, 0, 0, .1);
|
||||
display: flex;
|
||||
border-radius: 5px;
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
.card section {
|
||||
padding: 50px;
|
||||
text-align: center;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.card section.head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
background: #f3f7ff;
|
||||
border-right: 1px solid #e8ebf0;
|
||||
border-top-left-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
}
|
||||
|
||||
.card p {
|
||||
margin: 0 auto;
|
||||
max-width: 400px;
|
||||
line-height: 1.25em;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.card .logo {
|
||||
width: 100%;
|
||||
max-width: 100px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.card h1 {
|
||||
font-size: 42px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.form-fields {
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
input {
|
||||
font-size: 16px;
|
||||
font-family: 'PT Mono', 'Source Code Pro', monospace;
|
||||
}
|
||||
|
||||
.card input,
|
||||
.card button {
|
||||
display: block;
|
||||
margin: 1em auto;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.card input[type=text],
|
||||
.card input[type=email],
|
||||
.card input[type=password] {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.card button {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
padding: 10px 20px;
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
.card {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.swal-content p {
|
||||
margin: .5em 0;
|
||||
}
|
||||
|
||||
#reset-password-step2 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.logo-container {
|
||||
text-align: center;
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
.logo {
|
||||
max-width: 100px;
|
||||
}
|
||||
|
||||
.help {
|
||||
border-bottom: 1px dotted #222;
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.beta {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
justify-content: space-between;
|
||||
font-family: Maven Pro, sans-serif;
|
||||
}
|
||||
|
||||
.container > nav {
|
||||
background: #f8faff;
|
||||
width: 25%;
|
||||
max-width: 250px;
|
||||
}
|
||||
|
||||
.container > nav ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.container > nav ul a {
|
||||
display: block;
|
||||
padding: 10px 20px;
|
||||
color: #546c75;
|
||||
}
|
||||
|
||||
.container > nav ul a:hover {
|
||||
color: #01324b;
|
||||
background-color: #ebf3fb;
|
||||
}
|
||||
|
||||
.container > nav ul a.current {
|
||||
background-color: #e0ecfb;
|
||||
font-weight: bold;
|
||||
color: #01324b;
|
||||
}
|
||||
|
||||
.container > main {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.container > main.dashboard {
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.container section {
|
||||
background: white;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, .08);
|
||||
margin: 25px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
input[type=text],
|
||||
input[type=email],
|
||||
input[type=password] {
|
||||
padding: 8px;
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
form .field {
|
||||
padding: 0 20px 20px;
|
||||
max-width: 600px;
|
||||
margin: 0 auto 20px auto;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
form label b {
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
form .description {
|
||||
font-size: 14px;
|
||||
color: #777;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
form button,
|
||||
form input[type=submit] {
|
||||
font-size: 16px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
input[type=checkbox] {
|
||||
cursor: pointer;
|
||||
transform: scale(1.25);
|
||||
}
|
||||
|
||||
|
||||
|
||||
section .pad {
|
||||
margin: 15px 20px;
|
||||
}
|
||||
|
||||
section button:not([type=submit]),
|
||||
section .button:not([type=submit]) {
|
||||
font-size: 14px;
|
||||
padding: 6px 15px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
|
||||
section h1 {
|
||||
font-size: 22px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
tr {
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #ebf3ff;
|
||||
text-align: left;
|
||||
}
|
13
src/resources/css/account/dashboard.css
Normal file
13
src/resources/css/account/dashboard.css
Normal file
|
@ -0,0 +1,13 @@
|
|||
input[name=path] {
|
||||
font-size: 14px;
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
width: auto;
|
||||
/* max-width: 450px; */
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
a.disabled {
|
||||
color: #aaa;
|
||||
cursor: not-allowed;
|
||||
}
|
2563
src/resources/css/asciinema-player-2.6.1.css
Normal file
2563
src/resources/css/asciinema-player-2.6.1.css
Normal file
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue