elsgaard
(Thomas Elsgaard)
April 24, 2021, 1:44pm
1
1. Caddy version (caddy version
):
v2.3.0 h1:fnrqJLa3G5vfxcxmOH/+kJOcunPLhSBnjgIvjXV/QTA=
2. How I run Caddy:
systemd
a. System environment:
Centos8 + systemd
b. Command:
N/A
c. Service/unit/compose file:
N/A
d. My complete Caddyfile or JSON config:
test.dreamwalkers.dk {
basicauth {
foo JDJhJDE0JEI4TkVYZW5hcElKZEFMVzZtZ1p6TmV6RlFRaUY0NnRWZkUxbTB1MU5GcFBaRU91SEtkbEdD
}
reverse_proxy {
to 185.52.1.16:8080
to 81.4.109.218:8080
health_path /health
health_interval 1s
health_body "(OK)"
}
handle_errors {
@maintenance expression {http.error.status_code} == 502
rewrite @maintenance /images/502.html
reverse_proxy https://statictest.dreamwalkers.dk {
header_up Host statictest.dreamwalkers.dk
}
}
rewrite * /dreamwalkers/site{uri}
}
3. The problem Iām having:
When using āhandle_errorsā, i have difficulties also using basicauth. I belive the problem is that http 401 unauthorized is catched by the handle_errors, and never triggering the basicauth directive. Any suggestions to how i should be able to use both basicauth while also handle 502 errors ?
4. Error messages and/or full log output:
Login dialog never shown.
5. What I already tried:
I have tried to move the basicauth around, but that makes no difference
6. Links to relevant resources:
Well, it does trigger basicauth, but basicauth emits the 401 error which is then caught by handle_errors
.
Right now, youāre passing all errors through a reverse_proxy
. If you meant to only do that for 502s, then you should put all that inside a handle
:
handle_errors {
@maintenance expression {http.error.status_code} == 502
handle @maintenance {
rewrite * /images/502.html
reverse_proxy https://statictest.dreamwalkers.dk {
header_up Host statictest.dreamwalkers.dk
}
}
}
elsgaard
(Thomas Elsgaard)
April 24, 2021, 2:51pm
3
Yes, the handle_errors looks better with the handle, it is of course only the 502 i need to handle but the reverse_proxy, but it do not change that the basichauth is not working. I simply just get and blank page. If i remove the handle_errors, basicauth is working correctly
Ā“Ā“Ā“
test.dreamwalkers.dk {
basicauth {
foo JDJhJDE0JEI4TkVYZW5hcElKZEFMVzZtZ1p6TmV6RlFRaUY0NnRWZkUxbTB1MU5GcFBaRU91SEtkbEdD
}
reverse_proxy {
to 185.52.1.16:8080
to 81.4.109.218:8080
health_path /health
health_interval 1s
health_body "(OK)"
}
handle_errors {
@maintenance expression {http.error.status_code} == 502
handle @maintenance {
rewrite * /images/502.html
reverse_proxy https://statictest.dreamwalkers.dk {
header_up Host statictest.dreamwalkers.dk
}
}
}
rewrite * /dreamwalkers/site{uri}
}
Ā“Ā“Ā“
I think youāll also need to add this after the handle
block so that the error HTTP status is preserved:
respond {http.error.status_text} {http.error.status_code}
Actually, now Iām really confused. The behaviour youāre seeing was fixed over a year ago, well before v2.0.0 stable:
caddyserver:v2
ā roblabla:default-error-handler
opened 07:19PM - 20 Feb 20 UTC
Currently, when an error chain is defined, the default error handler is bypassedā¦ entirely - even if the error chain doesn't handle every error. This may result in pages returning a blank 200 OK page instead of the error status defined by the error.
For instance, it's possible for an error chain to match on the error status code and only handle a certain subtype of errors (like 403s). In this case, we'd want any other errors to still go through the default handler and return an empty page with the status code.
This PR changes the "suffix handler" passed to errorChain.Compile toset the status code of the response to the error status code.
Fixes #3053
I tried replicating locally and I canāt get it to happen. Iām using a config like this:
{
admin off
debug
}
:8883 {
basicauth {
foo JDJhJDE0JDd1Li5HMWR5bTBNdUV1ek1QdVlrb09JQUh4V243OVB5QXNkL0NESXdmUzBqYjV0UFZ6VHJT
}
handle_errors {
@nope expression `{http.error.status_code} == 502`
handle @nope {
respond {http.error.status_code}
}
}
respond "Hello World"
}
Running this, I make a request to http://localhost:8883
in my browser. I get the basicauth prompt. If I give a bad user/pass (say bar
/bar
) the basicauth prompt clears and reloads (Caddy responds with a 401
). If I then use the correct credentials foo
/foo
, then I get a HTTP 200 response with Hello World
displayed.
So something funky must be going on. Can you try the above and confirm that it works for you?
1 Like
elsgaard
(Thomas Elsgaard)
April 24, 2021, 6:13pm
7
With your config, i get the same result as you describe, getting 401ā¦ BUT, now try to change :8883 to x.x.x.x:8883 or a domain name:8883 then it starts working differently, not giving back 401 but 200
Ā“Ā“Ā“
{
admin off
debug
}
81.4.109.165:8883 {
basicauth {
foo JDJhJDE0JDd1Li5HMWR5bTBNdUV1ek1QdVlrb09JQUh4V243OVB5QXNkL0NESXdmUzBqYjV0UFZ6VHJT
}
handle_errors {
@nope expression `{http.error.status_code} == 502`
handle @nope {
respond {http.error.status_code}
}
}
respond "Hello World"
}
Ā“Ā“Ā“
With the above i get 200, and not 401 ā¦ As soon as i change 81.4.109.165:8883 to :8883 i get the correct 401 ā¦ that is very funky
1 Like
elsgaard
(Thomas Elsgaard)
April 24, 2021, 6:17pm
8
Actually you can just change it to: 127.0.0.1:80 and then do a curl -vvv http://127.0.0.1/
Ā“Ā“Ā“
Trying 127.0.0.1ā¦
TCP_NODELAY set
Connected to 127.0.0.1 (127.0.0.1) port 80 (#0 )
GET / HTTP/1.1
Host: 127.0.0.1
User-Agent: curl/7.61.1
Accept: /
< HTTP/1.1 200 OK
< Server: Caddy
< Www-Authenticate: Basic realm=ārestrictedā
< Date: Sat, 24 Apr 2021 18:17:07 GMT
< Content-Length: 0
<
Connection #0 to host 127.0.0.1 left intact
Ā“Ā“Ā“
1 Like
Oh wow, thatās fascinating. I see whatās going on now. Adapting the configs to JSON with caddy adapt --pretty
makes it obvious. Thanks for noticing that.
So when you have a host matcher, the error routes also inherit the host matcher, on a subroute that wraps the other routes. This subroute has terminal
marked on it which means that once matched, no handlers are executed past that point. The implicit error handler from the above PR isnāt actually run because itās appended after the subroute, which is ātoo lateā.
Iāll look to make a patch to fix this, I think we can append the implicit error handler at the end of top-level subroutes maybe.
1 Like
elsgaard
(Thomas Elsgaard)
April 24, 2021, 6:23pm
10
Caddy is not only a pleasure to work with. The community behind it is what makes it really really great!! Thanks for your effort and kind helpā¦
3 Likes
Wrote a PR to fix it. Seems to work fine but itās pretty awkward.
caddyserver:master
ā francislavoie:fix-error-fallback
opened 10:52PM - 24 Apr 21 UTC
This is mainly a problem with the default behaviour of the Caddyfile's `handle_eā¦ rrors` routes, ~~but it's kinda tricky to solve well. I went with an approach that involves a smidge of magic which might not really be desirable.~~
See https://caddy.community/t/problem-with-basicauth-handle-errors/12243/9 for context.
So we do already have a default fallback for error routes, i.e. `errorEmptyHandler` in `caddyhttp.go` which is always configured as the last handler in the chain (implicitly, not visible in the config).
The problem is that when ~~subroutes~~ routes come into play with `"terminal": true`, then this fallback handler will never be reached. This is the case when the Caddyfile generates a config which has a host matcher from a site block (which is most of the time) when the user configured `handle_errors` to handle specific errors (such as 502s or 404s to serve HTML pages for those, etc). If other errors, like `basicauth`'s 401s are emitted in that case, then the result is that the default of HTTP status 200 will be served instead of the 401, which breaks `basicauth` completely.
~~The fix I went with is to make the Caddyfile adapter append special `error` handlers inside of the `handle_errors` subroutes which throw error `-1`, which `server.go` then picks up, and seeing `-1` responds with the original error code of `401` instead. The `-1` thing is the aforementioned magic.~~
~~At first, I had this implemented with `static_response` setting the StatusCode to `{http.error.status_code}`, but it didn't feel right to use a placeholder because it's inherently slightly less efficient, and it wasn't 100% correct because non-handler errors wouldn't be handled as 500s properly I think (because if it's not a `HandlerError`, then `http.error.status_code` doesn't exist, so it would maybe try to write an the placeholder replacement result of an empty string as `0` for the status code).~~
Edit: The fix I went with in the end (after realizing some mistaken assumptions above) is to just make the routes fall back to `errorEmptyHandler` instead of the non-error empty handler, if `Terminal` is true, making the routes error-aware. Ultimately this was probably just an oversight when `errors` was implemented at some point in the early betas of v2.
I realized thereās a simpler solution than what I originally implemented, and I updated my PR. Feel free to try it out to confirm yourself.
You can grab the build from the CI artifacts here: caddyhttp: Fix via `routes.go` Ā· caddyserver/caddy@a735af4 Ā· GitHub
1 Like
system
(system)
Closed
May 24, 2021, 1:44pm
13
This topic was automatically closed after 30 days. New replies are no longer allowed.