I have a Caddyfile which has default rewrite configured:
rewrite {
to {path} {path}/ /index.php?{query}
}
Now I want to redirect requests to a directory to another server if the file is not available local.
My current testing config looks like this:
# use previous behaviour if not a request to the resources directory
rewrite {
if {path} not_match ^\/resources
to {path} {path}/ /index.php?{query}
}
# extract the last part of the resources directory if the file doesnt exist
rewrite {
r ^/resources/(.*)$
to {path} /{1}
}
# finally redirect requests to /resources using the rewrite-uri
redir {
# Modify the destination and status as required
/resources https://media.mycdn.org/{rewrite-uri} 307
}
The result is, that files which are available in my local resources directory are served correctly, but non existing files don’t redirect, but return 404.
I tried a few configs, but I dont see how the rewrite/redir play together here.
Hmm. At a guess I’d say it’s because you’re actually rewriting to remove the /resources/ prefix when the file’s not found.
Actually, at a glance, I’d expect that a request for a file inside /resources/ that exists locally would actually be redirected instead of served, with that setup. You’re definitely getting 200s and the file served locally in this case?
Anyway, you can’t really use a base path that you’re expecting to rewrite away from as the base path for your redir. You’ll need to use a blanket redir (because the rewrite could go anywhere), and you can use if to check whether it was rewritten away from /resources/.
I’ve written a few of these before, but this is an example by hand and untested. A few tips for the other components, too.
rewrite {
to {path} {path}/ /?{query} # canonical reference to index
}
rewrite /resources/ { # use base path to avoid running
r ^/resources/(.*)$ # regex on every single request -
to {path} /{1} # longer base path rewrite also
} # wins, no need to exclude above
redir {
if {uri} not {rewrite_uri} # check we did rewrite the URI
if {uri} starts_with /resources/ # specifically, from /resources
/ https://media.mycdn.org/{rewrite-uri} 307
}
Many thanks!
I finally got it running with a few changes.
rewrite-uri must be changed to rewrite_uri
I needed to move the fallback rewrite right at the bottom of the config
The rewrite /resources/ { was ignored - thus I changed rewrite {
I removed the slash from /{1} since it was leading to a double slash in the redirect
rewrite { # use base path to avoid running
r ^/resources/(.*)$ # regex on every single request -
to {path} {1} # longer base path rewrite also
} # wins, no need to exclude above
redir {
if {uri} not {rewrite_uri} # check we did rewrite the URI
if {uri} starts_with /resources/ # specifically, from /resources
/ https://media.mycdn.org/{rewrite_uri} 307
}
rewrite {
to {path} {path}/ /index.php?{query}
}
The second one is a direct result of the third. When one has a longer base path, it automatically “wins” out of the two, but with identical base paths (the implicit /), ordering becomes important. I’m not sure why it would be ignored, though. Maybe /resources would’ve been a better base path than /resources/?
As for the fourth, I don’t think it’s actually the slash before {1} that’s important. It’s the slash in the middle of media.mycdn.org/{rewrite_uri}, since {rewrite_uri} comes with the prefixed slash. It all comes out in the wash, though.