V2: redirect /path to /path/index.php with assets

I use Caddy v2 on my website and I have a link to a webapp that is located in a subfolder in my webpath (webroot/5g).

The index file in that subdirectory is a index.php file, but when I navigate to 5G Throughput Calculator, I get only the index.php to load correctly, but not the assets with it. When I visit 5G Throughput Calculator, it loads the assets just fine.

How do I need to setup my Caddyfile v2 to achieve this?

Caddyfile:

{
        "apps": {
                "http": {
                        "servers": {
                                "srv0": {
                                        "listen": [
                                                ":443"
                                        ],
                                        "routes": [
                                                {
                                                        "match": [
                                                                {
                                                                        "host": [
                                                                                "hnrk.io",
                                                                                "www.hnrk.io"
                                                                        ]
                                                                }
                                                        ],
                                                        "handle": [
                                                                {
                                                                        "handler": "subroute",
                                                                        "routes": [
                                                                                {
                                                                                        "handle": [
                                                                                                {
                                                                                                        "handler": "vars",
                                                                                                        "root": "/etc/caddy/html"
                                                                                                },
                                                                                                {
                                                                                                        "handler": "subroute",
                                                                                                        "routes": [
                                                                                                                {
                                                                                                                        "handle": [
                                                                                                                                {
                                                                                                                                        "encodings": {
                                                                                                                                                "brotli": {},
                                                                                                                                                "gzip": {},
                                                                                                                                                "zstd": {}
                                                                                                                                        },
                                                                                                                                        "handler": "encode"
                                                                                                                                }
                                                                                                                        ]
                                                                                                                },
                                                                                                                {
                                                                                                                        "handle": [
                                                                                                                                {
                                                                                                                                        "handler": "rewrite",
                                                                                                                                        "rehandle": true,
                                                                                                                                        "uri": "{http.matchers.file.relative}{http.request.uri.query_string}"
                                                                                                                                }
                                                                                                                        ],
                                                                                                                        "match": [
                                                                                                                                {
                                                                                                                                        "file": {
                                                                                                                                                "try_files": [
                                                                                                                                                        "{http.request.uri.path}",
                                                                                                                                                        "{http.request.uri.path}/index.php"
                                                                                                                                                ]
                                                                                                                                        }
                                                                                                                                }
                                                                                                                        ]
                                                                                                                },
                                                                                                                {
                                                                                                                        "handle": [
                                                                                                                                {
                                                                                                                                        "handler": "reverse_proxy",
                                                                                                                                        "transport": {
                                                                                                                                                "protocol": "fastcgi",
                                                                                                                                                "split_path": ".php"
                                                                                                                                        },
                                                                                                                                        "upstreams": [
                                                                                                                                                {
                                                                                                                                                        "dial": "unix//run/php/php7.3-fpm.sock"
                                                                                                                                                }
                                                                                                                                        ]
                                                                                                                                }
                                                                                                                        ],
                                                                                                                        "match": [
                                                                                                                                {
                                                                                                                                        "path": [
                                                                                                                                                "*.php"
                                                                                                                                        ]
                                                                                                                                }
                                                                                                                        ]
                                                                                                                },
                                                                                                                {
                                                                                                                        "handle": [
                                                                                                                                {
                                                                                                                                        "handler": "file_server",
                                                                                                                                        "hide": [
                                                                                                                                                "Caddyfile"
                                                                                                                                        ]
                                                                                                                                }
                                                                                                                        ]
                                                                                                                }
                                                                                                        ]
                                                                                                }
                                                                                        ]
                                                                                }
                                                                        ]
                                                                }
                                                        ]
                                                }
                                        ],
                                        "experimental_http3": true
                                }
                        }
                },
                "tls": {
                        "certificates": {
                                "load_files": [
                                        {
                                                "certificate": "/etc/caddy/hnrk.io.crt",
                                                "key": "/etc/caddy/hnrk.io.key"
                                        }
                                ]
                        },
                        "automation": {},
                        "session_tickets": {}
                }
        }
}

Thanks!

What are the href and src values on that page like?

The elements are:

<img src="img/4g.webp" class="card-img-top" alt=""> <a href="/5g" target="_blank"> <div class="mask rgba-white-slight"></div> </a>

I hope this helps you!

