docs(caddy): where the live Caddyfile is, and what the syntax page's claims cost

The page explained matcher ordering beautifully and never said where the file lives — so the
next agent hunts for a Caddyfile on the host and finds nothing. Measured on Dankclaw
2026-10-21: Caddy is a rootless Quadlet container (`caddy.container`, a *user* unit, so a
root `systemctl is-active caddy` answers `inactive` and means nothing), its config is
`/etc/caddy/Caddyfile` **inside the container**, `/etc/caddy` does not exist on the host, and
`pgrep -a caddy` prints a config path that no host path satisfies. Version is v2.11.7, which
closes the one version-dependent rule on the page: the leading-`/` `rewrite` form needs
2.8.0+, so the `*` disambiguator is legacy in this fleet's config.

Also: the seven caddyserver.com links sat in a mid-page "Sources:" paragraph. OKF wants
external claims under `# Citations`, so they move there and each entry says which claim it
supports. The validate section now points at the container instead of telling you to run the
validator on a file that is not there.

Refs #64
This commit is contained in:
Frank
2026-10-21 02:14:39 -07:00
parent 62a70caebb
commit e49537c2ac
+47 -15
View File
@@ -1,13 +1,13 @@
---
type: reference
title: Caddyfile Syntax
description: Caddy Caddyfile reference — directive and matcher syntax, named matchers, directive sorting, and the handle/route order rule. Grounded in caddyserver.com (fetched 2026-08-28).
description: Caddy Caddyfile reference — the syntax that bites (matchers, directive sorting, handle vs route), plus where the fleet's live Caddyfile actually is and how to validate it.
resource: https://caddyserver.com/docs/caddyfile
tags:
- caddy
- caddyfile
- reverse-proxy
verified: 2026-08-28
verified: 2026-10-21
---
# Caddyfile Syntax
@@ -17,13 +17,28 @@ port). Directives inside the block control how Caddy serves requests. Matchers
classify requests. This page records the syntax that trips people up, grounded
in the official docs.
Sources: [caddyfile-tutorial](https://caddyserver.com/docs/caddyfile-tutorial),
[matchers](https://caddyserver.com/docs/caddyfile/matchers),
[rewrite](https://caddyserver.com/docs/caddyfile/directives/rewrite),
[handle](https://caddyserver.com/docs/caddyfile/directives/handle),
[forward_auth](https://caddyserver.com/docs/caddyfile/directives/forward_auth),
[reverse_proxy](https://caddyserver.com/docs/caddyfile/directives/reverse_proxy),
[concepts](https://caddyserver.com/docs/caddyfile/concepts).
The syntax below is the parts that bite; the sources are listed under
`# Citations` at the end.
## Where the live Caddyfile is
Caddy runs as a **rootless Quadlet container** on Dankclaw
(`~/.config/containers/systemd/caddy.container`, unit `caddy.service`). It is a *user* unit:
`systemctl is-active caddy` as root answers `inactive` and means nothing — ask the user
manager (`systemctl --user`). Its config path lives inside the container, so there is **no
`/etc/caddy` on the host**: a host-side search for a Caddyfile comes up empty, and
`pgrep -a caddy` prints `--config /etc/caddy/Caddyfile` for a path that does not exist
locally. Everything about it goes through `podman exec`:
```bash
ssh dankclaw podman exec caddy cat /etc/caddy/Caddyfile
ssh dankclaw podman exec caddy caddy version # v2.11.7, read 2026-10-21
ssh dankclaw systemctl --user restart caddy
```
The live file's own header says what it fronts (both hosts, `franksdank.cloud` names,
Pi-hole-resolved); its deployment history belongs to the serverAppConfigs vault
(`Infrastructure/Caddy.md`), not to this syntax page.
## Directive and matcher syntax
@@ -116,9 +131,10 @@ Use `handle` for mutually exclusive branches (for example, per-path pages). Use
rewrite [<matcher>] <to>
```
`<to>` is the new URI (path or query). If `<to>` starts with `/`, Caddy 2.8.0+
parses it directly. Before 2.8.0, a leading `/` was confused with a path
matcher, so a `*` disambiguator was needed: `rewrite * /index.html`.
`<to>` is the new URI (path or query). If `<to>` starts with `/`, Caddy 2.8.0+ parses it
directly. Before 2.8.0 a leading `/` was confused with a path matcher, so a `*`
disambiguator was needed: `rewrite * /index.html`. The fleet runs v2.11.7, so write the
plain form.
`try_files <files...>` rewrites to the first listed file that exists. It is the
clean way to serve a named file for a path prefix:
@@ -244,6 +260,22 @@ wins). Put the specific `handle /admin*` before the catch-all `handle`.
## Validate before you deploy
Run `caddy validate --config <file> --adapter caddyfile` before loading a
Caddyfile. A placeholder hash (not a real bcrypt hash) fails validation with
`base64-decoding password`. Render the real hashes first, then validate.
Run `caddy validate --config <file> --adapter caddyfile` before loading a Caddyfile. A
placeholder hash (not a real bcrypt hash) fails validation with `base64-decoding password`.
Render the real hashes first, then validate. On the fleet's Caddy the file is inside the
container — run the validator there, see
[Where the live Caddyfile is](#where-the-live-caddyfile-is).
# Citations
- [Caddyfile tutorial](https://caddyserver.com/docs/caddyfile-tutorial) and
[concepts](https://caddyserver.com/docs/caddyfile/concepts) — directive form, the three
matcher token forms, and the canonical sort order behind the `handle`/`route` rule.
- [matchers](https://caddyserver.com/docs/caddyfile/matchers) — exact vs `*` prefix path
matching, named matchers, `matcher is defined more than once`.
- [rewrite](https://caddyserver.com/docs/caddyfile/directives/rewrite),
[handle](https://caddyserver.com/docs/caddyfile/directives/handle) and
[reverse_proxy](https://caddyserver.com/docs/caddyfile/directives/reverse_proxy) — the
2.8.0 leading-`/` change, `handle` vs `route` semantics, `trusted_proxies`.
- [forward_auth](https://caddyserver.com/docs/caddyfile/directives/forward_auth) — the
outpost-before-gate ordering and `copy_headers`.