Updated v2: Documentation (markdown)

Matt Holt 2019-07-02 22:17:44 -06:00
parent 7efba6c6a0
commit b6db30c1a4

@ -1,6 +1,6 @@
(This documentation is very much a work in progress!)
## Contents
# Contents
- [Command-line interface]()
- [start]()
@ -22,11 +22,13 @@
- [storage]()
- [caddy.storage.file_system]()
- [apps]()
- [http]()
- [tls]()
## Command-line interface
# Command-line interface
### start
## start
```
$ caddy start
@ -37,7 +39,7 @@ Starts the Caddy process, optionally bootstrapped with an
initial config file. Blocks until server is successfully
running (or fails to run), then returns.
### run
## run
```
$ caddy run
@ -46,7 +48,7 @@ $ caddy run
Same as `start`, but blocks indefinitely.
### stop
## stop
```
$ caddy stop
@ -55,7 +57,7 @@ $ caddy stop
Stops the running Caddy process. (Note: this will stop any process named the same as the executable file.)
### version
## version
```
$ caddy version
@ -63,7 +65,7 @@ $ caddy version
Prints the version.
### list-modules
## list-modules
```
$ caddy list-modules
@ -71,7 +73,7 @@ $ caddy list-modules
Prints the modules that are installed.
### environ
## environ
```
$ caddy environ
@ -81,19 +83,19 @@ Prints the environment as seen by caddy. Can be useful when debugging init syste
## Admin endpoint
# Admin endpoint
Caddy is configured through an administration endpoint which is an HTTP listener with a REST API.
Default address: `localhost:2019`
### POST /load
## POST /load
Sets Caddy's configuration to the JSON body. The `Content-Type` header must indicate a JSON payload, e.g. `application/json`.
_Enterprise_: If you are using the `/config` endpoint to modify configuration instead, you MUST NOT use `/load` because it lacks the capabilities for partial configuration updates.
#### Example
### Example
```bash
$ curl -X POST "http://localhost:2019/load" \
@ -101,13 +103,13 @@ $ curl -X POST "http://localhost:2019/load" \
-d @caddy.json
```
### GET /config/[scope]
## GET /config/[scope]
🏢 _Enterprise_
Exports Caddy's current configuration. Returns a JSON body. Any path appended to this endpoint will traverse the configuration and return only the scope scope.
#### Examples
### Examples
```bash
$ curl "http://localhost:2019/config/"
@ -120,13 +122,13 @@ $ curl "http://localhost:2019/config/apps/http/servers/myserver/listen"
```
### POST /config/[scope]
## POST /config/[scope]
🏢 _Enterprise_
Changes Caddy's configuration at the named scope to the JSON body of the request. If the named scope is an array, POST appends; if an object, it creates or replaces.
#### Example
### Example
```bash
$ curl -X POST \
@ -136,13 +138,13 @@ $ curl -X POST \
```
### PUT /config/[scope]
## PUT /config/[scope]
🏢 _Enterprise_
Changes Caddy's configuration at the named scope to the JSON body of the request. If the named scope is an array, PUT inserts; if an object, it strictly creates a new value.
#### Example
### Example
```bash
$ curl -X PUT \
@ -152,13 +154,13 @@ $ curl -X PUT \
```
### PATCH /config/[scope]
## PATCH /config/[scope]
🏢 _Enterprise_
Changes Caddy's configuration at the named scope to the JSON body of the request. PATCH strictly replaces an existing value or array element.
#### Example
### Example
```bash
$ curl -X PUT \
@ -168,13 +170,13 @@ $ curl -X PUT \
```
### DELETE /config/[scope]
## DELETE /config/[scope]
🏢 _Enterprise_
Changes Caddy's configuration at the named scope to the JSON body of the request. DELETE deletes the value at the named scope.
#### Example
### Example
```bash
$ curl -X DELETE "http://localhost:2019/config/apps/http/servers/myserver"
@ -182,7 +184,7 @@ $ curl -X DELETE "http://localhost:2019/config/apps/http/servers/myserver"
## Caddy modules
# Caddy modules
Caddy modules are distinct from [Go modules](https://github.com/golang/go/wiki/Modules), although technically speaking, Caddy modules can be implemented by Go modules. When we talk about modules here, we mean Caddy modules.
@ -202,7 +204,7 @@ _Guest modules_ (or _child modules_) are modules which get loaded or initialized
## Config structure
# Config structure
Caddy configuration is a JSON document.
@ -218,7 +220,7 @@ At the top level, you'll find properties needed for Caddy's basic functionality:
}
```
### admin
## admin
Configures the administration endpoint.
@ -230,13 +232,13 @@ Configures the administration endpoint.
- `listen`: the address to which the admin endpoint's listener should bind itself
### storage
## storage
Configures Caddy's default storage module.
Default: The local file system (`caddy.storage.file_system`). If `XDG_DATA_HOME` is set, then `$XDG_DATA_HOME/caddy` is the folder. Otherwise, `$HOME/.local/share/caddy` is the folder.
#### caddy.storage.file_system
### caddy.storage.file_system
```json
{
@ -249,7 +251,130 @@ Default: The local file system (`caddy.storage.file_system`). If `XDG_DATA_HOME`
- `root`: The base path in which things should be stored
### apps
## apps
Each app to initialize should be keyed by its name (i.e. module ID).
### http
The `http` app implements an HTTP server with automatic HTTPS. It consists of servers which you name and describe. Each server has listeners and routes.
Routes are not your traditional notion of routes (i.e. "GET /foo/bar" -> someFunc). Routes in Caddy 2 are much more powerful. They are given in an ordered list, and each route has three parts: match, apply, respond. All parts are optional. Match is the "if" statement of each route. Each route takes a list of matcher sets. A matcher set comprises matchers of various types. A matcher may comprise multiple values.
The boolean logic of request matching goes like this:
- Matcher sets are OR'ed (first matching matcher set is sufficient)
- Matchers within a site are AND'ed (all matchers in the set must match)
- Values within a specific matcher are OR'ed (but this could vary depending on the matcher; some don't allow multiple values)
This design enables moderately complex logic such as:
```
IF (Host = "example.com")
OR (Host = "sub.example.com" AND Path = "/foo/bar")
```
The expressions in parentheses are matcher sets. Even more advanced logic can be expressed through the Starlark expression matcher.
If a request matches a route, the route's middleware are applied to the request. Unlike Caddy 1, middleware in Caddy 2 are chained in the order you specify, rather than a hard-coded order. (So be careful!) Then a responder, if defined, is what actually writes the response.
All matching routes cascade on top of each other to create a "composite route" that is customized for each request. Crucially, if multiple responders match a request, only the first responder is used; the rest are ignored. This way it is impossible to corrupt the response with multiple writes solely by configuration (a common bug in Caddy 1).
A good rule of thumb for building routes: keep middleware that deal with the request near the beginning, and middleware that deal with the response near the end. Generally, this will help ensure you put things in the right order (e.g. the encode middleware must wrap the response writer, but you wouldn't want to execute templates on a compressed bitstream, so you'd put the templates middleware later in the chain).
If a route returns an error, the error along with its recommended status code are bubbled back to the HTTP server which executes a separate error route, if specified. The error routes work exactly like the normal routes, making error handling very powerful and expressive.
There is more to routing such as grouping routes for exclusivity (i.e. radio buttons instead of checkboxes); making routes terminal so they don't match any more later in the list; and rehandling, which is like an internal redirect that restarts handling the (likely modified) request. You can also omit matchers in a route to have it match all requests. Phew! Lots to know.
```json
{
"http_port": 80,
"https_port": 443,
"grace_period": "10s",
"servers": {
"my_server": {
"listen": [":8080"],
"routes": [
{
"match": [{
"host": ["example.com"],
"path": ["/foo/bar", "*.ext"],
"path_regexp": {
"name": "myre",
"pattern": "/foo/(.*)/bar"
},
"method": ["GET"],
"query": {"param": ["value"]},
"header": {"Field": ["foo"]},
"header_regexp": {
"Field": {
"pattern": "foo(.*)-bar",
"name": "other"
},
},
"protocol": "grpc",
"not": {
"path": ["/foo/bar"],
"...": "(any matchers in here will be negated)"
},
"remote_ip": {
"ranges": ["127.0.0.1", "192.168.0.1/24"]
},
"starlark_expr": "req.host == 'foo.com' || (req.host != 'example.com' && req.host != 'sub.example.com')"
}],
"apply": [
{
"middleware": "rewrite",
"method": "FOO",
"uri": "/test/abc"
},
{
"middleware": "headers",
"response": {
"set": {
"Foo": ["bar"],
"Regexp": ["{http.matchers.path_regexp.myre.0}"]
}
}
}
],
"respond": {
"responder": "static",
"body": "Booyah: {http.request.method} {http.request.uri} Foo: {http.response.header.foo}"
},
"group": "exclusive",
"terminal": true
}
],
"errors": {
"routes": [ ... ]
},
"tls_connection_policies": [
{
"match": {
"host": ["example.com"]
},
"alpn": ["..."],
"cipher_suites": ["..."],
"certificate_selection": {
"policy": "enterprise",
"subject.organization": "O1",
"tag": "company1"
}
}
],
"automatic_https": {
"disabled": false,
"disable_redirects": false,
"skip": ["exclude", "these", "domains"],
"skip_certificates": ["doesn't provision certs for these domains but still does redirects"]
},
"max_rehandles": 3
}
}
}
```
# FIN
@ -261,51 +386,7 @@ What follows is the original ad-hoc documentation that we sent some early tester
HTTP App
=========
Routes are not your traditional notion of routes (i.e. "GET /foo/bar" -> someFunc).
Routes in Caddy 2 are much more powerful. They are given in an ordered list, and each
route has three parts: match, apply, respond. All parts are optional. Match is the "if"
statement of each route. Each route takes a list of matcher sets. A matcher set
comprises matchers of various types. A matcher may comprise multiple values.
The boolean logic of request matching goes like this:
- Matcher sets are OR'ed (first matching matcher set is sufficient)
- Matchers within a site are AND'ed (all matchers in the set must match)
- Values within a specific matcher are OR'ed (but this could vary depending on
the matcher; some don't allow multiple values)
This design enables moderately complex logic such as:
IF (Host = "example.com") OR (Host = "sub.example.com" AND Path = "/foo/bar")
The expressions in parentheses are matcher sets. Even more advanced logic can be
expressed through the Starlark expression matcher.
If a request matches a route, the route's middleware are applied to the request.
Unlike Caddy 1, middleware in Caddy 2 are chained in the order you specify, rather than
a hard-coded order. (So be careful!) Then a responder, if defined, is what actually
writes the response.
All matching routes cascade on top of each other to create a "composite route" that is
customized for each request. Crucially, if multiple responders match a request, only the
first responder is used; the rest are ignored. This way it is impossible to corrupt the
response with multiple writes solely by configuration (a common bug in Caddy 1).
A good rule of thumb for building routes: keep middleware that deal with the request
near the beginning, and middleware that deal with the response near the end. Generally,
this will help ensure you put things in the right order (e.g. the encode middleware
must wrap the response writer, but you wouldn't want to execute templates on a
compressed bitstream, so you'd put the templates middleware later in the chain).
If a route returns an error, the error along with its recommended status code are
bubbled back to the HTTP server which executes a separate error route, if specified.
The error routes work exactly like the normal routes, making error handling very
powerful and expressive.
There is more to routing such as grouping routes for exclusivity (i.e. radio buttons
instead of checkboxes); making routes terminal so they don't match any more later in
the list; and rehandling, which is like an internal redirect that restarts handling
the (likely modified) request. You can also omit matchers in a route to have it match
all requests. Phew! Lots to know.
...
Now then. The contents of caddy.json are up to you. Here's a contrived example to
demonstrate the fields you can use: