Redirect /file/ to /file (strip trailing slash)

If I have a page at example.com/about.html I would like to also make it accessible as example.com/about/ but with a redirect (because in the past, it may have used a slash, so there could still be people linking to the version with the trailing slash).

What I have so far is:

@trailing_slash {
    path_regexp dir (.+)/$
    not file {path}/index.html
}
redir @trailing_slash {http.regexp.dir.1}?{query}

Here we check if we have a trailing slash, and furthermore, we check that there is not an index.html file in the directory: I do not like this check, because this check must mirror any other configuration about index pages, e.g. there could be an index.php, index.rss, or similar.

What I really want is to check that {path} is a non-existing directory. But it seems like the file matcher is specifically checking that {path} exists and is a file.

Any suggestions?

Secondly, any non-existing path with a trailing slash will be matched and redirected, so example.com/non-existing/ will produce a redirect to example.com/non-existing (which will then return 404).

What I would like to do is include a check for the file we redirect to, for example something like this:

@trailing_slash {
    path_regexp dir (.+)/$
    file {http.regexp.dir.1}.html # <-- Does not work!
}
redir @trailing_slash {http.regexp.dir.1}?{query}

This uses the capture from the path_regexp matcher to strip the trailing path component from {path}, but it appears that these captures can only be accessed from the directive that uses the matcher.

Is there any way to do a file test on the “parent” of {path}? Or another way to achieve the redirect?

Hello @duff. Using the redir with a handle or handle_path should achieve what you want.

Also take a look at

If I understand you right you would need something like this

domain.com {
        root * /path/to/site
        file_server {
              index index.html                
         }
         redir /about/ /about.html
         handle_path /about/ {
                 root * /path/to/site
                 file_server {
                   index about.html
                 }
        }
}

That should allow you to access about.html via domain.com/about.html and also domain.com/about/.

Not sure if it’s the most efficient way but it works. Caddy should spit a 404 back at you if you try to navigate to a non-existent site.

The handle_path directive is for Caddy v2.1 only. If you haven’t upgraded then you would need to use handle and use the uri directive linked above to strip the prefix.

I hope that helps.

1 Like

Thanks, but no, I wanted a general rule that redirects any non-existing path with a trailing slash to the path without the slash, assuming that there exist a html file at that location.

If you look at what I posted, I already managed to create the redirect for all non-existing paths, but it would redirect even if there wasn’t an html file where it redirected to, which is what I wanted to improve (to immediately return 404, instead of 308 followed by 404).

ok gotcha. Misunderstood the question.

Unfortunately, the order in which matchers are executed is not guaranteed, so you can’t use the result of a regexp in another matcher in the same block. What you can do instead though is chain them using handle. Something like this:

@pathWithSlash path_regexp dir (.+)/$
handle @pathWithSlash {
	@htmlFileExists file {re.dir.1}.html
	redir @htmlFileExists {re.dir.1}?{query}
}

As for your first question, I don’t think there’s any way to check for the existence of directories yet. What you could do is check for all the possible index files that could be served, like:

not file {path}/index.html {path}/index.php {path}/index.rss

This topic was automatically closed after 30 days. New replies are no longer allowed.