Yeah, it does, thanks. Because those are relative paths, the browser is making requests relative to the URI /5g which, because it doesn’t end in a forward slash, is treated as a file not a directory. So you have to redirect page loads at /5g to /5g/, but the static file server should do this for you automatically. Unless it’s not getting to the file server. You said that folder is PHP files? If so, then we’ll need to redirect /5g to /5g/ in the case of index.php files. What did your previous nginx config look like?

Yes, that is exactly the case. I don’t have an equivalent nginx config available because back then I didn’t have a php webapp, that hat an index.php in the folder, but rather an index.html, with further files in the folder being php.

Do you have an idea on how to rewrite /path to /path/index.php (maybe even elegantly without showing index.php in the uri?) just like the file_server does with index html files?

I still don’t have a super good hang of writing v2 JSON configs, so I’ll let you do it, but I think what you want to do is this:

Add another route before the rewrite, where you match against the request path being a directory containing index.php and if so you handle it as a static_response with a 301 redirect Home · caddyserver/caddy Wiki · GitHub.

2 Likes

Thank you for this interesting workaround. I’ve tried to integrate this into my Caddyfile v2, but I couldn’t get it to work exactly how I want and do not know how to convert this to easy Caddyfile syntax.

I’m no programmer really, but in Caddy v1 just specifying a relative path without a trailing slash at the end did work, might be that v1 did rewrite the request internally with a trailing slash at the end or it tested first for index files in that location.

https://github.com/caddyserver/caddy/blob/master/caddyhttp/fastcgi/fastcgi.go#L89-L105 Maybe this is why it works on v1? Something similar in v2 would be awesome, or so to say: Specifying the fastcgi directive in Caddyfile syntax should be enough for Caddy to try a locations index files and split with .php at the end.

My current Caddyfile looks like this:

{
        "apps": {
                "http": {
                        "servers": {
                                "srv0": {
                                        "listen": [
                                                ":443"
                                        ],
                                        "routes": [
                                                {
                                                        "match": [
                                                                {
                                                                        "host": [
                                                                                "hnrk.io",
                                                                                "www.hnrk.io"
                                                                        ]
                                                                }
                                                        ],
                                                        "handle": [
                                                                {
                                                                        "handler": "subroute",
                                                                        "routes": [
                                                                                {
                                                                                        "handle": [
                                                                                                {
                                                                                                        "handler": "vars",
                                                                                                        "root": "/etc/caddy/html"
                                                                                                },
                                                                                                {
                                                                                                        "handler": "subroute",
                                                                                                        "routes": [
                                                                                                                {
                                                                                                                        "handle": [
                                                                                                                                {
                                                                                                                                        "encodings": {
                                                                                                                                                "brotli": {},
                                                                                                                                                "zstd": {}
                                                                                                                                        },
                                                                                                                                        "handler": "encode"
                                                                                                                                }
                                                                                                                        ]
                                                                                                                },
                                                                                                                {
                                                                                                                        "handle": [
                                                                                                                                {
                                                                                                                                        "handler": "rewrite",
                                                                                                                                        "uri": "{http.matchers.file.relative}{http.request.uri.query_string}"
                                                                                                                                }
                                                                                                                        ],
                                                                                                                        "match": [
                                                                                                                                {
                                                                                                                                        "file": {
                                                                                                                                                "try_files": [
                                                                                                                                                        "{http.request.uri.path}.html",
                                                                                                                                                        "{http.request.uri.path}.php",
                                                                                                                                                        "{http.request.uri.path}/index.php",
                                                                                                                                                        "{http.request.uri.path}"
                                                                                                                                                ]
                                                                                                                                        }
                                                                                                                                }
                                                                                                                        ]
                                                                                                                },
                                                                                                                {
                                                                                                                        "handle": [
                                                                                                                                {
                                                                                                                                        "handler": "rewrite",
                                                                                                                                        "rehandle": true,
                                                                                                                                        "uri": "{http.matchers.file.relative}{http.request.uri.query_string}"
                                                                                                                                }
                                                                                                                        ],
                                                                                                                        "match": [
                                                                                                                                {
                                                                                                                                        "file": {
                                                                                                                                                "try_files": [
                                                                                                                                                        "{http.request.uri.path}",
                                                                                                                                                        "{http.request.uri.path}/index.php",
                                                                                                                                                        "index.php"
                                                                                                                                                ]
                                                                                                                                        }
                                                                                                                                }
                                                                                                                        ]
                                                                                                                },
                                                                                                                {
                                                                                                                        "handle": [
                                                                                                                                {
                                                                                                                                        "handler": "reverse_proxy",
                                                                                                                                        "transport": {
                                                                                                                                                "protocol": "fastcgi",
                                                                                                                                                "split_path": ".php"
                                                                                                                                        },
                                                                                                                                        "upstreams": [
                                                                                                                                                {
                                                                                                                                                        "dial": "unix//run/php/php7.3-fpm.sock"
                                                                                                                                                }
                                                                                                                                        ]
                                                                                                                                }
                                                                                                                        ],
                                                                                                                        "match": [
                                                                                                                                {
                                                                                                                                        "path": [
                                                                                                                                                "*.php"
                                                                                                                                        ]
                                                                                                                                }
                                                                                                                        ]
                                                                                                                },
                                                                                                                {
                                                                                                                        "handle": [
                                                                                                                                {
                                                                                                                                        "handler": "file_server",
                                                                                                                                        "hide": [
                                                                                                                                                "Caddyfile"
                                                                                                                                        ],
                                                                                                                                        "index_names": [
                                                                                                                                                "index.php",
                                                                                                                                                "index.html",
                                                                                                                                                "index.htm"
                                                                                                                                        ]
                                                                                                                                }
                                                                                                                        ]
                                                                                                                }
                                                                                                        ]
                                                                                                }
                                                                                        ]
                                                                                }
                                                                        ]
                                                                }
                                                        ]
                                                }
                                        ],
                                        "experimental_http3": true
                                }
                        }
                },
                "tls": {
                        "certificates": {
                                "load_files": [
                                        {
                                                "certificate": "/etc/caddy/hnrk.io.crt",
                                                "key": "/etc/caddy/hnrk.io.key"
                                        }
                                ]
                        },
                        "automation": {},
                        "session_tickets": {}
                }
        }
}

