1. The problem I’m having:
Normally, when I request /file%3F.txt/file%3F.txt, it should actually request /file?.txt/file?.txt, and using file_server directly works fine. However, if I have a php_fastcgi block, what gets passed to file_server seems to be /file, as if everything after the question mark was stripped away.
2. Error messages and/or full log output:
cat /root/caddytest/file
fake file
cat '/root/caddytest/file?.txt/file?.txt'
real file
curl http://localhost/file%3F.txt/file%3F.txt
fake file
caddy run --config Caddyfile
2026/01/14 07:24:41.620 INFO maxprocs: Leaving GOMAXPROCS=1: CPU quota undefined
2026/01/14 07:24:41.621 INFO GOMEMLIMIT is updated {"GOMEMLIMIT": 913464115, "previous": 9223372036854775807}
2026/01/14 07:24:41.621 INFO using config from file {"file": "Caddyfile"}
2026/01/14 07:24:41.621 INFO adapted config to JSON {"adapter": "caddyfile"}
2026/01/14 07:24:41.621 INFO admin admin endpoint started {"address": "localhost:2019", "enforce_origin": false, "origins": ["//localhost:2019", "//[::1]:2019", "//127.0.0.1:2019"]}
2026/01/14 07:24:41.622 WARN http.auto_https server is listening only on the HTTP port, so no automatic HTTPS will be applied to this server {"server_name": "srv0", "http_port": 80}
2026/01/14 07:24:41.622 DEBUG http.auto_https all servers have automatic HTTPS disabled and no domains need certificates, skipping TLS automation setup
2026/01/14 07:24:41.623 DEBUG http starting server loop {"address": "[::]:80", "tls": false, "http3": false}
2026/01/14 07:24:41.623 WARN http HTTP/2 skipped because it requires TLS {"network": "tcp", "addr": ":80"}
2026/01/14 07:24:41.623 WARN http HTTP/3 skipped because it requires TLS {"network": "tcp", "addr": ":80"}
2026/01/14 07:24:41.623 INFO http.log server running {"name": "srv0", "protocols": ["h1", "h2", "h3"]}
2026/01/14 07:24:41.623 DEBUG events event {"name": "started", "id": "308d8cc8-dc68-45c8-9b82-564deff668f4", "origin": "", "data": null}
2026/01/14 07:24:41.623 INFO autosaved config (load with --resume flag) {"file": "/root/.config/caddy/autosave.json"}
2026/01/14 07:24:41.623 INFO serving initial configuration
2026/01/14 07:24:41.634 INFO tls storage cleaning happened too recently; skipping for now {"storage": "FileStorage:/root/.local/share/caddy", "instance": "d61649d5-2acd-47b9-9e1f-ae148ea2df69", "try_again": "2026/01/15 07:24:41.634", "try_again_in": 86399.999999198}
2026/01/14 07:24:41.634 INFO tls finished cleaning storage units
2026/01/14 07:24:41.635 INFO tls.cache.maintenance started background certificate maintenance {"cache": "0xc000406200"}
2026/01/14 07:24:43.049 DEBUG http.handlers.rewrite rewrote request {"request": {"remote_ip": "::1", "remote_port": "36480", "client_ip": "::1", "proto": "HTTP/1.1", "method": "GET", "host": "localhost", "uri": "/file", "headers": {"User-Agent": ["curl/8.14.1"], "Accept": ["*/*"]}}, "method": "GET", "uri": "/file"}
2026/01/14 07:24:43.050 DEBUG http.handlers.file_server sanitized path join {"site_root": "/root/caddytest", "fs": "", "request_path": "/file", "result": "/root/caddytest/file"}
2026/01/14 07:24:43.050 DEBUG http.handlers.file_server opening file {"filename": "/root/caddytest/file"}
3. Caddy version:
e40bd019ff4599b34769d249ee37934217ed9fa4 (14 Jan 26 00:06 UTC)
4. How I installed and ran Caddy:
a. System environment:
I actually use systemd, but I can reproduce the issue by simply running caddy run.
b. Command:
caddy run --config Caddyfile
c. Service/unit/compose file:
none
d. My complete Caddy config:
{
debug
}
:80 {
root * /root/caddytest
php_fastcgi unix//run/php/php8.4-fpm.sock
file_server
}
5. Links to relevant resources:
none