Having problems adapting Caddyfile

1. The problem I’m having:

Hi, I’m trying to use caddy as a reverse proxy with direct static file serving for nodebb. They provided an example Caddyfile but I wish to adapt into JSON file
Original caddyfile

example.org {
    encode zstd gzip

    handle_path /assets/* {
        root * /path/to/nodebb
        try_files /build/public/{path} /public/{path}
        file_server
    }

    handle {
        reverse_proxy localhost:4567
    }
}

2. Error messages and/or full log output:

The adapted config is here

{
  "apps": {
    "http": {
      "servers": {
        "srv0": {
          "listen": [":443"],
          "routes": [
            {
              "match": [{ "host": ["example.com"] }],
              "handle": [
                {
                  "handler": "subroute",
                  "routes": [
                    {
                      "handle": [
                        {
                          "encodings": { "gzip": {}, "zstd": {} },
                          "handler": "encode",
                          "prefer": ["zstd", "gzip"]
                        }
                      ]
                    },
                    {
                      "group": "group2",
                      "handle": [
                        {
                          "handler": "subroute",
                          "routes": [
                            {
                              "handle": [
                                {
                                  "handler": "rewrite",
                                  "strip_path_prefix": "/assets"
                                }
                              ]
                            },
                            {
                              "handle": [
                                { "handler": "vars", "root": "/path/to/nodebb" }
                              ]
                            },
                            {
                              "handle": [
                                {
                                  "handler": "rewrite",
                                  "uri": "{http.matchers.file.relative}"
                                }
                              ],
                              "match": [
                                {
                                  "file": {
                                    "try_files": [
                                      "/build/public/{http.request.uri.path}",
                                      "/public/{http.request.uri.path}"
                                    ]
                                  }
                                }
                              ]
                            },
                            {
                              "handle": [
                                { "handler": "file_server", "hide": ["./test"] }
                              ]
                            }
                          ]
                        }
                      ],
                      "match": [{ "path": ["/assets/*"] }]
                    },
                    {
                      "group": "group2",
                      "handle": [
                        {
                          "handler": "subroute",
                          "routes": [
                            {
                              "handle": [
                                {
                                  "handler": "reverse_proxy",
                                  "upstreams": [{ "dial": "127.0.0.1:4567" }]
                                }
                              ]
                            }
                          ]
                        }
                      ]
                    }
                  ]
                }
              ],
              "terminal": true
            }
          ]
        }
      }
    }
  }
}

You see, the adapted config is obviously wrong. So I wrote it by myself but it seems not working. The static files cannot be accessed with 404 not found error.

{
  "match": [
    {
      "host": ["example.com"]
    }
  ],
  "handle": [
    {
      "handler": "subroute",
      "routes": [
        {
          "handle": [
            {
              "handler": "encode",
              "encodings": { "gzip": {}, "zstd": {} },
              "prefer": ["zstd", "gzip"],
              "minimum_length": 0
            }
          ]
        },
        {
          "match": [{ "path": ["/assets/*"] }],
          "handle": [
            {
              "handler": "subroute",
              "routes": [
                {
                  "handle": [
                    {
                      "handler": "rewrite",
                      "strip_path_prefix": "/assets"
                    }
                  ]
                },
                {
                  "match": [
                    {
                      "file": {
                        "root": "/path/to/nodebb",
                        "try_files": [
                          "/build/public/{http.request.uri.path}",
                          "/public/{http.request.uri.path}"
                        ]
                      }
                    }
                  ],
                  "handle": [
                    {
                      "handler": "rewrite",
                      "uri": "{http.matchers.file.relative}"
                    }
                  ]
                }
              ]
            }
          ]
        },
        {
          "handle": [
            {
              "handler": "reverse_proxy",
              "upstreams": [{ "dial": "127.0.0.1:4567" }]
            }
          ],
          "terminal": true
        }
      ]
    }
  ],
  "terminal": true
}

3. Caddy version:

v2.7.4 h1:J8nisjdOxnYHXlorUKXY75Gr6iBfudfoGhrJ8t7/flI=

4. How I installed and ran Caddy:

a. System environment:

Linux HOST 6.2.0-34-generic #34-Ubuntu SMP PREEMPT_DYNAMIC Mon Sep 4 13:06:55 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

b. Command:

/path/to/caddy run --environ --config /path/to/Caddyfile.json

c. Service/unit/compose file:

[Unit]
Description=Caddy
Documentation=https://caddyserver.com/docs/
After=network.target network-online.target
Requires=network-online.target

[Service]
User=caddy
ExecStart=/path/to/caddy run --environ --config /path/to/Caddyfile.json
ExecReload=/path/to/caddy reload --config /path/to/Caddyfile.json
AmbientCapabilities=CAP_NET_BIND_SERVICE

[Install]
WantedBy=multi-user.target

d. My complete Caddy config:

Well it's a bit complicated...

5. Links to relevant resources:

No. ;(

I don’t understand, in what way is it wrong? It’s adapted correctly.

"handle": [{ "handler": "vars", "root": "/path/to/nodebb" }]

I don’t think it’s right…

Why not? That’s exactly the point of the root directive.

Please explain in detail what you mean. I can’t read your mind!

Sorry sir, I didn’t read the full document

root
Sets the root path of the site, used by various matchers and directives that access the file system. If unset, the default site root is the current working directory.

**Specifically, this directive sets the {http.vars.root} placeholder.**

So
{ "handler": "vars", "root": "/path/to/nodebb" }
equals to
{ "handler": "file_server", "root": "/path/to/nodebb"}
My problem is, the static files cannot served properly, caddy always returns 404 error
I’m checking to see if it’s caused by something else.

Are you sure that root path is actually correct? Did you literally use that path? Is that actually where your files are stored? You’re meant to replace that with your actual path to your nodebb files.

Not exactly. Vars sets it so that any handler which needs the root path has access to it without each handler/matcher needing the root to be configured explicitly. This is useful for the file matcher as well (from try_files).

yes I’m sure I replaced that with the real path. perhaps something blocked caddy from reading these files?

OK I fully understand that now. Thank you very much

Possibly. What’s the real path? Caddy is running as the caddy user, so the files need to be accessible by that user.

/var/lib/nodebb. So maybe I should go back and check owner and permissions?

Yes, make sure that directory has permissions for the caddy user to read it. Depends what user/group it has.

I checked the permissions and everything is OK.
And actually the config may be the problem…
I replaced {"handle":[{"handler":"file_server","root":"/path/to/nodebb"}]} with

{"handle":[{"handler":"vars","root":"/path/to/nodebb"}]},
{"handle": [{ "handler": "file_server"}]}

then the page functions normally! Theoretically they’re doing the same thing (of course as you mentioned above there are still some differences), but the result is very weird. Sir do you have any ideas?

@francislavoie hello sir? If you don’t think this is worth discussing, I’ll mark your answer as solution, since my site is working again

I’m not sure what to add. Like I said, using vars defines root for all handlers/matchers that run after it. If you specify root on one handler/matcher that needs it but not the others, then it makes sense that things wouldn’t work as expected. Did you use the file matcher at all? You only shared a small part of your config so I can’t be sure you didn’t.

What do you mean by this? This is the only place in the entire configuration file where the file matcher is used.
The other places define root for file_server by setting "root": "/path/to/somewhere", not the variable.
:smiling_face_with_tear:

You were using try_files here which is a shortcut directive which combines the file matcher with a rewrite handler.

I understood that. Thanks!

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