Didn’t v1 just trigger a redirect to add the /? I think it does that because it falls through file server handler which does the redirect, but in this case because of the rewrite the directory case gets caught by fastcgi which makes the redirect not happen, hence why I suggested to explicitly do the redirect beforehand.

One thing to note if you look at https://github.com/caddyserver/caddy/blob/v2/caddyconfig/httpcaddyfile/directives.go, the default ordering of directives in the Caddyfile have redir and static_response after rewrite, so if you try to do a redirect before a rewrite, then it won’t work in the Caddyfile unless you set the handler_order to work differently. See here for an example where I did this.

Anyways if you read the http.matchers.file docs Home · caddyserver/caddy Wiki · GitHub you’ll read that if you specify path/to/dir/, i.e. with trailing / then it’ll only match a directory. So my idea is that you would match against "{http.request.uri.path}/" and if so do a redirect to "{http.request.uri.path}/". Not sure if that would work though. Don’t know what happens if there’s already a / at the end of the path and so on.

The other option would be to try and make the rewrite/fastcgi not match directories at all and let it fall through to file_server, not sure if that’s feasible though. Maybe by changing "{http.request.uri.path}/index.php" to "{http.request.uri.path}index.php"? Just a crapshoot at this point.

1 Like

Thank you Francis. I fiddled with the Caddyfile and this is what I got now.

Caddyfile syntax:

{
    experimental_http3
}
hnrk.io, www.hnrk.io
root * /etc/caddy/html
tls /etc/caddy/hnrk.io.crt /etc/caddy/hnrk.io.key
encode brotli zstd gzip
php_fastcgi unix//run/php/php7.3-fpm.sock
redir {path} {path}/
try_files {path}.html {path} {path}/
file_server

Caddyfile:

