Huh. Yes, you are right. There is different behaviour at play.
The reason appears to be here:
# Add trailing slash for directory requests
@canonicalPath {
file {path}/index.php
not path */
}
redir @canonicalPath {http.request.orig_uri.path}/ 308
- The first section deals with canonicalizing the request path. The goal is to ensure that requests that target a directory on disk actually have the trailing slash
/
added to the request path, so that only a single URL is valid for requests to that directory.
This is performed by using a request matcher that matches only requests that don’t end in a slash, and which map to a directory on disk which contains anindex.php
file, and if it matches, performs a HTTP 308 redirect with the trailing slash appended. So for example, it would redirect a request with path/foo
to/foo/
(appending a/
, to canonicalize the path to the directory), if/foo/index.php
exists on disk.
But that redirect is not query-preserving. See here:
~/Projects/caddy
➜ curl -i 'https://localhost/add?query=foo'
HTTP/2 308
alt-svc: h3=":443"; ma=2592000
location: /add/
server: Caddy
content-length: 0
date: Thu, 28 Nov 2024 02:29:57 GMT
I am not sure why this is the case - possibly there’s a good reason for it, possibly it’s an oversight.
Instead of php_fastcgi
you will have to copy and use the entire expanded form so that you can edit the canonical redirect. For your use case it should instead read:
redir @canonicalPath {http.request.orig_uri.path}/?{query} 308
I tested it like so and had a good result from /add?query=foo
:
{
debug
}
localhost {
route {
# Add trailing slash for directory requests
@canonicalPath {
file {path}/index.php
not path */
}
redir @canonicalPath {http.request.orig_uri.path}/?{query} 308
# If the requested file does not exist, try index files
@indexFiles file {
try_files {path} {path}/index.php index.php
split_path .php
}
rewrite @indexFiles {file_match.relative}
# Proxy PHP files to the FastCGI responder
@phpFiles path *.php
reverse_proxy @phpFiles unix//run/php-fpm/www.sock {
transport fastcgi {
split .php
}
}
}
}
~/Projects/caddy
➜ curl -i 'https://localhost/add?query=foo'
HTTP/2 308
alt-svc: h3=":443"; ma=2592000
location: /add/?query=foo
server: Caddy
content-length: 0
date: Thu, 28 Nov 2024 02:27:41 GMT
{
"AUTH_TYPE": "",
"DOCUMENT_URI": "add/index.php",
"SCRIPT_NAME": "/add/index.php",
"HTTPS": "on",
"CONTENT_LENGTH": "",
"REMOTE_PORT": "62283",
"SCRIPT_FILENAME": "/Users/whitestrake/Projects/caddy/add/index.php",
"HTTP_X_FORWARDED_HOST": "localhost",
"HTTP_HOST": "localhost",
"SERVER_SOFTWARE": "Caddy/v2.8.4",
"DOCUMENT_ROOT": "/Users/whitestrake/Projects/caddy",
"REQUEST_URI": "/add/?query=foo",
"HTTP_X_FORWARDED_FOR": "::1",
"QUERY_STRING": "query=foo",
"REMOTE_USER": "",
"REQUEST_SCHEME": "https",
"SERVER_NAME": "localhost",
"REMOTE_ADDR": "::1",
"HTTP_X_FORWARDED_PROTO": "https",
"HTTP_USER_AGENT": "curl/8.10.1",
"REMOTE_IDENT": "",
"REQUEST_METHOD": "GET",
"SERVER_PROTOCOL": "HTTP/2.0",
"SSL_PROTOCOL": "TLSv1.3",
"SSL_CIPHER": "TLS_AES_128_GCM_SHA256",
"CONTENT_TYPE": "",
"PATH_INFO": "",
"REMOTE_HOST": "::1",
"SERVER_PORT": "443",
"GATEWAY_INTERFACE": "CGI/1.1",
"HTTP_ACCEPT": "*/*"
}