Relationship between rewrite, redir, respond and try_files?

Hi! I’m trying to bridge some gaps in my own understanding on several Caddy directives that seem to me to be somehow connected.

redir or rewrite?

Under the section Trailing Slashes in the documentation, there’s mention of internal and external enforcement.

Is this a choice thing? In what situations would I use one method over the other?

rewrite or respond?

In the thread Help to migrate Caddyfile V1 to V2 for Nextcloud, there seemed to be a magical transformation from using rewrite to using respond.

When is one method preferable over the other, or are they mutually exclusive?


Following on from the same thread above, in @dougy’s final solution post 30, a named matcher @forbidden is used to specify paths/files that the respond directive acts on.

Why isn’t it sufficient to rely solely on Unix file permissions to secure the specified files/paths? From a webserver perspective, why is this considered a good security measure as well? How might the files/paths be chosen for a named matcher?

try_files and rewrite

I’ve read the documentation on try_files over and over, but, it’s still all a bit abstract to me and I don’t have warm, fuzzy feelings about it, and the rewrite directive. I don’t recall using either to date in any Caddyfiles I’ve constructed. I got that the expanded form of try_files was significant enough for a directive to be implemented for it, but apart from that, any tips on helping me better understand in what context I might use rewrite and try_files would be well received.

A redirect is like HTTP->HTTPS (tell the browser nah we don’t do HTTP, please use HTTPS), or like mapping some old paths to new ones if you’ve made a site migration (like maybe you had /about-us before but you changed it to /about), and you want the browser to make that change so the users see it. It can also serve a permanent redirect to tell search engines “this is the new page forever, this path is dead now”.

A rewrite is for anything that’s essentially required for your application to work, or just to make the URLs look cleaner for the user; for example like stripping off the .php at the end of URLs, or anything to make it easier for your app to handle the request like rewriting everything to index.php, or other kinds of transformations. The possibilities are endless with rewrites, really.

Well respond will actually serve a response right then and there, but a rewrite will only change the URI before letting another handler deal with the request and make a response. These don’t really have any usage overlap, they both serve a different role.

Using proper file permissions is recommended, and I’d personally avoid having to need a block like that to block certain paths, but some applications like WordPress and NextCloud seem to have some poor defaults at times so some users prefer to explicitly deny certain things.

If you use php_fastcgi, then you’re using a try_files (see the expanded form in the docs).

Basically it’s just a rewrite wrapped with a file matcher; basically only performs a rewrite to the given pattern if the pattern maps to a file that exists on the filesystem.

A good example is how php_fastcgi uses it, so first it checks if {path} exists as a file, i.e. if the request is exactly to a static file like some CSS or JS file, then it rewrites the path to that – which is effectively a no-op, but it prevents the next part from happening – otherwise it looks for {path}/index.php, i.e. if the request is to a directory that exists on disk which contains an index, then rewrites the path to that if so, so that the reverse_proxy can send the request over fastcgi for PHP to handle – and finally if not either of those, it’ll fall back to index.php for everything else (if an index.php exists in the root) so that the application can do its own routing. The original path is preserved in a PATH_INFO variable which is passed via fastcgi so the PHP app can use that to make routing decisions.

Hope this helped!


I think I understand. Can you please check my logic through the following example?

Say I have a link to a product catalogue on a client site and to get to it, I would normally have to reference the address If the client wanted to print some information cards to hand out to customers directing them to the product catalogue, it would be better if the printed link on the information card said something like I could then use rewrite so that the customer never actually sees the obscure reference to the product catalogue when the printed link is entered online. On the other hand, if it didn’t bother me that the address got changed to the obscure reference on the address bar when the printed link was entered, I could use redir to achieve the same result.

Thanks for the clarification on all the other points as well. They’re less of a mystery to me now. As always, I’m grateful for your assistance.

Yeah, that’s right.

Another example is “URL shortening” services, those are essentially just “redirects as a service”. For example, Twitter runs their own on their domain, which I’m sure you’ve run into before. Hover on any link in a tweet in your browser and you’ll see that the URL is actually When you visit that link, their servers count the click then serves a response with a Location header to trigger the redirect. You’ve probably seen others like and, etc.

1 Like

Until now, I never understood the mechanism behind this! So, because the path gets mapped to a new one, and the address on the address bar ultimately changes, redir is the magic behind URL shortening?

Yeah. It’s not really magic though, it’s just the Location header in the response that tells HTTP clients “hey, look over there” :sweat_smile:

If you caddy adapt a Caddyfile with redir in it, you’ll see that it’s just a static_response with the Location header set:




  "apps": {
    "http": {
      "servers": {
        "srv0": {
          "listen": [
          "routes": [
              "handle": [
                  "handler": "static_response",
                  "headers": {
                    "Location": [
                  "status_code": 302

You could make your own little URL shortener by using the map directive in your Caddyfile: {

	map {path} {redirect-uri} {
        	/old-about-page /about

	@hasRedir expression `{redirect-uri} != ""`
	redir @hasRedir {redirect-uri}

	respond "No redirect!"

To a layperson like myself, the stuff that you guys do is ALL magic to me!

That is so cool! :sunglasses: I’ve found a use for the map directive now.

1 Like

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