{
        "apps": {
                "http": {
                        "servers": {
                                "srv0": {
                                        "listen": [
                                                ":443"
                                        ],
                                        "routes": [
                                                {
                                                        "match": [
                                                                {
                                                                        "host": [
                                                                                "hnrk.io",
                                                                                "www.hnrk.io"
                                                                        ]
                                                                }
                                                        ],
                                                        "handle": [
                                                                {
                                                                        "handler": "subroute",
                                                                        "routes": [
                                                                                {
                                                                                        "handle": [
                                                                                                {
                                                                                                        "handler": "vars",
                                                                                                        "root": "/etc/caddy/html"
                                                                                                },
                                                                                                {
                                                                                                        "handler": "subroute",
                                                                                                        "routes": [
                                                                                                                {
                                                                                                                        "handle": [
                                                                                                                                {
                                                                                                                                        "handler": "rewrite",
                                                                                                                                        "uri": "{http.matchers.file.relative}{http.request.uri.query_string}"
                                                                                                                                }
                                                                                                                        ],
                                                                                                                        "match": [
                                                                                                                                {
                                                                                                                                        "file": {
                                                                                                                                                "try_files": [
                                                                                                                                                        "{http.request.uri.path}.html",
                                                                                                                                                        "{http.request.uri.path}",
                                                                                                                                                        "{http.request.uri.path}/"
                                                                                                                                                ]
                                                                                                                                        }
                                                                                                                                }
                                                                                                                        ]
                                                                                                                },
                                                                                                                {
                                                                                                                        "handle": [
                                                                                                                                {
                                                                                                                                        "encodings": {
                                                                                                                                                "brotli": {},
                                                                                                                                                "gzip": {},
                                                                                                                                                "zstd": {}
                                                                                                                                        },
                                                                                                                                        "handler": "encode"
                                                                                                                                }
                                                                                                                        ]
                                                                                                                },
                                                                                                                {
                                                                                                                        "handle": [
                                                                                                                                {
                                                                                                                                        "handler": "static_response",
                                                                                                                                        "headers": {
                                                                                                                                                "Location": [
                                                                                                                                                        "{http.request.uri.path}"
                                                                                                                                                ]
                                                                                                                                        },
                                                                                                                                        "status_code": "{http.request.uri.path}/"
                                                                                                                                }
                                                                                                                        ]
                                                                                                                },
                                                                                                                {
                                                                                                                        "handle": [
                                                                                                                                {
                                                                                                                                        "handler": "rewrite",
                                                                                                                                        "rehandle": true,
                                                                                                                                        "uri": "{http.matchers.file.relative}{http.request.uri.query_string}"
                                                                                                                                }
                                                                                                                        ],
                                                                                                                        "match": [
                                                                                                                                {
                                                                                                                                        "file": {
                                                                                                                                                "try_files": [
                                                                                                                                                        "{http.request.uri.path}",
                                                                                                                                                        "index.php"
                                                                                                                                                ]
                                                                                                                                        }
                                                                                                                                }
                                                                                                                        ]
                                                                                                                },
                                                                                                                {
                                                                                                                        "handle": [
                                                                                                                                {
                                                                                                                                        "handler": "reverse_proxy",
                                                                                                                                        "transport": {
                                                                                                                                                "protocol": "fastcgi",
                                                                                                                                                "split_path": ".php"
                                                                                                                                        },
                                                                                                                                        "upstreams": [
                                                                                                                                                {
                                                                                                                                                        "dial": "unix//run/php/php7.3-fpm.sock"
                                                                                                                                                }
                                                                                                                                        ]
                                                                                                                                }
                                                                                                                        ],
                                                                                                                        "match": [
                                                                                                                                {
                                                                                                                                        "path": [
                                                                                                                                                "*.php"
                                                                                                                                        ]
                                                                                                                                }
                                                                                                                        ]
                                                                                                                },
                                                                                                                {
                                                                                                                        "handle": [
                                                                                                                                {
                                                                                                                                        "handler": "file_server",
                                                                                                                                        "hide": [
                                                                                                                                                "Caddyfile"
                                                                                                                                        ]
                                                                                                                                }
                                                                                                                        ]
                                                                                                                }
                                                                                                        ]
                                                                                                }
                                                                                        ]
                                                                                }
                                                                        ]
                                                                }
                                                        ]
                                                }
                                        ],
                                        "experimental_http3": true
                                }
                        }
                },
                "tls": {
                        "certificates": {
                                "load_files": [
                                        {
                                                "certificate": "/etc/caddy/hnrk.io.crt",
                                                "key": "/etc/caddy/hnrk.io.key"
                                        }
                                ]
                        },
                        "automation": {},
                        "session_tickets": {}
                }
        }
}
  • I get HTTP 500 responses when visiting 5G Throughput Calculator

  • When manually navigating to 5G Throughput Calculator the app loads but with errors:

    2019/09/16 09:39:29 [ERROR] [GET /5g] {id=g6xk4mcnh} caddyhttp.StaticResponse.ServeHTTP (staticresp.go:106): HTTP 500: strconv.Atoi: parsing “/5g/”: invalid syntax
    2019/09/16 09:39:32 [ERROR] [GET /5g/] {id=xsptgnipw} caddyhttp.StaticResponse.ServeHTTP (staticresp.go:106): HTTP 500: strconv.Atoi: parsing “/5g//”: invalid syntax
    2019/09/16 09:39:32 [ERROR] [GET /5g/style.css] {id=d0x12m1yf} caddyhttp.StaticResponse.ServeHTTP (staticresp.go:106): HTTP 500: strconv.Atoi: parsing “/5g/style.css/”: invalid syntax
    2019/09/16 09:39:32 [ERROR] [GET /5g/app.js] {id=t85awgfvk} caddyhttp.StaticResponse.ServeHTTP (staticresp.go:106): HTTP 500: strconv.Atoi: parsing “/5g/app.js/”: invalid syntax
    2019/09/16 09:39:33 [ERROR] [GET /favicon.ico] {id=9g5kh7wuy} caddyhttp.StaticResponse.ServeHTTP (staticresp.go:106): HTTP 500: strconv.Atoi: parsing “/favicon.ico/”: invalid syntax
    2019/09/16 09:39:33 [ERROR] [GET /5g/manifest.json] {id=mduavhx4b} caddyhttp.StaticResponse.ServeHTTP (staticresp.go:106): HTTP 500: strconv.Atoi: parsing “/5g/manifest.json/”: invalid syntax
    2019/09/16 09:39:33 [ERROR] [GET /5g/5g-192.png] {id=az6s1w85m} caddyhttp.StaticResponse.ServeHTTP (staticresp.go:106): HTTP 500: strconv.Atoi: parsing “/5g/5g-192.png/”: invalid syntax
    2019/09/16 09:39:34 [ERROR] [GET /5g/nr-sw.js] {id=p09y2hc0u} caddyhttp.StaticResponse.ServeHTTP (staticresp.go:106): HTTP 500: strconv.Atoi: parsing “/5g/nr-sw.js/”: invalid syntax

