I wasn't trying to imply that Caddy is bad, so I hope it didn't come off like that. I was trying to highlight how things that seem simple might only be simple to people that already have a comprehensive understanding of the topic. I'll give you some follow up examples:
> What asterisks are almost _always_ for: wildcards!
However the link you gave doesn't include a single mention or example of using wildcards, so I can't even educate myself. Was that the link you intended to share?
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.
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.
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. If it's setting headers, that instantly tells me that my lack of knowledge is related to how the matching is happening and I can ignore all the other stuff like the asterisks and the capitalization, at least temporarily. In my specific case, I wanted to translate that config to nginx, so figuring out how the matching works is all I really need.
At the risk of sounding stupid, I'll say I still don't understand if it's routing traffic based on matched headers or adding headers to already matched traffic. This [1] answer seems like a similar config for nginx, but it's routing traffic based on matching those headers.
You have to remember that you can look at a config and instantly map it to the http spec. You probably know the context instantly because one of the possibilities is too stupid to consider. The thing is there's always going to be someone trying to learn that knows nothing and the contextual hints I'm talking about make a huge difference for someone that doesn't know everything.
> What do you mean "set up on your own"? Our download page does it for you.
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. For my specific use case, running a Docker container (locked to a stable tag) that auto updates is ideal.
> Or Docker images can be automated to include it as well.
That kind of illustrates the point I was trying to make. Setting up an automated Docker build to bake in the functionality I want is significantly different than getting it out of the box. Imagine telling a young person trying to learn "start by setting up an automated Docker build that bakes Caddy + the DNS plugin into the container." Is it reasonable to expect the users of Docker images to be on the same level as the developers of them?
> Takes about 2-5 minutes to set up, including getting credentials from your DNS provider.
Unless you're an experienced sysadmin or a Docker expert, getting to the point where you can start to configure DNS challenges is a huge amount of learning and work. It would take me half a day to set up a good quality, CI built Docker image with the Cloudflare DNS plugin baked in and I've spent hundreds (if not thousands) of hours working with Linux, Docker, CI, etc.. It might take 5 minutes to *configure* if you already know what you're doing.
> no other servers come with Cloudflare-specific support baked in with automatic ACME challenge solvers
Traefik has Cloudflare DNS support baked in to the official Docker image. It's not nearly as easy as Caddy, but it has it.
I qualified my opinion up front saying "for a home lab scale setup". I agree 100% that Caddy is a better product on a technical level, but for a certain scale of setup NGINX Proxy Manager provides a better user experience for me because it's a single container with everything I need baked in, someone else maintains it, and the GUI makes simple reverse proxy configs easier than anything I've ever used (including Caddy).
I wasn't trying to say Caddy is bad and I'm sorry if it came off like that. The only constructive feedback I can give is that if there was an official Docker image with the Cloudflare DNS plugin baked in it's likely I would have put in the time to learn Caddy. I think you underestimate the amount of effort it takes for someone that isn't an expert in the space to get up to speed. For myself I would set aside a full day to familiarize myself with running Caddy, but once I add in the need to build (and maintain) my own Docker image it gets to the point where, pragmatically, I ended up choosing a "good enough" solution over what I'd consider "the best" solution (I tried Caddy first).
> 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.
> 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.
> 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.
Thanks a ton for taking the time to write this reply. I went over it and re-read some of the docs and it makes a lot more sense to me now. The thing that made it click for me is realizing how directives act differently depending on their context/scope (I'm not sure what the right term is).
I really appreciate the explanation for the websocket matching. I spent a lot of time tying to find an explanation for that and couldn't find a good overview anywhere. Understanding the way the connection is upgraded helped me understand how everything is matched and sent to the backend. Now that I understand one scenario fairly well the docs are magically easier to read (imagine that! - lol).
> 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.
Yes. Everything is like that. When you're learning, you're like me, complaining the config is too terse and magical. Once you know it, you're like me, complaining the config is too verbose and explicit. :-)
The plugin/build thing is a bit of a mixed bag. I get the reasoning and the build system is very good/simple (building a Docker image is trivial). I replied to your other example and gave a really unpolished thought dump of why I don't want to maintain my own image. Maybe you could convince some of the infrastructure providers like Cloudflare to maintain community images with their DNS plugins baked in.
Thanks again for taking the time to reply. I'm probably going to set up a custom Docker image and give things another try. If I do and I end up using Caddy, hopefully I can pay it forward at some point :-)
> The thing that made it click for me is realizing how directives act differently depending on their context/scope (I'm not sure what the right term is).
The Concepts page explains https://caddyserver.com/docs/caddyfile/concepts#structure. Essentially, "directives" are top-level things inside of a site block (or things within 'route' or 'handle' as well, which wrap other directives), and things inside directives are "subdirectives", i.e. options/config for directives. Matchers are just matchers. Things inside an "empty" block at the top of the Caddyfile are "global options" (similar relative placement to directives, but can only appear in the global options block at the top).
> Maybe you could convince some of the infrastructure providers like Cloudflare to maintain community images with their DNS plugins baked in.
We have no contacts at Cloudflare. They'd have to reach out to us, tbh. But I don't think they are likely to see it as a benefit to them to spend the time either. Ultimately, the plugin very rarely changes, it's pretty stable at this point.
> Thanks again for taking the time to reply. I'm probably going to set up a custom Docker image and give things another try. If I do and I end up using Caddy, hopefully I can pay it forward at some point :-)
Glad to hear. Next time you need help, the forums are the best place to ask. It actually supports markdown, and it's actually meant for Caddy support https://caddy.community/
Hey. I wanted to let you know that I eventually switched my whole indie dev home lab to Caddy and it wasn't really fair for me to call the config a "black box". Once I got used to the conventions I ended up with config(s) that I'm extremely happy with and the official docs are very, very good.
> What asterisks are almost _always_ for: wildcards!
However the link you gave doesn't include a single mention or example of using wildcards, so I can't even educate myself. Was that the link you intended to share?
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.
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.
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. If it's setting headers, that instantly tells me that my lack of knowledge is related to how the matching is happening and I can ignore all the other stuff like the asterisks and the capitalization, at least temporarily. In my specific case, I wanted to translate that config to nginx, so figuring out how the matching works is all I really need.
At the risk of sounding stupid, I'll say I still don't understand if it's routing traffic based on matched headers or adding headers to already matched traffic. This [1] answer seems like a similar config for nginx, but it's routing traffic based on matching those headers.
You have to remember that you can look at a config and instantly map it to the http spec. You probably know the context instantly because one of the possibilities is too stupid to consider. The thing is there's always going to be someone trying to learn that knows nothing and the contextual hints I'm talking about make a huge difference for someone that doesn't know everything.
> What do you mean "set up on your own"? Our download page does it for you.
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. For my specific use case, running a Docker container (locked to a stable tag) that auto updates is ideal.
> Or Docker images can be automated to include it as well.
That kind of illustrates the point I was trying to make. Setting up an automated Docker build to bake in the functionality I want is significantly different than getting it out of the box. Imagine telling a young person trying to learn "start by setting up an automated Docker build that bakes Caddy + the DNS plugin into the container." Is it reasonable to expect the users of Docker images to be on the same level as the developers of them?
> Takes about 2-5 minutes to set up, including getting credentials from your DNS provider.
Unless you're an experienced sysadmin or a Docker expert, getting to the point where you can start to configure DNS challenges is a huge amount of learning and work. It would take me half a day to set up a good quality, CI built Docker image with the Cloudflare DNS plugin baked in and I've spent hundreds (if not thousands) of hours working with Linux, Docker, CI, etc.. It might take 5 minutes to *configure* if you already know what you're doing.
> no other servers come with Cloudflare-specific support baked in with automatic ACME challenge solvers
Traefik has Cloudflare DNS support baked in to the official Docker image. It's not nearly as easy as Caddy, but it has it.
I qualified my opinion up front saying "for a home lab scale setup". I agree 100% that Caddy is a better product on a technical level, but for a certain scale of setup NGINX Proxy Manager provides a better user experience for me because it's a single container with everything I need baked in, someone else maintains it, and the GUI makes simple reverse proxy configs easier than anything I've ever used (including Caddy).
I wasn't trying to say Caddy is bad and I'm sorry if it came off like that. The only constructive feedback I can give is that if there was an official Docker image with the Cloudflare DNS plugin baked in it's likely I would have put in the time to learn Caddy. I think you underestimate the amount of effort it takes for someone that isn't an expert in the space to get up to speed. For myself I would set aside a full day to familiarize myself with running Caddy, but once I add in the need to build (and maintain) my own Docker image it gets to the point where, pragmatically, I ended up choosing a "good enough" solution over what I'd consider "the best" solution (I tried Caddy first).
1. https://serverfault.com/a/923254/133882