> The problem for me in understanding that particular config is that I don't know enough about HTTP to know if you can set headers with asterisks in them. I can't look at that config snippet and figure out immediately if it's matching incoming requests and sending the matched requests to the backend or if it's adding the headers to incoming requests (that are matched some other way) before sending them to the backend.

It's _just_ matching, when it's inside a @ named matcher. No manipulation of the headers is going on. The docs would say so if it did. See https://caddyserver.com/docs/caddyfile/matchers#header

And as for reverse_proxy, all headers are passed through as-is, with a few exceptions which are documented here: https://caddyserver.com/docs/caddyfile/directives/reverse_pr...

> The root of the confusion for me is that other reverse proxies match on a location for that type of stuff (ex: /wss/) and I simply don't know enough about websockets to make an educated guess about how Caddy is deciding where the traffic gets routed. That's not the kind of thing I'd show up on your forum asking about either. I can figure it out if I need to, but that likely involves spinning up a Caddy server and watching the traffic to see what's going on.

Actually, asking on the forums is exactly what you should do, if you're confused. We can help there.

And yes -- the initial websocket connection (which is actually HTTP first, then "upgraded" to a raw TCP duplex pipe) contains those two headers which can be used to reliably match websocket connections. It's more reliable to do it this way than by path, because you can completely multi-plex a regular HTTP app and a websocket app this way even if they both share the same request paths. Some people end up dedicating a separate port for websocket connections for their apps because of concerns of path overlap, but matching on headers let you avoid that.

I'm not sure where you found that config, but I'd hope that there was at least a mention of what it's doing. It was probably originally taken from here in the docs https://caddyserver.com/docs/caddyfile/matchers#named-matche... which does have a mention of what that matcher is doing.

> Something as simple as `set-header` or `match-header` instead of `header` would make it easier for me to read and learn the config because it adds enough context that I can immediately figure out what the config is doing.

That's redundant, because you're inside of a named matcher, i.e. a thing starting with @, so that's your hint that it's matching.

Also the 'header' directive (outside matchers) doesn't _only_ set headers, it can also delete them or make in-place replacements, or even set a default if none is already set. See https://caddyserver.com/docs/caddyfile/directives/header

> I'm talking about make a huge difference for someone that doesn't know everything.

Well, it's a balance. For the Caddyfile, we decided to focus on ergonomics rather than absolute clarity. We could make the syntax more verbose (and early betas of Caddy v2 had a much more verbose matcher syntax) but we want it to be easy to write configs once you've gotten your bearings. Yes there's a learning curve, but there's a learning curve for everything.

> The download page only gives me a binary, right? I need to deal with setting up a system service. It's not hard, but it's extra steps because I need to redo it every time there's an update or I need to automate it somehow.

If you're on debian, you can install Caddy with a systemd service by using our apt repo https://caddyserver.com/docs/install#debian-ubuntu-raspbian and then if you need to swap out the binary with a custom one, you can follow these steps https://caddyserver.com/docs/build#package-support-files-for... and then after that point if you need to upgrade versions, you can actually run "sudo caddy upgrade" which will hit the Download page to fetch a new build with the same plugins that you had in your existing binary, but with the latest version of Caddy https://caddyserver.com/docs/command-line#caddy-upgrade.

> For my specific use case, running a Docker container (locked to a stable tag) that auto updates is ideal.

See my other reply where I explain the setup for Docker. It's super easy!

> Is it reasonable to expect the users of Docker images to be on the same level as the developers of them?

If you're using Docker, it's not a stretch to expect that you can at least copy a Dockerfile from the docs and build it (either with 'docker build' or via your docker-compose.yml). You don't have to build it from CI, you can just build it in-place on the server you're running it on.

> Traefik has Cloudflare DNS support baked in to the official Docker image. It's not nearly as easy as Caddy, but it has it.

And the downside of that is that their binary is significantly more bloated because of it. It has to pull in the Cloudflare Go library for their API, as well as the APIs/SDKs for all the other DNS providers they support. That increases the attack surface a considerable amount. We decided we didn't want to have the bloat and risk by shipping them by default, so they're plugins. Also, most of them are not maintained by us, by rather by the community, because we can't be expected to actually use all these DNS providers ourselves, we can only maintain the ones for providers we actually use ourselves. Nobody ever needs all the DNS providers plugged in at the same time, you'll only ever need one at a time (outside of some weird setups where you're serving domains owned by customers or something).

We've worked hard to make sure building with plugins is as easy as possible, and I really think we've achieved that. You just need Go, and xcaddy (a little helper program we wrote), then you run 'xcaddy build --with <plugin>' and it makes a build for you. The 'builder' docker image variant gives you Go + xcaddy so you can produce a build with whatever plugins you want, very easily.