All in all it seems that using static_responses or rewrites are workarounds and I admit, it is really complicated for me to integrate them into Caddyfile JSON. I really think that Caddy v2 should adobt Caddy v1’s behaviour on rewriting the path internally or on the file_server level.

E.g. so that php_fastcgi unix//run/php/php7.3-fpm.sock should be enough to 1. have a php upstream, 2. redirect if path is a directory and 3. search for index.php files automatically in the given path.

What do you think?

You are trying to set the response status code (a number, like HTTP 200 for “OK” or HTTP 404 for “Not Found”) to a path: "status_code": "{http.request.uri.path}/" – if the JSON was generated from that Caddyfile, then that’s probably because redir {path} {path}/ expects a status code, not a path, as that second argument.

E.g. so that php_fastcgi unix//run/php/php7.3-fpm.sock should be enough to 1. have a php upstream, 2. redirect if path is a directory and 3. search for index.php files automatically in the given path.

Yes, I agree; I think all that’s missing currently is #2. Can you please open an issue to request that? Then I won’t forget.

Done: v2: php_fastcgi: 301 redirect if path is a directory (add trailing slash at the end) · Issue #2752 · caddyserver/caddy · GitHub.

Thank you guys for your help!

1 Like

Thanks @HNRK. I’ve submitted a PR that I hope will fix – or come close to fixing – the issue! Please take a look, as I have a hard time testing this myself. :stuck_out_tongue:

Edit: Thanks for your help in testing it!

1 Like

Thank you Francis and Matt! :blush:

@matt I’m not really sure why, but I recently discovered that you’ve blocked my Twitter account :sweat_smile: . Please revert that because I really enjoyed following you on that platform and like Caddy! :heart:

Hmm, oops – fixed

1 Like

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