I am currently moving from Caddy V1 to V2. I read the migration guide, however I fail to get a PHP application served with a minimal config file. In the above case I am trying to run phpMyAdmin, from https://server.example.com/pma/. PMA loads about 85 different resources initially, but according to the browser console only index.php is loaded. Everything else is answered by Caddy with a HTTP 200, but without content (content-length is always 0 bytes). I observed the same behaviour when using reverse_proxy to localhost (Gitea, listening on port 3000). I saw several topics on the forum, which seemed somehow similar, but found no configuration which was helpful.
5. What I already tried:
I tried named matchers and direct matching in different flavours, played around with traling slashes and wildcards, but nothing was helpful so far. A simple setup with an index.php containing nothing else than a call to phpinfo() works. I guess it has to do with loading resouces from a root php file. PMA for instance loads https://server.example.com/pma/themes/pmahomme/jquery/jquery-ui.css. This file exists on the server at /srv/pma/themes/pmahomme/jquery/jquery-ui.css, but if I enter the URL in the browser, the CSS is not loaded and displayed. Instead the browser loads index.php and tries to load all resources. I see i.e. a request for https://server.example.com/pma/themes/pmahomme/jquery/themes/pmahomme/jquery/jquery-ui.css. This of course does not exist (wrong URL!), but Caddy again answers with HTTP 200 and a content with 0 bytes.
Caddy v2 doesn’t enable a static file server by default. I think that’s probably the only thing you’re missing here.
Check out the migration guide:
You can also simplify things a bit by using route to group things together that use the same matcher, and since all you need is a path matcher you can use it inline instead of declaring a matcher block:
Note you still need to specify * as a matcher for root because the next argument begins with / which Caddy would interpret as a path matcher otherwise.
Since you’re running your site in a subpath, you need to rewrite the URL to strip /pma since you don’t have /pma inside of /srv/pma on disk. Caddy was looking for a file like /srv/pma/pma/somefile.txt for example.
Alternatively, you could change your root to simply /srv if you have no other directories in there you’re worried about.
However, I still don’t understand Caddy’s behaviour here. If it looks for /srv/pma/pma/somefile.txt which does not exist, why all the 200 responses instead of a lot of 404s?
In your situation, this is because of how php_fastcgi is implemented.
If you look at the expanded form, you’ll see try_files {path} {path}/index.php index.php. This tells Caddy to do the following:
try to rewrite the URI if the requested file exists on disk (i.e. {root}/{path} → /srv/pma/pma/somefile.txt, where root is /srv/pma and {path} is from the URL, /pma/somefile.txt)
if it doesn’t, it then checks if the path is a directory and contains index.php within that directory as a fallback
if not, as a final fallback, it then rewrites everything else to {root}/index.php which in your case is a file found on disk because you have /srv/pma/index.php.
This approach is ideal for most modern PHP web frameworks because it allows the PHP app to handle path routing internally, and subsequently handle 404s on its own if it can’t handle the route. It seems that phpMyAdmin just happens not to do that and didn’t serve 404s here.
I can’t judge about what PHP applications do these days as I am only a PHP user, not a developer.
However, I tried Piwigo with the same approach you described and in general it works. With this setup, it’s doing its job, but some page elements are missing:
In general, I would recommend running your various sites under subdomains instead of subpaths. Many apps don’t behave well when run inside of a subpath due to using absolute URLs for links and assets.
You can configure your DNS pointing *.server.example.com to the same IP address as server.example.com and Caddy will use SNI (Server Name Identification) to determine which site to serve based on the hostname.