caddy: Bug: Caddy v2.4.2 with specified rewrite rules causes unexpected 308 redirection
Phenomenon: Open web page on Firefox and Chrome, and they both say “the page cannot redirect correctly”. After downgrading Caddy to v2.4.1, everything becomes OK.
Caddy configuation (Caddyfile):
${domain}
root * /path/to/html
encode zstd gzip
tls /path/to/cert.pem /path/to/key.pem {
protocols tls1.3
alpn h2 http/1.1
curves x25519
}
header Strict-Transport-Security max-age=31536000
reverse_proxy /path/to/proxy 127.0.0.1:${port} {
transport http {
versions h2c
}
}
@common not path /path/to/proxy
handle @common {
rewrite * /path/to/rewrite.html
}
file_server
In Caddy’s log, there are many lines like the one below:
{"level":"error","ts":1623667844.8768942,"logger":"http.handlers.reverse_proxy","msg":"aborting with incomplete response","error":"context canceled"}
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 5
- Comments: 19 (15 by maintainers)
Commits related to this issue
- Revert "fileserver: Redirect within the original URL (#4179)" This reverts commit f9b54454a19e2b070159ce8d2af76d819658244e. /cc @diamondburned (see #4205) — committed to caddyserver/caddy by mholt 3 years ago
- fileserver: Clarify docs about canonicalization Related to https://github.com/caddyserver/caddy/issues/4205. — committed to caddyserver/caddy by mholt 3 years ago
- Test basic redirect and Test case 1 from https://github.com/caddyserver/caddy/issues/4205#issuecomment-863352037 — committed to jaygooby/caddy by jaygooby a year ago
- Test case 2 from https://github.com/caddyserver/caddy/issues/4205#issuecomment-863352037 — committed to jaygooby/caddy by jaygooby a year ago
I think I came up with a solution that works in all 3 main cases I’ve tested: only redirect if the base element of the path (the filename) is the same in both the original request and the rewritten request. In other words, do not redirect if the filename in the path was changed/rewritten internally. (The logic being, if the admin wanted to rewrite to the canonical path, they would have.)
This seems to prevent the file server from stepping on the toes of intentional rewrites, while still enforcing path canonicalization when, for example, only the prefix of the path is changed (as in
handle_path).For all the test cases below, I found it helpful to turn on debug mode:
Test case 1
This config (used on my Expert Caddy website) used to cause a redirect loop:
(This config could actually be better, probably by specifying
template.htmlas an index file in thefile_server, but 🤷♂️)Test case 2
This config is from the Caddy website. Without my proposed change, it would not render pages in the /docs/ section of the site:
With my proposed change, the docs pages still function as expected (canonicalization redirects are NOT dispatched, since I explicitly rewrote the filename to be what I want it to be).
Test case 3
A simple file server with directory listings, that does not have an index file, where we use
handle_pathto serve therootfolder within the path of/foo/*:With my proposed change, this continues to issue canonicalization redirects because only the path prefix is rewritten, not the filename; and the redirects correctly preserve the
/foo/prefix and the relative hrefs continue to work because of the redirects.I’m going to commit and push this soon, then probably release v2.4.3 later today.
I am experiencing the same issue and downgrading to
2.4.1worked for me. Adding repro details:1. Environment
1a. Operating system and version
1b. Caddy version (run
caddy versionor paste commit SHA)2. Description
2a. What happens (briefly explain what is wrong)
Using file_server to serve the output of a webpack build, where we need all paths not belonging to a static file to rewrite to an index.html outside the directory of the Caddyfile. A GET to Caddy at
http://localhost:3030responds with a 308 Redirect with the headerLocation: /. This causes a redirect loop for any request to Caddy.2b. Why it’s a bug (if it’s not obvious)
On Caddy 2.4.1 this redirect would not happen and the expected html file is served.
2c. Log output
2d. Workaround(s)
Downgrade to Caddy 2.4.1
3. Tutorial (minimal steps to reproduce the bug)
The bug was first encountered in a CI environment where our repo is cloned to
/root, so add a/root/index.htmlthat we want to serve with Caddy.In a different directory, add minimum Caddyfile:
caddy runcurl localhost:3030=> 308 Redirect to /The trailing slash creates a path matcher which only matches exactly
/and nothing else.I agree this is confusing behaviour, and I plan to deprecate path matchers in site addresses soon, because it’s clearer to use a
handleblock explicitly instead, if you’re actually intending to use a path matcher.Your issue is not related to the one that was originally reported in this issue. It’s a different problem altogether.
For the record, I tried using a solution that Francis suggested where we don’t canonicalize (redirect) if the rewritten path is explicitly an index file. This worked for one of the use cases I tried, but not the Caddy website for example (the docs part of the site), in part due to how templates use the rewritten path (it expects the index page to have “index” in the rewritten path).
I think for now the best thing to do is keep the revert for v2.4.3. Yes, it can be problematic for URL canonicalization when used inside
handle_path, but we’ll need a solution that doesn’t break so many sites in such complex ways.Point taken. I agree the redirect is not necessarily wrong, but it is not obvious. I wouldn’t expect that being more explicit with
/index.htmlwould cause an issue. (edit: while the redirect is not wrong, I also don’t think /index.html is wrong either?)Perhaps worth noting, my solution was guided by this community forum and your comment where the recommended solution is
try_files {path} /index.html. This is the top search result for “caddy serve single page app”.Thanks for the repro instructions. That exhibits it for me. The commit I linked earlier is definitely a regression, because that shouldn’t yield a redirect loop (edit: actually, maybe it should, see below).
(I still want to know @inoblue’s exact use case & config though, since how to solve both problems without a regression is still an open question.)
Are there any debug logs available with the broken commit?
Edit: I think it has to do with the changes in
modules/caddyhttp/fileserver/staticfiles.go. I wasn’t too sure what the changes there had to do with my issue, and I only experienced an issue withmodules/caddyhttp/fileserver/browse.go, but the original fix was forstaticfiles.go.I think I can make a commit with just the fix for
browse.goand see how that goes.The issue was solved after building from source.
Thanks for your help.