gcss
(Carl Drechsel)
May 3, 2022, 12:14am
1
1. Caddy version (caddy version
):
v2.5.0 h1:eRHzZ4l3X6Ag3kUt8nj5IxATprhqKq/wToP7OHlXWA0=
Today, a frustrated coworker sent me this Caddyfile
. Now the issue’s obvious to me, but she had spent half a day on it:
:80 {
handle_path /api* {
reverse_proxy /api* {$SERVER}:5000
}
}
and why this would result in a 200 with an empty body
curl -vvv 'http://caddy_server/api/my/path' -H 'some-header: some-value'
My annotated response to her was:
# disable Automatic HTTPS
:80 {
# handle_path does the same as handle, but it strips a prefix from the request before running its handlers
handle /api* {
# NOTE: This is a redundant. Consider removing the matcher as the handler does the work for you. Let's discuss after standup
reverse_proxy /api* {$SERVER}:5000
}
}
That said, I really wanted to write something like this for her:
# disable Automatic HTTPS
:80 {
# handle_path does the same as handle, but it strips a prefix from the request before running its handlers
handle /api* {
# NOTE: This is a redundant. Consider removing the matcher as the handler does the work for you. Let's discuss after standup
reverse_proxy /api* {$SERVER}:5000
handle {
# Fallback for any otherwise unhandled requests, maybe a 404 if you want
respond "Nope!" 404
}
respond * 500 {
body "no handlers were found"
close
}
}
}
Now, this seems to be a freq. problem:
Yeah we had a mistake in the spot that was logging reverse_proxy debug logs so it wasn’t logging errors. These two commits fixed it and v2.1 will be better in that regard.
If you want, you can compile from source or use the latest build from CI for now if you need it right away.
opened 11:34PM - 24 May 20 UTC
closed 04:23AM - 03 Oct 22 UTC
feature
This was suggested by a user on the forums: https://caddy.community/t/v2-struggl… ing-with-reverse-proxy-in-a-caddyfile/8352/10
It can be tricky to determine what's going on when Caddy returns an empty 200 response. A debug log that would mention that the request was not matched would be pretty handy to alert users that something wasn't configured correctly.
I took a quick look through the code and I'm not seeing an obvious way to do this because of the handler middleware chain. I think this might not be possible without having some state on the request context that gets set when a handler matches, then checked later in `server.go`'s `ServeHTTP()`.
I'm mainly opening this as a "would be nice if..." but if it's not viable, we can just close this.
opened 09:38AM - 20 Nov 20 UTC
closed 04:03PM - 01 Dec 20 UTC
discussion
documentation
Caddy's current behavior when no site or handler match is to return a 200 status… and empty body. The idea behind this is that the server defaults to answering with 200 and an empty body with no configuration without any "magic"/"convenience" behavior in certain cases to do otherwise. You need to explicitly match all routes to with the behavior you need. This is sadly not well documented and the documentation should likely explicitly state this and give examples.
Personally a 200 and an empty body might make sense if there are no handlers configured at all, but it can be argued that a 404 or even just closing the connection might be a better behavior when there are any handlers configured, as otherwise receiving a 200 and an empty body is highly confusing and it took me quite a while to figure out what is going on. Still that is "magic" behavior that some may like and some may not.
The other issue is that this is not that easy to do with the Caddyfile, forcing you to eschew some of the shorthand syntax and convenience it tries to provide. Let's imagine a Caddyfile that just does a plain `reverse_proxy` under some `/api/` route:
```
localhost
reverse_proxy /api/ upstream
```
Any request to something not under `/api/` will respond with a 200 and an empty body. Normally users coming from other servers will expect a 404, but since Caddy prefers to be explicit, this is not the case and you need to add that yourself. The problem? It is not possible to achieve this easily with just the simple "behavior-first" style configuration without using `route` or `handle`, as there is no support for configuring a "fallback" route that will match, if no other route does, in that style of configuration. You are forced to use either one of the more verbose:
```
localhost
route {
reverse_proxy /api/ upstream
respond 404
}
```
Or:
```
localhost
handle /api/ {
reverse_proxy upstream
}
handle {
respond 404
}
```
This is not only more verbose, but because this is such a commonly desired behavior IMHO, this simply eschews the use of the "behavior-first" style without `route` or `handle` at all.
The same problem also applies to site host matching, Caddy will respond with a 200 and an empty body for any unmatching host, when the site address includes a host in the Caddyfile. Forcing you to use the more verbose form of the Caddyfile with curly braces, eschewing the use of the shorthand without them at all:
```
localhost {
handle /api/ {
reverse_proxy upstream
}
handle {
respond 404
}
}
:80 {
respond 404
}
```
This issue causes the loss of much of the convenience the Caddyfile shorthand syntax aims to offer, unless additional constructs are added to tackle this issue in a concise way (Or the default behavior is changed, but even then, some users might want to override it).
There are two things that could be added (Both or maybe just one of them):
1. Defining a fallback route in a server when no other handler matches. (A special matcher? Shorthand Caddyfile syntax for it, like for paths?), this can also be useful to implement other kinds of configurations without resorting to `route` or `handle`.
2. Defining a default handler/behavior that takes effect if no handler or server matches at all. (Without having to add curly braces to the server perhaps? In the global config block?)
opened 09:57AM - 17 Feb 21 UTC
closed 11:04AM - 17 Feb 21 UTC
invalid
Hey, I'm not sure if this is a _bug_ per se, but it's certainly surprising behav… ior: I have a caddy v2 server with this caddyfile:
```
subdomain.example.com {
reverse_proxy /api/* http://127.0.0.1:8080
}
```
As expected, any request to `/api/*` is forwarded to my backend server on :8080. However, a request to `/something_else/` is responded with a `200 OK` and `Content-Length: 0`.
This response is very surprising to me, I would have either expected a `404 Not Found` or a `503 Service Unavailable` response, indicating that the route was not matched. `200 OK` is almost certainly not the right move here.
… and I can imagine why this could be hard to implement (handle /api*
does “handle” the request afterall), but any ideas come to mind where we can explicitly encode in the config the behavior of paths not explicitly processed?
This is just a user error. We have no plans to change the behaviour of unhandled requests.
I worked on trying to add a debug log to show something when a request went unhandled, but it was very tricky to actually implement for various reasons Add debug log if a request was not explicitly matched/handled · Issue #3445 · caddyserver/caddy · GitHub . Nearly two years later though, I could probably figure something out having more experience with the codebase.
To be clear, a handle
doesn’t necessarily “handle” a request, cause you could use a handle
and do nothing within it, which would still cause an empty 200.
gcss:
# handle_path does the same as handle, but it strips a prefix from the request before running its handlers
handle /api* {
# NOTE: This is a redundant. Consider removing the matcher as the handler does the work for you. Let's discuss after standup
reverse_proxy /api* {$SERVER}:5000
handle {
# Fallback for any otherwise unhandled requests, maybe a 404 if you want
respond "Nope!" 404
}
respond * 500 {
body "no handlers were found"
close
}
}
The middle handle
for fallback is in the wrong place here, it should be outside of the handle /api*
. Also, this config would cause all API requests to respond with a 404, because handle
has a higher directive order than reverse_proxy
.
2 Likes
system
(system)
Closed
June 2, 2022, 12:14am
3
This topic was automatically closed after 30 days. New replies are no longer allowed.